From ccfb820cd705e38c687d2e492bdda537d4b30711 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:22:28 -0400 Subject: [PATCH 001/114] lint: Apply latest version of eslint-config-yscope. (#441) --- .../webui/imports/api/ingestion/server/publications.js | 7 +++++-- .../SearchControlsTimeRangeInput/index.jsx | 4 +++- .../SearchResultsTable/SearchResultsLoadSensor.jsx | 3 ++- .../SearchView/SearchResults/SearchResultsTable/index.jsx | 7 +++++-- components/webui/imports/ui/SearchView/SearchStatus.jsx | 3 ++- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/components/webui/imports/api/ingestion/server/publications.js b/components/webui/imports/api/ingestion/server/publications.js index 6a558e7fe..61aefb8a1 100644 --- a/components/webui/imports/api/ingestion/server/publications.js +++ b/components/webui/imports/api/ingestion/server/publications.js @@ -4,10 +4,13 @@ import {logger} from "/imports/utils/logger"; import {MONGO_SORT_BY_ID} from "/imports/utils/mongo"; import { - CompressionJobsCollection, STATS_COLLECTION_ID, StatsCollection, + CompressionJobsCollection, + STATS_COLLECTION_ID, + StatsCollection, } from "../collections"; import { - COMPRESSION_JOB_WAITING_STATES, COMPRESSION_JOBS_TABLE_COLUMN_NAMES, + COMPRESSION_JOB_WAITING_STATES, + COMPRESSION_JOBS_TABLE_COLUMN_NAMES, } from "../constants"; import CompressionDbManager from "./CompressionDbManager"; import StatsDbManager from "./StatsDbManager"; diff --git a/components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/index.jsx b/components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/index.jsx index 7f763ac19..382212ad6 100644 --- a/components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/index.jsx @@ -8,7 +8,9 @@ import Row from "react-bootstrap/Row"; import { computeTimeRange, convertLocalDateToSameUtcDatetime, - convertUtcDatetimeToSameLocalDate, TIME_RANGE_PRESET_LABEL, TIME_UNIT, + convertUtcDatetimeToSameLocalDate, + TIME_RANGE_PRESET_LABEL, + TIME_UNIT, } from "/imports/utils/datetime"; import SearchControlsFilterLabel from "../SearchControlsFilterLabel"; diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.jsx index 9c9c0e97c..b7f62e1d8 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.jsx @@ -1,5 +1,6 @@ import { - useEffect, useRef, + useEffect, + useRef, } from "react"; import Spinner from "react-bootstrap/Spinner"; diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index bbdf11ca8..77d6af8a8 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -4,12 +4,15 @@ import Table from "react-bootstrap/Table"; import dayjs from "dayjs"; import { - faSort, faSortDown, faSortUp, + faSort, + faSortDown, + faSortUp, } from "@fortawesome/free-solid-svg-icons"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import { - MONGO_SORT_ORDER, SEARCH_RESULTS_FIELDS, + MONGO_SORT_ORDER, + SEARCH_RESULTS_FIELDS, } from "/imports/api/search/constants"; import {DATETIME_FORMAT_TEMPLATE} from "/imports/utils/datetime"; diff --git a/components/webui/imports/ui/SearchView/SearchStatus.jsx b/components/webui/imports/ui/SearchView/SearchStatus.jsx index 2b084622b..8c63f41f2 100644 --- a/components/webui/imports/ui/SearchView/SearchStatus.jsx +++ b/components/webui/imports/ui/SearchView/SearchStatus.jsx @@ -9,7 +9,8 @@ import {faExclamationCircle} from "@fortawesome/free-solid-svg-icons"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import { - isSearchSignalQuerying, SEARCH_SIGNAL, + isSearchSignalQuerying, + SEARCH_SIGNAL, } from "/imports/api/search/constants"; import "./SearchStatus.scss"; From eedbd2045e19d6683c00dd39ded22be314f6de31 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:06:22 -0400 Subject: [PATCH 002/114] clp-s: Add archive_id to search results. (#435) --- components/core/src/clp_s/ArchiveReader.cpp | 28 +++++--- components/core/src/clp_s/ArchiveReader.hpp | 11 ++-- components/core/src/clp_s/JsonConstructor.cpp | 11 ++-- components/core/src/clp_s/JsonConstructor.hpp | 2 + components/core/src/clp_s/clp-s.cpp | 13 ++-- components/core/src/clp_s/search/Output.cpp | 7 +- .../core/src/clp_s/search/OutputHandler.cpp | 50 ++++++++------ .../core/src/clp_s/search/OutputHandler.hpp | 66 ++++++++++++------- 8 files changed, 115 insertions(+), 73 deletions(-) diff --git a/components/core/src/clp_s/ArchiveReader.cpp b/components/core/src/clp_s/ArchiveReader.cpp index 93f905e3b..14cf4fa0b 100644 --- a/components/core/src/clp_s/ArchiveReader.cpp +++ b/components/core/src/clp_s/ArchiveReader.cpp @@ -1,26 +1,34 @@ #include "ArchiveReader.hpp" +#include +#include + #include "archive_constants.hpp" #include "ReaderUtils.hpp" +using std::string_view; + namespace clp_s { -void ArchiveReader::open(std::string const& archive_path) { +void ArchiveReader::open(string_view archives_dir, string_view archive_id) { if (m_is_open) { throw OperationFailed(ErrorCodeNotReady, __FILENAME__, __LINE__); } m_is_open = true; - m_archive_path = archive_path; + m_archive_id = archive_id; + std::filesystem::path archive_path{archives_dir}; + archive_path /= m_archive_id; + auto const archive_path_str = archive_path.string(); - m_var_dict = ReaderUtils::get_variable_dictionary_reader(m_archive_path); - m_log_dict = ReaderUtils::get_log_type_dictionary_reader(m_archive_path); - m_array_dict = ReaderUtils::get_array_dictionary_reader(m_archive_path); - m_timestamp_dict = ReaderUtils::get_timestamp_dictionary_reader(m_archive_path); + m_var_dict = ReaderUtils::get_variable_dictionary_reader(archive_path_str); + m_log_dict = ReaderUtils::get_log_type_dictionary_reader(archive_path_str); + m_array_dict = ReaderUtils::get_array_dictionary_reader(archive_path_str); + m_timestamp_dict = ReaderUtils::get_timestamp_dictionary_reader(archive_path_str); - m_schema_tree = ReaderUtils::read_schema_tree(m_archive_path); - m_schema_map = ReaderUtils::read_schemas(m_archive_path); + m_schema_tree = ReaderUtils::read_schema_tree(archive_path_str); + m_schema_map = ReaderUtils::read_schemas(archive_path_str); - m_tables_file_reader.open(m_archive_path + constants::cArchiveTablesFile); - m_table_metadata_file_reader.open(m_archive_path + constants::cArchiveTableMetadataFile); + m_tables_file_reader.open(archive_path_str + constants::cArchiveTablesFile); + m_table_metadata_file_reader.open(archive_path_str + constants::cArchiveTableMetadataFile); } void ArchiveReader::read_metadata() { diff --git a/components/core/src/clp_s/ArchiveReader.hpp b/components/core/src/clp_s/ArchiveReader.hpp index 54eb42698..929252dcf 100644 --- a/components/core/src/clp_s/ArchiveReader.hpp +++ b/components/core/src/clp_s/ArchiveReader.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -29,9 +30,10 @@ class ArchiveReader { /** * Opens an archive for reading. - * @param archive_path + * @param archives_dir + * @param archive_id */ - void open(std::string const& archive_path); + void open(std::string_view archives_dir, std::string_view archive_id); /** * Reads the dictionaries and metadata. @@ -92,6 +94,8 @@ class ArchiveReader { SchemaReader& read_table(int32_t schema_id, bool should_extract_timestamp, bool should_marshal_records); + std::string_view get_archive_id() { return m_archive_id; } + std::shared_ptr get_variable_dictionary() { return m_var_dict; } std::shared_ptr get_log_type_dictionary() { return m_log_dict; } @@ -161,8 +165,7 @@ class ArchiveReader { ); bool m_is_open; - std::string m_archive_path; - + std::string m_archive_id; std::shared_ptr m_var_dict; std::shared_ptr m_log_dict; std::shared_ptr m_array_dict; diff --git a/components/core/src/clp_s/JsonConstructor.cpp b/components/core/src/clp_s/JsonConstructor.cpp index 777f62ce2..218f1107f 100644 --- a/components/core/src/clp_s/JsonConstructor.cpp +++ b/components/core/src/clp_s/JsonConstructor.cpp @@ -13,7 +13,8 @@ namespace clp_s { JsonConstructor::JsonConstructor(JsonConstructorOption const& option) : m_output_dir(option.output_dir), - m_archives_dir(option.archives_dir) { + m_archives_dir(option.archives_dir), + m_archive_id(option.archive_id) { std::error_code error_code; if (false == std::filesystem::create_directory(option.output_dir, error_code) && error_code) { throw OperationFailed( @@ -28,12 +29,14 @@ JsonConstructor::JsonConstructor(JsonConstructorOption const& option) ); } - if (false == std::filesystem::is_directory(m_archives_dir)) { + std::filesystem::path archive_path{m_archives_dir}; + archive_path /= m_archive_id; + if (false == std::filesystem::is_directory(archive_path)) { throw OperationFailed( ErrorCodeFailure, __FILENAME__, __LINE__, - fmt::format("'{}' is not a directory", m_archives_dir) + fmt::format("'{}' is not a directory", archive_path.c_str()) ); } } @@ -43,7 +46,7 @@ void JsonConstructor::store() { writer.open(m_output_dir + "/original", FileWriter::OpenMode::CreateIfNonexistentForAppending); m_archive_reader = std::make_unique(); - m_archive_reader->open(m_archives_dir); + m_archive_reader->open(m_archives_dir, m_archive_id); m_archive_reader->read_dictionaries_and_metadata(); m_archive_reader->store(writer); m_archive_reader->close(); diff --git a/components/core/src/clp_s/JsonConstructor.hpp b/components/core/src/clp_s/JsonConstructor.hpp index 8aa35f904..688f19418 100644 --- a/components/core/src/clp_s/JsonConstructor.hpp +++ b/components/core/src/clp_s/JsonConstructor.hpp @@ -16,6 +16,7 @@ namespace clp_s { struct JsonConstructorOption { std::string archives_dir; + std::string archive_id; std::string output_dir; }; @@ -50,6 +51,7 @@ class JsonConstructor { private: std::string m_archives_dir; + std::string m_archive_id; std::string m_output_dir; std::unique_ptr m_archive_reader; diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index b1dda7508..7caef88a5 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -271,10 +271,11 @@ int main(int argc, char const* argv[]) { clp_s::JsonConstructorOption option; option.output_dir = command_line_arguments.get_output_dir(); + option.archives_dir = archives_dir; try { auto const& archive_id = command_line_arguments.get_archive_id(); if (false == archive_id.empty()) { - option.archives_dir = std::filesystem::path{archives_dir} / archive_id; + option.archive_id = archive_id; decompress_archive(option); } else { for (auto const& entry : std::filesystem::directory_iterator(archives_dir)) { @@ -283,7 +284,7 @@ int main(int argc, char const* argv[]) { continue; } - option.archives_dir = entry.path(); + option.archive_id = entry.path().filename(); decompress_archive(option); } } @@ -330,10 +331,7 @@ int main(int argc, char const* argv[]) { auto const& archive_id = command_line_arguments.get_archive_id(); auto archive_reader = std::make_shared(); if (false == archive_id.empty()) { - std::filesystem::path const archives_dir_path{archives_dir}; - std::string const archive_path{archives_dir_path / archive_id}; - - archive_reader->open(archive_path); + archive_reader->open(archives_dir, archive_id); if (false == search_archive(command_line_arguments, archive_reader, expr, reducer_socket_fd)) { @@ -347,7 +345,8 @@ int main(int argc, char const* argv[]) { continue; } - archive_reader->open(entry.path()); + auto const archive_id = entry.path().filename().string(); + archive_reader->open(archives_dir, archive_id); if (false == search_archive( command_line_arguments, diff --git a/components/core/src/clp_s/search/Output.cpp b/components/core/src/clp_s/search/Output.cpp index 524c055fd..b6a3b8fe0 100644 --- a/components/core/src/clp_s/search/Output.cpp +++ b/components/core/src/clp_s/search/Output.cpp @@ -65,6 +65,7 @@ bool Output::filter() { populate_string_queries(top_level_expr); std::string message; + auto const archive_id = m_archive_reader->get_archive_id(); for (int32_t schema_id : matched_schemas) { m_expr_clp_query.clear(); m_expr_var_match_map.clear(); @@ -85,15 +86,15 @@ bool Output::filter() { auto& reader = m_archive_reader->read_table( schema_id, - m_output_handler->should_output_timestamp(), + m_output_handler->should_output_metadata(), m_should_marshal_records ); reader.initialize_filter(this); - if (m_output_handler->should_output_timestamp()) { + if (m_output_handler->should_output_metadata()) { epochtime_t timestamp; while (reader.get_next_message_with_timestamp(message, timestamp, this)) { - m_output_handler->write(message, timestamp); + m_output_handler->write(message, timestamp, archive_id); } } else { while (reader.get_next_message(message, this)) { diff --git a/components/core/src/clp_s/search/OutputHandler.cpp b/components/core/src/clp_s/search/OutputHandler.cpp index 47a66bbd5..8d6a1eaa5 100644 --- a/components/core/src/clp_s/search/OutputHandler.cpp +++ b/components/core/src/clp_s/search/OutputHandler.cpp @@ -1,6 +1,8 @@ #include "OutputHandler.hpp" #include +#include +#include #include @@ -9,9 +11,12 @@ #include "../../reducer/network_utils.hpp" #include "../../reducer/Record.hpp" +using std::string; +using std::string_view; + namespace clp_s::search { NetworkOutputHandler::NetworkOutputHandler( - std::string const& host, + string const& host, int port, bool should_output_timestamp ) @@ -23,18 +28,14 @@ NetworkOutputHandler::NetworkOutputHandler( } } -void NetworkOutputHandler::write(std::string const& message, epochtime_t timestamp) { - msgpack::type::tuple src(timestamp, message, ""); - msgpack::sbuffer m; - msgpack::pack(m, src); - - if (-1 == send(m_socket_fd, m.data(), m.size(), 0)) { - throw OperationFailed(ErrorCode::ErrorCodeFailureNetwork, __FILE__, __LINE__); - } -} - -void NetworkOutputHandler::write(std::string const& message) { - msgpack::type::tuple src(0, message, ""); +void NetworkOutputHandler::write( + string_view message, + epochtime_t timestamp, + string_view archive_id +) { + static constexpr string_view cOrigFilePathPlaceholder{""}; + msgpack::type::tuple const + src(timestamp, message, cOrigFilePathPlaceholder, archive_id); msgpack::sbuffer m; msgpack::pack(m, src); @@ -44,8 +45,8 @@ void NetworkOutputHandler::write(std::string const& message) { } ResultsCacheOutputHandler::ResultsCacheOutputHandler( - std::string const& uri, - std::string const& collection, + string const& uri, + string const& collection, uint64_t batch_size, uint64_t max_num_results, bool should_output_timestamp @@ -73,7 +74,8 @@ ErrorCode ResultsCacheOutputHandler::flush() { m_results.emplace_back(std::move(bsoncxx::builder::basic::make_document( bsoncxx::builder::basic::kvp("original_path", std::move(result.original_path)), bsoncxx::builder::basic::kvp("message", std::move(result.message)), - bsoncxx::builder::basic::kvp("timestamp", result.timestamp) + bsoncxx::builder::basic::kvp("timestamp", result.timestamp), + bsoncxx::builder::basic::kvp("archive_id", std::move(result.archive_id)) ))); count++; @@ -98,12 +100,20 @@ ErrorCode ResultsCacheOutputHandler::flush() { return ErrorCode::ErrorCodeSuccess; } -void ResultsCacheOutputHandler::write(std::string const& message, epochtime_t timestamp) { +void ResultsCacheOutputHandler::write( + string_view message, + epochtime_t timestamp, + string_view archive_id +) { if (m_latest_results.size() < m_max_num_results) { - m_latest_results.emplace(std::make_unique("", message, timestamp)); + m_latest_results.emplace( + std::make_unique(string_view{}, message, timestamp, archive_id) + ); } else if (m_latest_results.top()->timestamp < timestamp) { m_latest_results.pop(); - m_latest_results.emplace(std::make_unique("", message, timestamp)); + m_latest_results.emplace( + std::make_unique(string_view{}, message, timestamp, archive_id) + ); } } @@ -114,7 +124,7 @@ CountOutputHandler::CountOutputHandler(int reducer_socket_fd) m_pipeline.add_pipeline_stage(std::make_shared()); } -void CountOutputHandler::write(std::string const& message) { +void CountOutputHandler::write(string_view message) { m_pipeline.push_record(reducer::EmptyRecord{}); } diff --git a/components/core/src/clp_s/search/OutputHandler.hpp b/components/core/src/clp_s/search/OutputHandler.hpp index 624c006be..ca12e32d3 100644 --- a/components/core/src/clp_s/search/OutputHandler.hpp +++ b/components/core/src/clp_s/search/OutputHandler.hpp @@ -5,8 +5,10 @@ #include #include +#include #include #include +#include #include #include @@ -28,8 +30,8 @@ namespace clp_s::search { class OutputHandler { public: // Constructors - explicit OutputHandler(bool should_output_timestamp, bool should_marshal_records) - : m_should_output_timestamp(should_output_timestamp), + explicit OutputHandler(bool should_output_metadata, bool should_marshal_records) + : m_should_output_metadata(should_output_metadata), m_should_marshal_records(should_marshal_records) {}; // Destructor @@ -40,14 +42,16 @@ class OutputHandler { * Writes a log event to the output handler. * @param message The message in the log event. * @param timestamp The timestamp of the log event. + * @param archive_id The archive containing the log event. */ - virtual void write(std::string const& message, epochtime_t timestamp) = 0; + virtual void write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) + = 0; /** * Writes a message to the output handler. * @param message The message to write. */ - virtual void write(std::string const& message) = 0; + virtual void write(std::string_view message) = 0; /** * Flushes the output handler after each table that gets searched. @@ -61,12 +65,12 @@ class OutputHandler { */ virtual ErrorCode finish() { return ErrorCode::ErrorCodeSuccess; } - [[nodiscard]] bool should_output_timestamp() const { return m_should_output_timestamp; } + [[nodiscard]] bool should_output_metadata() const { return m_should_output_metadata; } [[nodiscard]] bool should_marshal_records() const { return m_should_marshal_records; } private: - bool m_should_output_timestamp; + bool m_should_output_metadata; bool m_should_marshal_records; }; @@ -76,15 +80,16 @@ class OutputHandler { class StandardOutputHandler : public OutputHandler { public: // Constructors - explicit StandardOutputHandler(bool should_output_timestamp = false) - : OutputHandler(should_output_timestamp, true) {} + explicit StandardOutputHandler(bool should_output_metadata = false) + : OutputHandler(should_output_metadata, true) {} // Methods inherited from OutputHandler - void write(std::string const& message, epochtime_t timestamp) override { - printf("%" EPOCHTIME_T_PRINTF_FMT " %s", timestamp, message.c_str()); + void + write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override { + std::cout << archive_id << ": " << timestamp << " " << message; } - void write(std::string const& message) override { printf("%s", message.c_str()); } + void write(std::string_view message) override { std::cout << message; } }; /** @@ -104,7 +109,7 @@ class NetworkOutputHandler : public OutputHandler { explicit NetworkOutputHandler( std::string const& host, int port, - bool should_output_timestamp = false + bool should_output_metadata = false ); // Destructor @@ -115,9 +120,10 @@ class NetworkOutputHandler : public OutputHandler { } // Methods inherited from OutputHandler - void write(std::string const& message, epochtime_t timestamp) override; + void + write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override; - void write(std::string const& message) override; + void write(std::string_view message) override { write(message, 0, {}); } private: std::string m_host; @@ -133,14 +139,21 @@ class ResultsCacheOutputHandler : public OutputHandler { // Types struct QueryResult { // Constructors - QueryResult(std::string original_path, std::string message, epochtime_t timestamp) - : original_path(std::move(original_path)), - message(std::move(message)), - timestamp(timestamp) {} + QueryResult( + std::string_view original_path, + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id + ) + : original_path(original_path), + message(message), + timestamp(timestamp), + archive_id(archive_id) {} std::string original_path; std::string message; epochtime_t timestamp; + std::string archive_id; }; struct QueryResultGreaterTimestampComparator { @@ -165,7 +178,7 @@ class ResultsCacheOutputHandler : public OutputHandler { std::string const& collection, uint64_t batch_size, uint64_t max_num_results, - bool should_output_timestamp = true + bool should_output_metadata = true ); // Methods inherited from OutputHandler @@ -176,9 +189,10 @@ class ResultsCacheOutputHandler : public OutputHandler { */ ErrorCode flush() override; - void write(std::string const& message, epochtime_t timestamp) override; + void + write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override; - void write(std::string const& message) override { write(message, 0); } + void write(std::string_view message) override { write(message, 0, {}); } private: mongocxx::client m_client; @@ -202,9 +216,10 @@ class CountOutputHandler : public OutputHandler { CountOutputHandler(int reducer_socket_fd); // Methods inherited from OutputHandler - void write(std::string const& message, epochtime_t timestamp) override {} + void + write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override {} - void write(std::string const& message) override; + void write(std::string_view message) override; /** * Flushes the count. @@ -231,12 +246,13 @@ class CountByTimeOutputHandler : public OutputHandler { m_count_by_time_bucket_size{count_by_time_bucket_size} {} // Methods inherited from OutputHandler - void write(std::string const& message, epochtime_t timestamp) override { + void + write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override { int64_t bucket = (timestamp / m_count_by_time_bucket_size) * m_count_by_time_bucket_size; m_bucket_counts[bucket] += 1; } - void write(std::string const& message) override {} + void write(std::string_view message) override {} /** * Flushes the counts. From 8cfa96c61d3f26cc89aa682df15a0d146fa24ba2 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Fri, 14 Jun 2024 14:16:45 -0400 Subject: [PATCH 003/114] clp-s: Add support for decompression in ascending timestamp order. (#440) Co-authored-by: wraymo <37269683+wraymo@users.noreply.github.com> --- components/core/src/clp_s/ArchiveReader.cpp | 48 ++++++++++++++----- components/core/src/clp_s/ArchiveReader.hpp | 13 +++-- .../core/src/clp_s/CommandLineArguments.cpp | 9 ++++ .../core/src/clp_s/CommandLineArguments.hpp | 3 ++ components/core/src/clp_s/JsonConstructor.cpp | 31 +++++++++++- components/core/src/clp_s/JsonConstructor.hpp | 10 ++++ components/core/src/clp_s/SchemaReader.hpp | 10 ++++ components/core/src/clp_s/clp-s.cpp | 1 + 8 files changed, 110 insertions(+), 15 deletions(-) diff --git a/components/core/src/clp_s/ArchiveReader.cpp b/components/core/src/clp_s/ArchiveReader.cpp index 14cf4fa0b..f211a0707 100644 --- a/components/core/src/clp_s/ArchiveReader.cpp +++ b/components/core/src/clp_s/ArchiveReader.cpp @@ -100,14 +100,40 @@ SchemaReader& ArchiveReader::read_table( throw OperationFailed(ErrorCodeFileNotFound, __FILENAME__, __LINE__); } - auto& schema_reader - = create_schema_reader(schema_id, should_extract_timestamp, should_marshal_records); + initialize_schema_reader( + m_schema_reader, + schema_id, + should_extract_timestamp, + should_marshal_records + ); m_tables_file_reader.try_seek_from_begin(m_id_to_table_metadata[schema_id].offset); m_tables_decompressor.open(m_tables_file_reader, cDecompressorFileReadBufferCapacity); - schema_reader.load(m_tables_decompressor, m_id_to_table_metadata[schema_id].uncompressed_size); + m_schema_reader.load( + m_tables_decompressor, + m_id_to_table_metadata[schema_id].uncompressed_size + ); m_tables_decompressor.close_for_reuse(); - return schema_reader; + return m_schema_reader; +} + +std::vector> ArchiveReader::read_all_tables() { + constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB + + std::vector> readers; + readers.reserve(m_id_to_table_metadata.size()); + for (auto const& [id, table_metadata] : m_id_to_table_metadata) { + auto schema_reader = std::make_shared(); + initialize_schema_reader(*schema_reader, id, true, true); + + m_tables_file_reader.try_seek_from_begin(table_metadata.offset); + m_tables_decompressor.open(m_tables_file_reader, cDecompressorFileReadBufferCapacity); + schema_reader->load(m_tables_decompressor, table_metadata.uncompressed_size); + m_tables_decompressor.close_for_reuse(); + + readers.push_back(std::move(schema_reader)); + } + return readers; } BaseColumnReader* ArchiveReader::append_reader_column(SchemaReader& reader, int32_t column_id) { @@ -200,13 +226,14 @@ void ArchiveReader::append_unordered_reader_columns( } } -SchemaReader& ArchiveReader::create_schema_reader( +void ArchiveReader::initialize_schema_reader( + SchemaReader& reader, int32_t schema_id, bool should_extract_timestamp, bool should_marshal_records ) { auto& schema = (*m_schema_map)[schema_id]; - m_schema_reader.reset( + reader.reset( m_schema_tree, schema_id, schema.get_ordered_schema_view(), @@ -226,7 +253,7 @@ SchemaReader& ArchiveReader::create_schema_reader( Schema::get_unordered_object_type(column_id) ); append_unordered_reader_columns( - m_schema_reader, + reader, mst_subtree_root_node_id, sub_schema, should_marshal_records @@ -239,21 +266,20 @@ SchemaReader& ArchiveReader::create_schema_reader( // column id is the root of the unordered object, so we can pass it directly to // append_unordered_reader_columns. append_unordered_reader_columns( - m_schema_reader, + reader, column_id, std::span(), should_marshal_records ); continue; } - BaseColumnReader* column_reader = append_reader_column(m_schema_reader, column_id); + BaseColumnReader* column_reader = append_reader_column(reader, column_id); if (should_extract_timestamp && column_reader && timestamp_column_ids.count(column_id) > 0) { - m_schema_reader.mark_column_as_timestamp(column_reader); + reader.mark_column_as_timestamp(column_reader); } } - return m_schema_reader; } void ArchiveReader::store(FileWriter& writer) { diff --git a/components/core/src/clp_s/ArchiveReader.hpp b/components/core/src/clp_s/ArchiveReader.hpp index 929252dcf..91fcc1a94 100644 --- a/components/core/src/clp_s/ArchiveReader.hpp +++ b/components/core/src/clp_s/ArchiveReader.hpp @@ -94,6 +94,12 @@ class ArchiveReader { SchemaReader& read_table(int32_t schema_id, bool should_extract_timestamp, bool should_marshal_records); + /** + * Loads all of the tables in the archive and returns SchemaReaders for them. + * @return the schema readers for every table in the archive + */ + std::vector> read_all_tables(); + std::string_view get_archive_id() { return m_archive_id; } std::shared_ptr get_variable_dictionary() { return m_var_dict; } @@ -129,13 +135,14 @@ class ArchiveReader { private: /** - * Creates a schema reader for a given schema. + * Initializes a schema reader passed by reference to become a reader for a given schema. + * @param reader * @param schema_id * @param should_extract_timestamp * @param should_marshal_records - * @return a reference to the newly created schema reader initialized with the given parameters */ - SchemaReader& create_schema_reader( + void initialize_schema_reader( + SchemaReader& reader, int32_t schema_id, bool should_extract_timestamp, bool should_marshal_records diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index 640a45f8c..3b715aff7 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -286,6 +286,14 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { ); extraction_options.add(input_options); + po::options_description decompression_options("Decompression Options"); + decompression_options.add_options()( + "ordered", + po::bool_switch(&m_ordered_decompression), + "Enable decompression in ascending timestamp order for this archive" + ); + extraction_options.add(decompression_options); + po::positional_options_description positional_options; positional_options.add("archives-dir", 1); positional_options.add("output-dir", 1); @@ -316,6 +324,7 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { po::options_description visible_options; visible_options.add(general_options); visible_options.add(input_options); + visible_options.add(decompression_options); std::cerr << visible_options << std::endl; return ParsingResult::InfoCommand; } diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 20fa3ec6e..4c367509a 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -104,6 +104,8 @@ class CommandLineArguments { bool get_structurize_arrays() const { return m_structurize_arrays; } + bool get_ordered_decompression() const { return m_ordered_decompression; } + private: // Methods /** @@ -167,6 +169,7 @@ class CommandLineArguments { bool m_print_archive_stats{false}; size_t m_max_document_size{512ULL * 1024 * 1024}; // 512 MB bool m_structurize_arrays{false}; + bool m_ordered_decompression{false}; // Metadata db variables std::optional m_metadata_db_config; diff --git a/components/core/src/clp_s/JsonConstructor.cpp b/components/core/src/clp_s/JsonConstructor.cpp index 218f1107f..e48d370d1 100644 --- a/components/core/src/clp_s/JsonConstructor.cpp +++ b/components/core/src/clp_s/JsonConstructor.cpp @@ -1,6 +1,7 @@ #include "JsonConstructor.hpp" #include +#include #include #include @@ -14,6 +15,7 @@ namespace clp_s { JsonConstructor::JsonConstructor(JsonConstructorOption const& option) : m_output_dir(option.output_dir), m_archives_dir(option.archives_dir), + m_ordered{option.ordered}, m_archive_id(option.archive_id) { std::error_code error_code; if (false == std::filesystem::create_directory(option.output_dir, error_code) && error_code) { @@ -43,15 +45,42 @@ JsonConstructor::JsonConstructor(JsonConstructorOption const& option) void JsonConstructor::store() { FileWriter writer; + // TODO: change this when doing chunking writer.open(m_output_dir + "/original", FileWriter::OpenMode::CreateIfNonexistentForAppending); m_archive_reader = std::make_unique(); m_archive_reader->open(m_archives_dir, m_archive_id); m_archive_reader->read_dictionaries_and_metadata(); - m_archive_reader->store(writer); + if (false == m_ordered) { + m_archive_reader->store(writer); + } else { + construct_in_order(writer); + } m_archive_reader->close(); writer.close(); } +void JsonConstructor::construct_in_order(FileWriter& writer) { + std::string buffer; + auto tables = m_archive_reader->read_all_tables(); + using ReaderPointer = std::shared_ptr; + auto cmp = [](ReaderPointer& left, ReaderPointer& right) { + return left->get_next_timestamp() > right->get_next_timestamp(); + }; + std::priority_queue record_queue(tables.begin(), tables.end(), cmp); + // Clear tables vector so that memory gets deallocated after we have marshalled all records for + // a given table + tables.clear(); + while (false == record_queue.empty()) { + ReaderPointer next = record_queue.top(); + record_queue.pop(); + next->get_next_message(buffer); + if (false == next->done()) { + record_queue.emplace(std::move(next)); + } + writer.write(buffer.c_str(), buffer.length()); + } + writer.close(); +} } // namespace clp_s diff --git a/components/core/src/clp_s/JsonConstructor.hpp b/components/core/src/clp_s/JsonConstructor.hpp index 688f19418..0324924b9 100644 --- a/components/core/src/clp_s/JsonConstructor.hpp +++ b/components/core/src/clp_s/JsonConstructor.hpp @@ -9,6 +9,7 @@ #include "ColumnReader.hpp" #include "DictionaryReader.hpp" #include "ErrorCode.hpp" +#include "FileWriter.hpp" #include "SchemaReader.hpp" #include "SchemaTree.hpp" #include "TraceableException.hpp" @@ -18,6 +19,7 @@ struct JsonConstructorOption { std::string archives_dir; std::string archive_id; std::string output_dir; + bool ordered; }; class JsonConstructor { @@ -50,9 +52,17 @@ class JsonConstructor { void store(); private: + /** + * Reads all of the tables from m_archive_reader and writes all of the records + * they contain to writer in timestamp order. + * @param writer + */ + void construct_in_order(FileWriter& writer); + std::string m_archives_dir; std::string m_archive_id; std::string m_output_dir; + bool m_ordered{false}; std::unique_ptr m_archive_reader; }; diff --git a/components/core/src/clp_s/SchemaReader.hpp b/components/core/src/clp_s/SchemaReader.hpp index 8597316a6..3639560f6 100644 --- a/components/core/src/clp_s/SchemaReader.hpp +++ b/components/core/src/clp_s/SchemaReader.hpp @@ -185,6 +185,16 @@ class SchemaReader { */ static int32_t get_first_column_in_span(std::span schema); + /** + * @return the timestamp found in the row pointed to by m_cur_message + */ + epochtime_t get_next_timestamp() const { return m_get_timestamp(); } + + /** + * @return true if all records in this table have been iterated over, false otherwise + */ + bool done() const { return m_cur_message >= m_num_messages; } + private: /** * Merges the current local schema tree with the section of the global schema tree corresponding diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 7caef88a5..74235e0e1 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -271,6 +271,7 @@ int main(int argc, char const* argv[]) { clp_s::JsonConstructorOption option; option.output_dir = command_line_arguments.get_output_dir(); + option.ordered = command_line_arguments.get_ordered_decompression(); option.archives_dir = archives_dir; try { auto const& archive_id = command_line_arguments.get_archive_id(); From ac123dab811357a331529632661d0a58cc5ab364 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Fri, 14 Jun 2024 19:45:17 -0400 Subject: [PATCH 004/114] Add log-viewer-webui component with boilerplate Fastify server. (#442) Co-authored-by: Junhao Liao --- components/log-viewer-webui/.gitignore | 2 + components/log-viewer-webui/README.md | 9 + components/log-viewer-webui/server/.env | 2 + components/log-viewer-webui/server/.gitignore | 2 + .../log-viewer-webui/server/package-lock.json | 8742 +++++++++++++++++ .../log-viewer-webui/server/package.json | 32 + components/log-viewer-webui/server/src/app.js | 19 + .../log-viewer-webui/server/src/app.test.js | 26 + .../log-viewer-webui/server/src/main.js | 64 + .../server/src/routes/examples.js | 18 + .../dev-guide/components-log-viewer-webui.md | 61 + 11 files changed, 8977 insertions(+) create mode 100644 components/log-viewer-webui/.gitignore create mode 100644 components/log-viewer-webui/README.md create mode 100644 components/log-viewer-webui/server/.env create mode 100644 components/log-viewer-webui/server/.gitignore create mode 100644 components/log-viewer-webui/server/package-lock.json create mode 100644 components/log-viewer-webui/server/package.json create mode 100644 components/log-viewer-webui/server/src/app.js create mode 100644 components/log-viewer-webui/server/src/app.test.js create mode 100644 components/log-viewer-webui/server/src/main.js create mode 100644 components/log-viewer-webui/server/src/routes/examples.js create mode 100644 docs/src/dev-guide/components-log-viewer-webui.md diff --git a/components/log-viewer-webui/.gitignore b/components/log-viewer-webui/.gitignore new file mode 100644 index 000000000..b6448e2f6 --- /dev/null +++ b/components/log-viewer-webui/.gitignore @@ -0,0 +1,2 @@ +# Dependencies +node_modules diff --git a/components/log-viewer-webui/README.md b/components/log-viewer-webui/README.md new file mode 100644 index 000000000..265385dc6 --- /dev/null +++ b/components/log-viewer-webui/README.md @@ -0,0 +1,9 @@ +# Log Viewer WebUI + +A webapp that allows us to serve the [log-viewer] and integrate it with CLP's [webui]. + +See the [docs] for more details. + +[docs]: https://docs.yscope.com/clp/main/dev-guide/components-log-viewer-webui.md +[log-viewer]: https://github.com/y-scope/yscope-log-viewer +[webui]: ../webui diff --git a/components/log-viewer-webui/server/.env b/components/log-viewer-webui/server/.env new file mode 100644 index 000000000..3fd917426 --- /dev/null +++ b/components/log-viewer-webui/server/.env @@ -0,0 +1,2 @@ +HOST=localhost +PORT=3000 diff --git a/components/log-viewer-webui/server/.gitignore b/components/log-viewer-webui/server/.gitignore new file mode 100644 index 000000000..d0e829eda --- /dev/null +++ b/components/log-viewer-webui/server/.gitignore @@ -0,0 +1,2 @@ +# Testing +/.tap diff --git a/components/log-viewer-webui/server/package-lock.json b/components/log-viewer-webui/server/package-lock.json new file mode 100644 index 000000000..435ccc040 --- /dev/null +++ b/components/log-viewer-webui/server/package-lock.json @@ -0,0 +1,8742 @@ +{ + "name": "log-viewer-server", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "log-viewer-server", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "dotenv": "^16.4.5", + "fastify": "^4.28.0", + "http-status-codes": "^2.3.0", + "pino-pretty": "^11.2.1" + }, + "devDependencies": { + "eslint-config-yscope": "latest", + "nodemon": "^3.1.3", + "tap": "^19.2.5" + } + }, + "node_modules/@alcalzone/ansi-tokenize": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.1.3.tgz", + "integrity": "sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=14.13.1" + } + }, + "node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", + "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "^8.56.5", + "@types/estree": "^1.0.5", + "@typescript-eslint/types": "^7.2.0", + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "dev": true, + "peer": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", + "integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/@fastify/error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "dependencies": { + "fast-json-stringify": "^5.7.0" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", + "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "peer": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009": { + "version": "10.9.7", + "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.7.tgz", + "integrity": "sha512-9f0bhUr9TnwwpgUhEpr3FjxSaH/OHaARkE2F9fM0lS4nIs2GNerrvGwQz493dk0JKlTaGYVrKbq36vA/whZ34g==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node14": "*", + "@tsconfig/node16": "*", + "@tsconfig/node18": "*", + "@tsconfig/node20": "*", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=4.2" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", + "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^4.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", + "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", + "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^4.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", + "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", + "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sigstore/bundle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", + "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", + "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", + "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", + "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "make-fetch-happen": "^13.0.1", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", + "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.2", + "tuf-js": "^2.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", + "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.2" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.8.1.tgz", + "integrity": "sha512-c5c2C8Mos5tTQd+NWpqwEu7VT6SSRooAguFPMj1cp2RkTYl1ynKoXo8MWy3k4rkbzoeYHrqC2UlUzsroAN7wtQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "acorn": "^8.11.3", + "escape-string-regexp": "^4.0.0", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.8.1.tgz", + "integrity": "sha512-k1Eb6rcjMP+mmjvj+vd9y5KUdWn1OBkkPLHXhsrHt5lCDFZxJEs0aVQzE5lpYrtVZVkpc5esTtss/cPJux0lfA==", + "dev": true, + "peer": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "^1.8.1", + "@types/eslint": "^8.56.10", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.8.1.tgz", + "integrity": "sha512-4+40H3lHYTN8OWz+US8CamVkO+2hxNLp9+CAjorI7top/lHqemhpJvKA1LD9Uh+WMY9DYWiWpL2+SZ2wAXY9fQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^6.21.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@tapjs/after": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.31.tgz", + "integrity": "sha512-531NkYOls9PvqfnLsEDRzIWwjynoFRbUVq7pTYuA3PRIw4Ka7jA9uUjILeUurcWjaHrQNzUua0jj/Yu94f6YYw==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/after-each": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-2.0.8.tgz", + "integrity": "sha512-btkpQ/BhmRyG50rezduxEZb3pMJblECvTQa41+U2ln2te1prDTlllHlpq4lOjceUksl8KFF1avDqcBqIqPzneQ==", + "dev": true, + "dependencies": { + "function-loop": "^4.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/asserts": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-2.0.8.tgz", + "integrity": "sha512-57VrI0p2kAqfgHHUwowDvd31eTfDHw3HO4FSSVUCvngPGWa96R6eH9gXa9fNig4qIp4Dup+nI7gJlJfU0R80SA==", + "dev": true, + "dependencies": { + "@tapjs/stack": "2.0.1", + "is-actual-promise": "^1.0.1", + "tcompare": "7.0.1", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/before": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-2.0.8.tgz", + "integrity": "sha512-22ZdGSn/zOKf8J8cb3yfw5R4I/ozdHEDKL8lBWon/zsxxMMvaRTgOtFXEjb4RE+5SDrqQ4NM7ZRYPGhE7T97dw==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/before-each": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-2.0.8.tgz", + "integrity": "sha512-Xjgk8/fuP7iFa5CYjFDl05p5PZGRe//VyHJNuYNzWpF1K9PNMtVdlmwplfpFmbrNrw/bIPq7R6LuiPmTBgzuOw==", + "dev": true, + "dependencies": { + "function-loop": "^4.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/chdir": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@tapjs/chdir/-/chdir-1.1.4.tgz", + "integrity": "sha512-axXkT5kWp2/X8l6inKyrqzUhqgvsgrWI8/0xLAdmirpFZ8H6gFxrl763Ozdm27EAmkLnnnWgFITPqUQCuB/tMA==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/config": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-3.1.6.tgz", + "integrity": "sha512-5gkDMSLXL5798bbCdX4RdLpB4OUQeu9TXftzKmL1+1T2xbcd4q7zfDnCfOB9zTk50x2f04+4h6Q7Z1NcSKIspg==", + "dev": true, + "dependencies": { + "@tapjs/core": "2.1.6", + "@tapjs/test": "2.2.4", + "chalk": "^5.2.0", + "jackspeak": "^3.1.2", + "polite-json": "^4.0.1", + "tap-yaml": "2.2.2", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6", + "@tapjs/test": "2.2.4" + } + }, + "node_modules/@tapjs/config/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@tapjs/core": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-2.1.6.tgz", + "integrity": "sha512-NYMp0bl52DxXfcLmivMKvOIE14aaB9qJjdHeUbs6GZ9yxgD5w0yeiOT+gWEL+1PzZgGWRxSFEpghID1YfXAc4w==", + "dev": true, + "dependencies": { + "@tapjs/processinfo": "^3.1.8", + "@tapjs/stack": "2.0.1", + "@tapjs/test": "2.2.4", + "async-hook-domain": "^4.0.1", + "diff": "^5.2.0", + "is-actual-promise": "^1.0.1", + "minipass": "^7.0.4", + "signal-exit": "4.1", + "tap-parser": "16.0.1", + "tap-yaml": "2.2.2", + "tcompare": "7.0.1", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/@tapjs/error-serdes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-2.0.1.tgz", + "integrity": "sha512-P+M4rtcfkDsUveKKmoRNF+07xpbPnRY5KrstIUOnyn483clQ7BJhsnWr162yYNCsyOj4zEfZmAJI1f8Bi7h/ZA==", + "dev": true, + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/filter": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-2.0.8.tgz", + "integrity": "sha512-/ps6nOS3CTh1WLfCjJnU7tS4PH4KFgEasFSVPCIFN+BasyoqDapzj4JKIlzQvppZOGTQadKH3wUakafZl7uz8w==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/fixture": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-2.0.8.tgz", + "integrity": "sha512-LJnjeAMSozPFXzu+wQw2HJsjA9djHbTcyeMnsgiRL/Q8ffcLqAawV3SN6XKdDLdWYUg3e1fXhHspnbsouZj+xA==", + "dev": true, + "dependencies": { + "mkdirp": "^3.0.0", + "rimraf": "^5.0.5" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/fixture/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/fixture/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/fixture/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/intercept": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-2.0.8.tgz", + "integrity": "sha512-OF2Q35jtZ20bwV4hRNoca7vqIrzPFR3JR25G2rGru+fgPmq4heN0RLoh0d1O34AbrtXqra2lXkacMB/DPgb01A==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.31", + "@tapjs/stack": "2.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/mock": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-2.1.6.tgz", + "integrity": "sha512-bNXKrjg/r+i/gfKij5Oo/5Md2DvGNHPSRCHQmjz3VQjpyxqK7S1FGcR0kyqJ8Nof6Wc8yIhpNOCuibj19200IQ==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.31", + "@tapjs/stack": "2.0.1", + "resolve-import": "^1.4.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/node-serialize": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-2.0.8.tgz", + "integrity": "sha512-92oqhkmIz5wr0yRs1CPQfim5JSwHPSmoDWnQmJlYUZsY1OYgYouQm3ifnPkqK/9hJpVYzlZEQmefxehxbs2WNQ==", + "dev": true, + "dependencies": { + "@tapjs/error-serdes": "2.0.1", + "@tapjs/stack": "2.0.1", + "tap-parser": "16.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/processinfo": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.8.tgz", + "integrity": "sha512-FIriEB+qqArPhmVYc1PZwRHD99myRdl7C9Oe/uts04Q2LOxQ5MEmqP9XOP8vVYzpDOYwmL8OmL6eOYt9eZlQKQ==", + "dev": true, + "dependencies": { + "pirates": "^4.0.5", + "process-on-spawn": "^1.0.0", + "signal-exit": "^4.0.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=16.17" + } + }, + "node_modules/@tapjs/reporter": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-2.0.8.tgz", + "integrity": "sha512-tZn5ZHIrFwjbi59djtdXHBwgSIZSBXdJpz2i9CZ9HEC1nFhWtIr2Jczvrz4ScfixUgA0GNFirz+q+9iA4IFMvw==", + "dev": true, + "dependencies": { + "@tapjs/config": "3.1.6", + "@tapjs/stack": "2.0.1", + "chalk": "^5.2.0", + "ink": "^4.4.1", + "minipass": "^7.0.4", + "ms": "^2.1.3", + "patch-console": "^2.0.0", + "prismjs-terminal": "^1.2.3", + "react": "^18.2.0", + "string-length": "^6.0.0", + "tap-parser": "16.0.1", + "tap-yaml": "2.2.2", + "tcompare": "7.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/reporter/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@tapjs/reporter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@tapjs/run": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-2.1.7.tgz", + "integrity": "sha512-Hk41E68f1x4eLBm6Rrxx4ARzZzrjwaLbKThb16+f3bGYiajmqAvBdeyNEoQpEWmW+Sv2HSlueOk2SS2P4fyetg==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.31", + "@tapjs/before": "2.0.8", + "@tapjs/config": "3.1.6", + "@tapjs/processinfo": "^3.1.8", + "@tapjs/reporter": "2.0.8", + "@tapjs/spawn": "2.0.8", + "@tapjs/stdin": "2.0.8", + "@tapjs/test": "2.2.4", + "c8": "^9.1.0", + "chalk": "^5.3.0", + "chokidar": "^3.6.0", + "foreground-child": "^3.1.1", + "glob": "^10.3.16", + "minipass": "^7.0.4", + "mkdirp": "^3.0.1", + "opener": "^1.5.2", + "pacote": "^17.0.6", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.5", + "semver": "^7.6.0", + "signal-exit": "^4.1.0", + "tap-parser": "16.0.1", + "tap-yaml": "2.2.2", + "tcompare": "7.0.1", + "trivial-deferred": "^2.0.0", + "which": "^4.0.0" + }, + "bin": { + "tap-run": "dist/esm/index.js" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/run/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@tapjs/run/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/run/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@tapjs/run/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/run/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/run/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tapjs/snapshot": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-2.0.8.tgz", + "integrity": "sha512-L0vtqWKkgnQt/XNQkvHOme9Np7ffteCNf1P0F9mz2YiJion4er1nv6pZuJoKVxXFQsbNd2k+LGyx0Iw+bIzwFg==", + "dev": true, + "dependencies": { + "is-actual-promise": "^1.0.1", + "tcompare": "7.0.1", + "trivial-deferred": "^2.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/spawn": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-2.0.8.tgz", + "integrity": "sha512-vCYwynIYJNijY87uHFANe+gCu9rdGoe4GOBmghl6kwDy7eISmcN/FW5TlmrjePMNhTvrDMeYqOIAzqh3WRYmPA==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/stack": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-2.0.1.tgz", + "integrity": "sha512-3rKbZkRkLeJl9ilV/6b80YfI4C4+OYf7iEz5/d0MIVhmVvxv0ttIy5JnZutAc4Gy9eRp5Ne5UTAIFOVY5k36cg==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/stdin": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-2.0.8.tgz", + "integrity": "sha512-tW/exLXuDqjtH2wjptiPHXBahkdSyoppxDY56l9MG4tiz66dMN6NTCZFvQxp7+3t+lsQKqJp/74z8T/ayp+vZA==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/test": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-2.2.4.tgz", + "integrity": "sha512-QIgq2BhMpwO9SN8I0qlwZYXAllO4xWCfJ0MgAGhc+J7p69B5p9dDNPmyOreHeXWMmk6VlNj3oWveoXb5Zn9xZQ==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.7", + "@tapjs/after": "1.1.31", + "@tapjs/after-each": "2.0.8", + "@tapjs/asserts": "2.0.8", + "@tapjs/before": "2.0.8", + "@tapjs/before-each": "2.0.8", + "@tapjs/chdir": "1.1.4", + "@tapjs/filter": "2.0.8", + "@tapjs/fixture": "2.0.8", + "@tapjs/intercept": "2.0.8", + "@tapjs/mock": "2.1.6", + "@tapjs/node-serialize": "2.0.8", + "@tapjs/snapshot": "2.0.8", + "@tapjs/spawn": "2.0.8", + "@tapjs/stdin": "2.0.8", + "@tapjs/typescript": "1.4.13", + "@tapjs/worker": "2.0.8", + "glob": "^10.3.16", + "jackspeak": "^3.1.2", + "mkdirp": "^3.0.0", + "package-json-from-dist": "^1.0.0", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.5", + "sync-content": "^1.0.1", + "tap-parser": "16.0.1", + "tshy": "^1.14.0", + "typescript": "5.4", + "walk-up-path": "^3.0.1" + }, + "bin": { + "generate-tap-test-class": "dist/esm/build.mjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/test/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/test/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/test/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tapjs/typescript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.4.13.tgz", + "integrity": "sha512-MNs7zlhM6G3pNUIjkKXDxgNCwCGZt2bUCGtVunSTDVIrKiUlHAl4QSjQ1oTjumHlCi9gFIWiwFAvpHekzFti0w==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.7" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tapjs/worker": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-2.0.8.tgz", + "integrity": "sha512-AySf2kV6OHvwgD3DrLdT2az2g4hRdoRtKsFCLdZo3jOoKte+ft/IQJEnOW7CPT0RYUskS3elv6eabYgSyTH4tg==", + "dev": true, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "peerDependencies": { + "@tapjs/core": "2.1.6" + } + }, + "node_modules/@tsconfig/node14": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-14.1.2.tgz", + "integrity": "sha512-1vncsbfCZ3TBLPxesRYz02Rn7SNJfbLoDVkcZ7F/ixOV6nwxwgdhD1mdPcc5YQ413qBJ8CvMxXMFfJ7oawjo7Q==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-16.1.3.tgz", + "integrity": "sha512-9nTOUBn+EMKO6rtSZJk+DcqsfgtlERGT9XPJ5PRj/HNENPCBY1yu/JEj5wT6GLtbCLBO2k46SeXDaY0pjMqypw==", + "dev": true + }, + "node_modules/@tsconfig/node18": { + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", + "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", + "dev": true + }, + "node_modules/@tsconfig/node20": { + "version": "20.1.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", + "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", + "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "peer": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "peer": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "20.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", + "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "peer": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "peer": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "peer": true + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + }, + "node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-hook-domain": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-4.0.1.tgz", + "integrity": "sha512-bSktexGodAjfHWIrSrrqxqWzf1hWBZBpmPNZv+TYUMyWa2eoefFc6q6H1+KtdHYSz35lrhWdmXt/XK9wNEZvww==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/auto-bind": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", + "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "peer": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/avvio": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.3.2.tgz", + "integrity": "sha512-st8e519GWHa/azv8S87mcJvZs4WsgTBjOw/Ih1CP6u+8SZvcOeAYNG6JbsIrAUUJJ7JfmrnOkR8ipDS+u9SIRQ==", + "dependencies": { + "@fastify/error": "^3.3.0", + "fastq": "^1.17.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/c8": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz", + "integrity": "sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=14.14.0" + } + }, + "node_modules/cacache": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "peer": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "dev": true, + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "peer": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "peer": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "peer": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "peer": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-yscope": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/eslint-config-yscope/-/eslint-config-yscope-0.0.29.tgz", + "integrity": "sha512-k+jHGltXmGGdBtuacUME7b3M9k0TOXbr/kWxkxVhbFPMX4Eg33WqCDYEiHV/jWlXLfag18YBH3r7RI+ysMIbeg==", + "dev": true, + "peerDependencies": { + "@stylistic/eslint-plugin-js": "^1.6.2", + "@stylistic/eslint-plugin-jsx": "^1.6.2", + "@stylistic/eslint-plugin-plus": "^1.6.2", + "eslint": "^8.57.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-import-newlines": "^1.4.0", + "eslint-plugin-jsdoc": "^48.2.3", + "eslint-plugin-no-autofix": "^1.2.3", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-simple-import-sort": "^12.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "peer": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import-newlines": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.4.0.tgz", + "integrity": "sha512-+Cz1x2xBLtI9gJbmuYEpvY7F8K75wskBmJ7rk4VRObIJo+jklUJaejFJgtnWeL0dCFWabGEkhausrikXaNbtoQ==", + "dev": true, + "peer": true, + "bin": { + "import-linter": "lib/index.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "48.2.12", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.12.tgz", + "integrity": "sha512-sO9sKkJx5ovWoRk9hV0YiNzXQ4Z6j27CqE/po2E3wddZVuy9wvKPSTiIhpxMTrP/qURvKayJIDB2+o9kyCW1Fw==", + "dev": true, + "peer": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.43.1", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "semver": "^7.6.2", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-no-autofix": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", + "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", + "dev": true, + "peer": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0", + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "eslint": ">= 5.12.1" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.2.tgz", + "integrity": "sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==", + "dev": true, + "peer": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "peer": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.0.tgz", + "integrity": "sha512-Y2fqAfC11TcG/WP3TrI1Gi3p3nc8XJyEOJYHyEPEGI/UAgNx6akxxlX74p7SbAQdLcgASKhj8M0GKvH3vq/+ig==", + "dev": true, + "peer": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-to-array": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-2.0.3.tgz", + "integrity": "sha512-f/qE2gImHRa4Cp2y1stEOSgw8wTFyUdVJX7G//bMwbaV9JqISFxg99NbmVQeP7YLnDUZ2un851jlaDrlpmGehQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/fast-content-type-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==" + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "node_modules/fast-json-stringify": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.0.tgz", + "integrity": "sha512-A4bg6E15QrkuVO3f0SwIASgzMzR6XC4qTyTqhf3hYXy0iazbAdZKwkE+ox4WgzKyzM6ygvbdq3r134UjOaaAnA==", + "dependencies": { + "@fastify/merge-json-schemas": "^0.1.0", + "ajv": "^8.10.0", + "ajv-formats": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + }, + "node_modules/fast-uri": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz", + "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==" + }, + "node_modules/fastify": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.28.0.tgz", + "integrity": "sha512-HhW7UHW07YlqH5qpS0af8d2Gl/o98DhJ8ZDQWHRNDnzeOhZvtreWsX8xanjGgXmkYerGbo8ax/n40Dpwqkot8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.3.0", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^8.0.0", + "light-my-request": "^5.11.0", + "pino": "^9.0.0", + "process-warning": "^3.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-my-way": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.0.tgz", + "integrity": "sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^3.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "peer": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "peer": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", + "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-loop": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-4.0.0.tgz", + "integrity": "sha512-f34iQBedYF3XcI93uewZZOnyscDragxgTK/eTvVB74k3fCD0ZorOi5BV9GS4M8rz/JoNi0Kl3qX5Y9MH3S/CLQ==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "peer": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "peer": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "peer": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "peer": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/ignore-walk": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", + "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ink": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/ink/-/ink-4.4.1.tgz", + "integrity": "sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==", + "dev": true, + "dependencies": { + "@alcalzone/ansi-tokenize": "^0.1.3", + "ansi-escapes": "^6.0.0", + "auto-bind": "^5.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "cli-cursor": "^4.0.0", + "cli-truncate": "^3.1.0", + "code-excerpt": "^4.0.0", + "indent-string": "^5.0.0", + "is-ci": "^3.0.1", + "is-lower-case": "^2.0.2", + "is-upper-case": "^2.0.2", + "lodash": "^4.17.21", + "patch-console": "^2.0.0", + "react-reconciler": "^0.29.0", + "scheduler": "^0.23.0", + "signal-exit": "^3.0.7", + "slice-ansi": "^6.0.0", + "stack-utils": "^2.0.6", + "string-width": "^5.1.2", + "type-fest": "^0.12.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0", + "ws": "^8.12.0", + "yoga-wasm-web": "~0.3.3" + }, + "engines": { + "node": ">=14.16" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "react": ">=18.0.0", + "react-devtools-core": "^4.19.1" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-devtools-core": { + "optional": true + } + } + }, + "node_modules/ink/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ink/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/ink/node_modules/type-fest": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-actual-promise": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-actual-promise/-/is-actual-promise-1.0.2.tgz", + "integrity": "sha512-xsFiO1of0CLsQnPZ1iXHNTyR9YszOeWKYv+q6n8oSFW3ipooFJ1j1lbRMgiMCr+pp2gLruESI4zb5Ak6eK5OnQ==", + "dev": true + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "peer": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "peer": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", + "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "peer": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "peer": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", + "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "peer": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "peer": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/light-my-request": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.13.0.tgz", + "integrity": "sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==", + "dependencies": { + "cookie": "^0.6.0", + "process-warning": "^3.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "peer": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/nodemon": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.3.tgz", + "integrity": "sha512-m4Vqs+APdKzDFpuaL9F9EVOF85+h070FnkHVEoU4+rmT6Vw0bmNl7s61VEkY/cJkL7RCv1p4urnUDUMrS5rk2w==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", + "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", + "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", + "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", + "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", + "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", + "dev": true, + "dependencies": { + "@npmcli/redact": "^1.1.0", + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, + "node_modules/pacote": { + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.7.tgz", + "integrity": "sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^4.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-console": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", + "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "peer": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", + "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.2.1.tgz", + "integrity": "sha512-O05NuD9tkRasFRWVaF/uHLOvoRDFD7tb5VMertr78rbsYFjYp48Vg3477EshVAF5eZaEw+OpDl/tu+B0R5o+7g==", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==" + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/polite-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/polite-json/-/polite-json-4.0.1.tgz", + "integrity": "sha512-8LI5ZeCPBEb4uBbcYKNVwk4jgqNx1yHReWoW4H4uUihWlSqZsUDfSITrRhjliuPgxsNPFhNSudGO2Zu4cbWinQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/prismjs-terminal": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prismjs-terminal/-/prismjs-terminal-1.2.3.tgz", + "integrity": "sha512-xc0zuJ5FMqvW+DpiRkvxURlz98DdfDsZcFHdO699+oL+ykbFfgI7O4VDEgUyc07BSL2NHl3zdb8m/tZ/aaqUrw==", + "dev": true, + "dependencies": { + "chalk": "^5.2.0", + "prismjs": "^1.29.0", + "string-length": "^6.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/prismjs-terminal/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "peer": true + }, + "node_modules/react-reconciler": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", + "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/read-package-json": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.1.tgz", + "integrity": "sha512-8PcDiZ8DXUjLf687Ol4BR8Bpm2umR7vhoZOzNRt+uxD9GpBh/K+CAAALVIiYFknmvlmyg7hM7BSNUXPaCCqd0Q==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "peer": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-import": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", + "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", + "dev": true, + "dependencies": { + "glob": "^10.3.3", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/resolve-import/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/resolve-import/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/ret": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", + "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", + "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "dependencies": { + "ret": "~0.4.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", + "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.3.2", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.2", + "@sigstore/sign": "^2.3.2", + "@sigstore/tuf": "^2.3.4", + "@sigstore/verify": "^1.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-6.0.0.tgz", + "integrity": "sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/sonic-boom": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", + "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-6.0.0.tgz", + "integrity": "sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==", + "dev": true, + "dependencies": { + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sync-content": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-content/-/sync-content-1.0.2.tgz", + "integrity": "sha512-znd3rYiiSxU3WteWyS9a6FXkTA/Wjk8WQsOyzHbineeL837dLn3DA4MRhsIX3qGcxDMH6+uuFV4axztssk7wEQ==", + "dev": true, + "dependencies": { + "glob": "^10.2.6", + "mkdirp": "^3.0.1", + "path-scurry": "^1.9.2", + "rimraf": "^5.0.1" + }, + "bin": { + "sync-content": "dist/mjs/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sync-content/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sync-content/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sync-content/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tap": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/tap/-/tap-19.2.5.tgz", + "integrity": "sha512-Mz7MznUuKCqrN9dr0s8REt6zLg6WLNrvGXwDSaUyPO73dpXXjakYA7YVKRWu6TBnj7NsSYKuHXpQFROlqZ2KTg==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.31", + "@tapjs/after-each": "2.0.8", + "@tapjs/asserts": "2.0.8", + "@tapjs/before": "2.0.8", + "@tapjs/before-each": "2.0.8", + "@tapjs/chdir": "1.1.4", + "@tapjs/core": "2.1.6", + "@tapjs/filter": "2.0.8", + "@tapjs/fixture": "2.0.8", + "@tapjs/intercept": "2.0.8", + "@tapjs/mock": "2.1.6", + "@tapjs/node-serialize": "2.0.8", + "@tapjs/run": "2.1.7", + "@tapjs/snapshot": "2.0.8", + "@tapjs/spawn": "2.0.8", + "@tapjs/stdin": "2.0.8", + "@tapjs/test": "2.2.4", + "@tapjs/typescript": "1.4.13", + "@tapjs/worker": "2.0.8", + "resolve-import": "^1.4.5" + }, + "bin": { + "tap": "dist/esm/run.mjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tap-parser": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-16.0.1.tgz", + "integrity": "sha512-vKianJzSSzLkJ3bHBwzvZDDRi9yGMwkRANJxwPAjAue50owB8rlluYySmTN4tZVH0nsh6stvrQbg9kuCL5svdg==", + "dev": true, + "dependencies": { + "events-to-array": "^2.0.3", + "tap-yaml": "2.2.2" + }, + "bin": { + "tap-parser": "bin/cmd.cjs" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/tap-yaml": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.2.tgz", + "integrity": "sha512-MWG4OpAKtNoNVjCz/BqlDJiwTM99tiHRhHPS4iGOe1ZS0CgM4jSFH92lthSFvvy4EdDjQZDV7uYqUFlU9JuNhw==", + "dev": true, + "dependencies": { + "yaml": "^2.4.1", + "yaml-types": "^0.3.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tcompare": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-7.0.1.tgz", + "integrity": "sha512-JN5s7hgmg/Ya5HxZqCnywT+XiOGRFcJRgYhtMyt/1m+h0yWpWwApO7HIM8Bpwyno9hI151ljjp5eAPCHhIGbpQ==", + "dev": true, + "dependencies": { + "diff": "^5.2.0", + "react-element-to-jsx-string": "^15.0.0" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/trivial-deferred": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-2.0.0.tgz", + "integrity": "sha512-iGbM7X2slv9ORDVj2y2FFUq3cP/ypbtu2nQ8S38ufjL0glBABvmR9pTdsib1XtS2LUhhLMbelaBUaf/s5J3dSw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tshy": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.15.1.tgz", + "integrity": "sha512-7p30vmXaNX7OL1yLy/MYUtO0SJOm9fQSnzk3DXaM+LmQosooCB4elVeHAGIIZdABhL2E8dx5t/5msR5lh0xnaQ==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "chokidar": "^3.6.0", + "foreground-child": "^3.1.1", + "minimatch": "^9.0.4", + "mkdirp": "^3.0.1", + "polite-json": "^4.0.1", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.1", + "sync-content": "^1.0.2", + "typescript": "^5.4.5", + "walk-up-path": "^3.0.1" + }, + "bin": { + "tshy": "dist/esm/index.js" + }, + "engines": { + "node": "16 >=16.17 || 18 >=18.15.0 || >=20.6.1" + } + }, + "node_modules/tshy/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/tshy/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tshy/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tshy/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/tuf-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", + "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", + "dev": true, + "dependencies": { + "@tufjs/models": "2.0.1", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "peer": true + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "peer": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "peer": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "peer": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yaml-types/-/yaml-types-0.3.0.tgz", + "integrity": "sha512-i9RxAO/LZBiE0NJUy9pbN5jFz5EasYDImzRkj8Y81kkInTi1laia3P3K/wlMKzOxFQutZip8TejvQP/DwgbU7A==", + "dev": true, + "engines": { + "node": ">= 16", + "npm": ">= 7" + }, + "peerDependencies": { + "yaml": "^2.3.0" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoga-wasm-web": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", + "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", + "dev": true + } + } +} diff --git a/components/log-viewer-webui/server/package.json b/components/log-viewer-webui/server/package.json new file mode 100644 index 000000000..059a0eb22 --- /dev/null +++ b/components/log-viewer-webui/server/package.json @@ -0,0 +1,32 @@ +{ + "name": "log-viewer-server", + "version": "0.1.0", + "description": "", + "main": "src/main.js", + "scripts": { + "dev": "NODE_ENV=development nodemon src/main.js", + "lint:check": "npx eslint --no-eslintrc --config package.json src", + "lint:fix": "npx eslint --fix --no-eslintrc --config package.json src", + "start": "NODE_ENV=production node src/main.js", + "test": "tap" + }, + "author": "YScope Inc. ", + "license": "Apache-2.0", + "type": "module", + "dependencies": { + "dotenv": "^16.4.5", + "fastify": "^4.28.0", + "http-status-codes": "^2.3.0", + "pino-pretty": "^11.2.1" + }, + "devDependencies": { + "eslint-config-yscope": "latest", + "nodemon": "^3.1.3", + "tap": "^19.2.5" + }, + "eslintConfig": { + "extends": [ + "yscope/common" + ] + } +} diff --git a/components/log-viewer-webui/server/src/app.js b/components/log-viewer-webui/server/src/app.js new file mode 100644 index 000000000..22982c352 --- /dev/null +++ b/components/log-viewer-webui/server/src/app.js @@ -0,0 +1,19 @@ +import fastify from "fastify"; + +import exampleRoutes from "./routes/examples.js"; + + +/** + * Creates the Fastify app with the given options. + * + * @param {import("fastify").FastifyServerOptions} fastifyOptions + * @return {Promise} + */ +const app = async (fastifyOptions = {}) => { + const server = fastify(fastifyOptions); + await server.register(exampleRoutes); + + return server; +}; + +export default app; diff --git a/components/log-viewer-webui/server/src/app.test.js b/components/log-viewer-webui/server/src/app.test.js new file mode 100644 index 000000000..1215c795f --- /dev/null +++ b/components/log-viewer-webui/server/src/app.test.js @@ -0,0 +1,26 @@ +import httpStatusCodes from "http-status-codes"; +import {test} from "tap"; + +import app from "./app.js"; + + +test("Tests the example routes", async (t) => { + const server = await app(); + t.teardown(() => server.close()); + + let resp = await server.inject({ + method: "GET", + url: "/examples/get/Alice", + }); + + t.equal(resp.statusCode, httpStatusCodes.OK); + t.match(JSON.parse(resp.body), {msg: String}); + + resp = await server.inject({ + method: "POST", + url: "/examples/post", + payload: {name: "Bob"}, + }); + t.equal(resp.statusCode, httpStatusCodes.OK); + t.match(JSON.parse(resp.body), {msg: String}); +}); diff --git a/components/log-viewer-webui/server/src/main.js b/components/log-viewer-webui/server/src/main.js new file mode 100644 index 000000000..706040dce --- /dev/null +++ b/components/log-viewer-webui/server/src/main.js @@ -0,0 +1,64 @@ +import dotenv from "dotenv"; +import process from "node:process"; + +import app from "./app.js"; + + +/** + * Parses environment variables into config values for the application. + * + * @return {{PORT: string, HOST: string}} + * @throws {Error} if any required environment variable is undefined. + */ +const parseEnvVars = () => { + dotenv.config({ + path: ".env", + }); + + const { + HOST, PORT, + } = process.env; + const envVars = { + HOST, PORT, + }; + + // Check for mandatory environment variables + for (const [key, value] of Object.entries(envVars)) { + if ("undefined" === typeof value) { + throw new Error(`Environment variable ${key} must be defined.`); + } + } + + return envVars; +}; + +/** + * Sets up and runs the server. + */ +const main = async () => { + const envToLogger = { + development: { + transport: { + target: "pino-pretty", + }, + }, + production: true, + test: false, + }; + const server = await app({ + logger: envToLogger[process.env.NODE_ENV] ?? true, + }); + + try { + const envVars = parseEnvVars(); + await server.listen({host: envVars.HOST, port: Number(envVars.PORT)}); + } catch (e) { + server.log.error(e); + process.exit(1); + } +}; + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/components/log-viewer-webui/server/src/routes/examples.js b/components/log-viewer-webui/server/src/routes/examples.js new file mode 100644 index 000000000..8074f4a29 --- /dev/null +++ b/components/log-viewer-webui/server/src/routes/examples.js @@ -0,0 +1,18 @@ +/** + * Creates example routes. + * + * @param {import("fastify").FastifyInstance} fastify + * @param {import("fastify").FastifyPluginOptions} options + * @return {Promise} + */ +const routes = async (fastify, options) => { + fastify.get("/examples/get/:name", async (req, resp) => { + return {msg: `Hello, ${req.params.name}!`}; + }); + + fastify.post("/examples/post", async (req, resp) => { + return {msg: `Goodbye, ${req.body.name}!`}; + }); +}; + +export default routes; diff --git a/docs/src/dev-guide/components-log-viewer-webui.md b/docs/src/dev-guide/components-log-viewer-webui.md new file mode 100644 index 000000000..e77375b9d --- /dev/null +++ b/docs/src/dev-guide/components-log-viewer-webui.md @@ -0,0 +1,61 @@ +# Log Viewer WebUI + +A webapp that allows us to serve the [log-viewer] and integrate it with CLP's [webui]. The webapp +currently consists of a [Fastify] server. In the future, we'll add a [React] frontend. + +## Requirements + +* Node.js v20 or higher + +## Setup + +Install the app's dependencies: + +```shell +cd components/log-viewer-webui/server +npm i +``` + +## Running + +To run the server during development: + +```shell +npm run dev +``` + +To run the server in production: + +```shell +npm start +``` + +In both cases, if you want to customize what host and port the server binds to, you can use the +environment variables in `components/log-viewer-webui/server/.env`. + +## Testing + +To run all unit tests: + +```shell +npm test +``` + +## Linting + +To check for linting errors: + +```shell +npm run lint:check +``` + +To also fix linting errors (if possible): + +```shell +npm run lint:fix +``` + +[Fastify]: https://www.fastify.io/ +[log-viewer]: https://github.com/y-scope/yscope-log-viewer +[React]: https://reactjs.org/ +[webui]: components-webui.md From 22bcd4bea7734401b5c6e83083de50725e33195e Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Fri, 14 Jun 2024 23:48:46 -0400 Subject: [PATCH 005/114] docs: Fix unreferenced doc. (#443) --- docs/src/dev-guide/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/dev-guide/index.md b/docs/src/dev-guide/index.md index 237cf1df0..1dbf560a0 100644 --- a/docs/src/dev-guide/index.md +++ b/docs/src/dev-guide/index.md @@ -63,6 +63,7 @@ contributing-linting :hidden: components-core/index +components-log-viewer-webui components-webui ::: From c9c9548460c550d04ce61c8ab1e5f96c3bcc609d Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sun, 16 Jun 2024 05:38:25 -0400 Subject: [PATCH 006/114] ffi: Extract some serialization methods for use in other files. (#444) --- components/core/CMakeLists.txt | 2 + components/core/src/clp/clp/CMakeLists.txt | 2 + .../clp/ffi/ir_stream/encoding_methods.cpp | 55 +------------------ .../core/src/clp/ffi/ir_stream/utils.cpp | 32 +++++++++++ .../core/src/clp/ffi/ir_stream/utils.hpp | 47 ++++++++++++++++ 5 files changed, 84 insertions(+), 54 deletions(-) create mode 100644 components/core/src/clp/ffi/ir_stream/utils.cpp create mode 100644 components/core/src/clp/ffi/ir_stream/utils.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index c8f76baad..3445d798b 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -304,6 +304,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/decoding_methods.inc src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp + src/clp/ffi/ir_stream/utils.cpp + src/clp/ffi/ir_stream/utils.hpp src/clp/ffi/ir_stream/protocol_constants.hpp src/clp/ffi/SchemaTree.cpp src/clp/ffi/SchemaTree.hpp diff --git a/components/core/src/clp/clp/CMakeLists.txt b/components/core/src/clp/clp/CMakeLists.txt index 1d8a20860..4ea4f20c6 100644 --- a/components/core/src/clp/clp/CMakeLists.txt +++ b/components/core/src/clp/clp/CMakeLists.txt @@ -25,6 +25,8 @@ set( ../ffi/ir_stream/decoding_methods.inc ../ffi/ir_stream/encoding_methods.cpp ../ffi/ir_stream/encoding_methods.hpp + ../ffi/ir_stream/utils.cpp + ../ffi/ir_stream/utils.hpp ../FileReader.cpp ../FileReader.hpp ../FileWriter.cpp diff --git a/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp b/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp index 682972e9d..35363e2d3 100644 --- a/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp @@ -5,8 +5,8 @@ #include "../../ir/parsing.hpp" #include "../../ir/types.hpp" #include "../../time_types.hpp" -#include "byteswap.hpp" #include "protocol_constants.hpp" +#include "utils.hpp" using clp::ir::eight_byte_encoded_variable_t; using clp::ir::epoch_time_ms_t; @@ -17,15 +17,6 @@ using std::vector; namespace clp::ffi::ir_stream { // Local function prototypes -/** - * Serializes the given integer into the IR stream - * @tparam integer_t - * @param value - * @param ir_buf - */ -template -static void serialize_int(integer_t value, vector& ir_buf); - /** * Serializes the given logtype into the IR stream * @param logtype @@ -34,14 +25,6 @@ static void serialize_int(integer_t value, vector& ir_buf); */ static bool serialize_logtype(string_view logtype, vector& ir_buf); -/** - * Serializes the given metadata into the IR stream - * @param metadata - * @param ir_buf - * @return true on success, false otherwise - */ -static bool serialize_metadata(nlohmann::json& metadata, vector& ir_buf); - /** * Adds the basic metadata fields to the given JSON object * @param timestamp_pattern @@ -90,21 +73,6 @@ class DictionaryVariableHandler { vector& m_ir_buf; }; -template -static void serialize_int(integer_t value, vector& ir_buf) { - integer_t value_big_endian; - static_assert(sizeof(integer_t) == 2 || sizeof(integer_t) == 4 || sizeof(integer_t) == 8); - if constexpr (sizeof(value) == 2) { - value_big_endian = bswap_16(value); - } else if constexpr (sizeof(value) == 4) { - value_big_endian = bswap_32(value); - } else if constexpr (sizeof(value) == 8) { - value_big_endian = bswap_64(value); - } - auto data = reinterpret_cast(&value_big_endian); - ir_buf.insert(ir_buf.end(), data, data + sizeof(value)); -} - static bool serialize_logtype(string_view logtype, vector& ir_buf) { auto length = logtype.length(); if (length <= UINT8_MAX) { @@ -124,27 +92,6 @@ static bool serialize_logtype(string_view logtype, vector& ir_buf) { return true; } -static bool serialize_metadata(nlohmann::json& metadata, vector& ir_buf) { - ir_buf.push_back(cProtocol::Metadata::EncodingJson); - - auto metadata_serialized - = metadata.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore); - auto metadata_serialized_length = metadata_serialized.length(); - if (metadata_serialized_length <= UINT8_MAX) { - ir_buf.push_back(cProtocol::Metadata::LengthUByte); - ir_buf.push_back(bit_cast(static_cast(metadata_serialized_length))); - } else if (metadata_serialized_length <= UINT16_MAX) { - ir_buf.push_back(cProtocol::Metadata::LengthUShort); - serialize_int(static_cast(metadata_serialized_length), ir_buf); - } else { - // Can't encode metadata longer than 64 KiB - return false; - } - ir_buf.insert(ir_buf.cend(), metadata_serialized.cbegin(), metadata_serialized.cend()); - - return true; -} - static void add_base_metadata_fields( string_view timestamp_pattern, string_view timestamp_pattern_syntax, diff --git a/components/core/src/clp/ffi/ir_stream/utils.cpp b/components/core/src/clp/ffi/ir_stream/utils.cpp new file mode 100644 index 000000000..0a22536b6 --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/utils.cpp @@ -0,0 +1,32 @@ +#include "utils.hpp" + +#include +#include + +#include + +#include "../../type_utils.hpp" +#include "protocol_constants.hpp" + +namespace clp::ffi::ir_stream { +auto serialize_metadata(nlohmann::json& metadata, std::vector& ir_buf) -> bool { + ir_buf.push_back(cProtocol::Metadata::EncodingJson); + + auto const metadata_serialized + = metadata.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore); + auto const metadata_serialized_length = metadata_serialized.length(); + if (metadata_serialized_length <= UINT8_MAX) { + ir_buf.push_back(cProtocol::Metadata::LengthUByte); + ir_buf.push_back(bit_cast(static_cast(metadata_serialized_length))); + } else if (metadata_serialized_length <= UINT16_MAX) { + ir_buf.push_back(cProtocol::Metadata::LengthUShort); + serialize_int(static_cast(metadata_serialized_length), ir_buf); + } else { + // Can't encode metadata longer than 64 KiB + return false; + } + ir_buf.insert(ir_buf.cend(), metadata_serialized.cbegin(), metadata_serialized.cend()); + + return true; +} +} // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/utils.hpp b/components/core/src/clp/ffi/ir_stream/utils.hpp new file mode 100644 index 000000000..5e1fb293a --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/utils.hpp @@ -0,0 +1,47 @@ +#ifndef CLP_FFI_IR_STREAM_UTILS_HPP +#define CLP_FFI_IR_STREAM_UTILS_HPP + +#include +#include +#include + +#include + +#include "byteswap.hpp" + +namespace clp::ffi::ir_stream { +/** + * Serializes the given metadata into the IR stream. + * @param metadata + * @param ir_buf + * @return Whether serialization succeeded. + */ +[[nodiscard]] auto +serialize_metadata(nlohmann::json& metadata, std::vector& ir_buf) -> bool; + +/** + * Serializes the given integer into the IR stream. + * @tparam integer_t + * @param value + * @param ir_buf + */ +template +auto serialize_int(integer_t value, std::vector& ir_buf) -> void; + +template +auto serialize_int(integer_t value, std::vector& ir_buf) -> void { + integer_t value_big_endian{}; + static_assert(sizeof(integer_t) == 2 || sizeof(integer_t) == 4 || sizeof(integer_t) == 8); + if constexpr (sizeof(value) == 2) { + value_big_endian = bswap_16(value); + } else if constexpr (sizeof(value) == 4) { + value_big_endian = bswap_32(value); + } else if constexpr (sizeof(value) == 8) { + value_big_endian = bswap_64(value); + } + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + std::span const data_view{reinterpret_cast(&value_big_endian), sizeof(value)}; + ir_buf.insert(ir_buf.end(), data_view.begin(), data_view.end()); +} +} // namespace clp::ffi::ir_stream +#endif From b335c113b295e171d8208f5c880d95b437640407 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:50:37 -0400 Subject: [PATCH 007/114] core: Add C++ classes for read-only memory-mapped files and UNIX file descriptors; Remove Zstandard's dependency on Boost. (#445) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 5 + components/core/src/clp/FileDescriptor.cpp | 63 +++++++++++++ components/core/src/clp/FileDescriptor.hpp | 93 +++++++++++++++++++ .../core/src/clp/ReadOnlyMemoryMappedFile.cpp | 41 ++++++++ .../core/src/clp/ReadOnlyMemoryMappedFile.hpp | 66 +++++++++++++ components/core/src/clp/clg/CMakeLists.txt | 4 + components/core/src/clp/clo/CMakeLists.txt | 4 + components/core/src/clp/clp/CMakeLists.txt | 4 + .../make_dictionaries_readable/CMakeLists.txt | 4 + .../zstd/Decompressor.cpp | 44 ++------- .../zstd/Decompressor.hpp | 4 +- .../core/tests/test-MemoryMappedFile.cpp | 64 +++++++++++++ .../core/tests/test-StreamingCompression.cpp | 1 + 13 files changed, 357 insertions(+), 40 deletions(-) create mode 100644 components/core/src/clp/FileDescriptor.cpp create mode 100644 components/core/src/clp/FileDescriptor.hpp create mode 100644 components/core/src/clp/ReadOnlyMemoryMappedFile.cpp create mode 100644 components/core/src/clp/ReadOnlyMemoryMappedFile.hpp create mode 100644 components/core/tests/test-MemoryMappedFile.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 3445d798b..99d3c8469 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -324,6 +324,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/search/Subquery.hpp src/clp/ffi/search/WildcardToken.cpp src/clp/ffi/search/WildcardToken.hpp + src/clp/FileDescriptor.cpp + src/clp/FileDescriptor.hpp src/clp/FileReader.cpp src/clp/FileReader.hpp src/clp/FileWriter.cpp @@ -381,6 +383,8 @@ set(SOURCE_FILES_unitTest src/clp/Query.hpp src/clp/ReaderInterface.cpp src/clp/ReaderInterface.hpp + src/clp/ReadOnlyMemoryMappedFile.cpp + src/clp/ReadOnlyMemoryMappedFile.hpp src/clp/spdlog_with_specializations.hpp src/clp/SQLiteDB.cpp src/clp/SQLiteDB.hpp @@ -456,6 +460,7 @@ set(SOURCE_FILES_unitTest tests/test-kql.cpp tests/test-main.cpp tests/test-math_utils.cpp + tests/test-MemoryMappedFile.cpp tests/test-NetworkReader.cpp tests/test-ParserWithUserSchema.cpp tests/test-query_methods.cpp diff --git a/components/core/src/clp/FileDescriptor.cpp b/components/core/src/clp/FileDescriptor.cpp new file mode 100644 index 000000000..2e17bfe05 --- /dev/null +++ b/components/core/src/clp/FileDescriptor.cpp @@ -0,0 +1,63 @@ +#include "FileDescriptor.hpp" + +#include +#include +#include + +#include +#include +#include + +#include "ErrorCode.hpp" +#include "type_utils.hpp" + +namespace clp { +FileDescriptor::FileDescriptor( + std::string_view path, + OpenMode open_mode, + CloseFailureCallback close_failure_callback +) + : m_open_mode{open_mode}, + m_close_failure_callback{close_failure_callback} { + // For newly created files, we enable writing for the owner and reading for everyone. + // Callers can change the created file's permissions as necessary. + constexpr auto cNewFilePermission{S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH}; + auto const flag{enum_to_underlying_type(open_mode)}; + if (0 != (flag & O_CREAT)) { + m_fd = open(path.data(), flag, cNewFilePermission); + } else { + m_fd = open(path.data(), flag); + } + if (-1 == m_fd) { + throw OperationFailed( + ErrorCode_errno, + __FILE__, + __LINE__, + "Failed to open file descriptor for path: " + std::string{path} + ); + } +} + +FileDescriptor::~FileDescriptor() { + if (-1 == m_fd) { + return; + } + if (0 != close(m_fd) && nullptr != m_close_failure_callback) { + m_close_failure_callback(errno); + } +} + +auto FileDescriptor::get_size() const -> size_t { + struct stat stat_result {}; + + if (0 != fstat(m_fd, &stat_result)) { + throw OperationFailed( + ErrorCode_errno, + __FILE__, + __LINE__, + "Failed to stat file using file descriptor." + ); + } + return static_cast(stat_result.st_size); +} +} // namespace clp diff --git a/components/core/src/clp/FileDescriptor.hpp b/components/core/src/clp/FileDescriptor.hpp new file mode 100644 index 000000000..a704326bf --- /dev/null +++ b/components/core/src/clp/FileDescriptor.hpp @@ -0,0 +1,93 @@ +#ifndef CLP_FILEDESCRIPTOR_HPP +#define CLP_FILEDESCRIPTOR_HPP + +#include + +#include +#include +#include +#include + +#include "ErrorCode.hpp" +#include "TraceableException.hpp" + +namespace clp { +/** + * Wrapper for a UNIX file descriptor. + */ +class FileDescriptor { +public: + // Types + /** + * `close` is called in the destructor to close the file descriptor. However, `close` may return + * an error indicated by `errno`. This type alias defines a callback to handle the `close` + * failure in the destructor. + * The signature of the callback: void close_failure_callback(int errno) + */ + using CloseFailureCallback = void (*)(int); + + class OperationFailed : public TraceableException { + public: + OperationFailed( + ErrorCode error_code, + char const* const filename, + int line_number, + std::string msg + ) + : TraceableException{error_code, filename, line_number}, + m_msg{std::move(msg)} {} + + [[nodiscard]] auto what() const noexcept -> char const* override { return m_msg.c_str(); } + + private: + std::string m_msg; + }; + + /** + * A C++ wrapper for Unix oflag that describes the open mode. + */ + // NOLINTNEXTLINE(performance-enum-size) + enum class OpenMode : int { + ReadOnly = O_RDONLY, + CreateForWrite = O_WRONLY | O_CREAT | O_TRUNC, + }; + + // Constructors + FileDescriptor( + std::string_view path, + OpenMode open_mode, + CloseFailureCallback close_failure_callback = nullptr + ); + + // Destructor + ~FileDescriptor(); + + // Disable copy/move constructors/assignment operators + FileDescriptor(FileDescriptor const&) = delete; + FileDescriptor(FileDescriptor&&) = delete; + auto operator=(FileDescriptor const&) -> FileDescriptor& = delete; + auto operator=(FileDescriptor&&) -> FileDescriptor& = delete; + + /** + * @return The raw fd. + */ + [[nodiscard]] auto get_raw_fd() const -> int { return m_fd; } + + /** + * @return The size of the file. + */ + [[nodiscard]] auto get_size() const -> size_t; + + /** + * @return The open mode. + */ + [[nodiscard]] auto get_open_mode() const -> OpenMode { return m_open_mode; } + +private: + int m_fd{-1}; + OpenMode m_open_mode; + CloseFailureCallback m_close_failure_callback{nullptr}; +}; +} // namespace clp + +#endif diff --git a/components/core/src/clp/ReadOnlyMemoryMappedFile.cpp b/components/core/src/clp/ReadOnlyMemoryMappedFile.cpp new file mode 100644 index 000000000..167b675a5 --- /dev/null +++ b/components/core/src/clp/ReadOnlyMemoryMappedFile.cpp @@ -0,0 +1,41 @@ +#include "ReadOnlyMemoryMappedFile.hpp" + +#include + +#include +#include + +#include "ErrorCode.hpp" +#include "FileDescriptor.hpp" + +namespace clp { +ReadOnlyMemoryMappedFile::ReadOnlyMemoryMappedFile(std::string_view path) { + FileDescriptor const fd{path, FileDescriptor::OpenMode::ReadOnly}; + auto const file_size{fd.get_size()}; + if (0 == file_size) { + // `mmap` doesn't allow mapping an empty file, so we don't need to call it. + return; + } + auto* mmap_ptr{mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd.get_raw_fd(), 0)}; + if (MAP_FAILED == mmap_ptr) { + throw OperationFailed( + ErrorCode_errno, + __FILE__, + __LINE__, + "`mmap` failed to map path: " + std::string{path} + ); + } + m_data = mmap_ptr; + m_buf_size = file_size; +} + +ReadOnlyMemoryMappedFile::~ReadOnlyMemoryMappedFile() { + if (0 == m_buf_size) { + // We don't call `mmap` for empty files, so we don't need to call `munmap`. + return; + } + // We skip error checking since the only likely reason for `munmap` to fail is if we give it + // invalid arguments. + munmap(m_data, m_buf_size); +} +} // namespace clp diff --git a/components/core/src/clp/ReadOnlyMemoryMappedFile.hpp b/components/core/src/clp/ReadOnlyMemoryMappedFile.hpp new file mode 100644 index 000000000..5749d3bd2 --- /dev/null +++ b/components/core/src/clp/ReadOnlyMemoryMappedFile.hpp @@ -0,0 +1,66 @@ +#ifndef CLP_READONLYMEMORYMAPPEDFILE_HPP +#define CLP_READONLYMEMORYMAPPEDFILE_HPP + +#include +#include +#include +#include +#include + +#include "ErrorCode.hpp" +#include "TraceableException.hpp" + +namespace clp { +/** + * A class for mapping a read-only file into memory. It maintains the memory buffer created by the + * underlying `mmap` system call and provides methods to get a view of the memory buffer. + */ +class ReadOnlyMemoryMappedFile { +public: + // Types + class OperationFailed : public TraceableException { + public: + OperationFailed( + ErrorCode error_code, + char const* const filename, + int line_number, + std::string msg + ) + : TraceableException{error_code, filename, line_number}, + m_msg{std::move(msg)} {} + + [[nodiscard]] auto what() const noexcept -> char const* override { return m_msg.c_str(); } + + private: + std::string m_msg; + }; + + // Constructors + /** + * @param path The path of the file to map. + */ + explicit ReadOnlyMemoryMappedFile(std::string_view path); + + // Destructor + ~ReadOnlyMemoryMappedFile(); + + // Disable copy/move constructors/assignment operators + ReadOnlyMemoryMappedFile(ReadOnlyMemoryMappedFile const&) = delete; + ReadOnlyMemoryMappedFile(ReadOnlyMemoryMappedFile&&) = delete; + auto operator=(ReadOnlyMemoryMappedFile const&) -> ReadOnlyMemoryMappedFile& = delete; + auto operator=(ReadOnlyMemoryMappedFile&&) -> ReadOnlyMemoryMappedFile& = delete; + + /** + * @return A view of the mapped file in memory. + */ + [[nodiscard]] auto get_view() const -> std::span { + return std::span{static_cast(m_data), m_buf_size}; + } + +private: + void* m_data{nullptr}; + size_t m_buf_size{0}; +}; +} // namespace clp + +#endif diff --git a/components/core/src/clp/clg/CMakeLists.txt b/components/core/src/clp/clg/CMakeLists.txt index 37c5a3710..bed6c11fc 100644 --- a/components/core/src/clp/clg/CMakeLists.txt +++ b/components/core/src/clp/clg/CMakeLists.txt @@ -18,6 +18,8 @@ set( ../ffi/ir_stream/decoding_methods.cpp ../ffi/ir_stream/decoding_methods.hpp ../ffi/ir_stream/decoding_methods.inc + ../FileDescriptor.cpp + ../FileDescriptor.hpp ../FileReader.cpp ../FileReader.hpp ../FileWriter.cpp @@ -57,6 +59,8 @@ set( ../Query.hpp ../ReaderInterface.cpp ../ReaderInterface.hpp + ../ReadOnlyMemoryMappedFile.cpp + ../ReadOnlyMemoryMappedFile.hpp ../spdlog_with_specializations.hpp ../SQLiteDB.cpp ../SQLiteDB.hpp diff --git a/components/core/src/clp/clo/CMakeLists.txt b/components/core/src/clp/clo/CMakeLists.txt index b798e918a..306b6049d 100644 --- a/components/core/src/clp/clo/CMakeLists.txt +++ b/components/core/src/clp/clo/CMakeLists.txt @@ -20,6 +20,8 @@ set( ../ffi/ir_stream/decoding_methods.cpp ../ffi/ir_stream/decoding_methods.hpp ../ffi/ir_stream/decoding_methods.inc + ../FileDescriptor.cpp + ../FileDescriptor.hpp ../FileReader.cpp ../FileReader.hpp ../FileWriter.cpp @@ -49,6 +51,8 @@ set( ../Query.hpp ../ReaderInterface.cpp ../ReaderInterface.hpp + ../ReadOnlyMemoryMappedFile.cpp + ../ReadOnlyMemoryMappedFile.hpp ../spdlog_with_specializations.hpp ../SQLiteDB.cpp ../SQLiteDB.hpp diff --git a/components/core/src/clp/clp/CMakeLists.txt b/components/core/src/clp/clp/CMakeLists.txt index 4ea4f20c6..b8e073dd1 100644 --- a/components/core/src/clp/clp/CMakeLists.txt +++ b/components/core/src/clp/clp/CMakeLists.txt @@ -27,6 +27,8 @@ set( ../ffi/ir_stream/encoding_methods.hpp ../ffi/ir_stream/utils.cpp ../ffi/ir_stream/utils.hpp + ../FileDescriptor.cpp + ../FileDescriptor.hpp ../FileReader.cpp ../FileReader.hpp ../FileWriter.cpp @@ -80,6 +82,8 @@ set( ../Query.hpp ../ReaderInterface.cpp ../ReaderInterface.hpp + ../ReadOnlyMemoryMappedFile.cpp + ../ReadOnlyMemoryMappedFile.hpp ../spdlog_with_specializations.hpp ../SQLiteDB.cpp ../SQLiteDB.hpp diff --git a/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt b/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt index 6dc5334bf..fd62a39fb 100644 --- a/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt +++ b/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt @@ -4,6 +4,8 @@ set( ../dictionary_utils.hpp ../DictionaryEntry.hpp ../DictionaryReader.hpp + ../FileDescriptor.cpp + ../FileDescriptor.hpp ../FileReader.cpp ../FileReader.hpp ../FileWriter.cpp @@ -17,6 +19,8 @@ set( ../ParsedMessage.hpp ../ReaderInterface.cpp ../ReaderInterface.hpp + ../ReadOnlyMemoryMappedFile.cpp + ../ReadOnlyMemoryMappedFile.hpp ../spdlog_with_specializations.hpp ../streaming_compression/Decompressor.hpp ../streaming_compression/passthrough/Decompressor.cpp diff --git a/components/core/src/clp/streaming_compression/zstd/Decompressor.cpp b/components/core/src/clp/streaming_compression/zstd/Decompressor.cpp index 9f320efe6..818379a24 100644 --- a/components/core/src/clp/streaming_compression/zstd/Decompressor.cpp +++ b/components/core/src/clp/streaming_compression/zstd/Decompressor.cpp @@ -2,9 +2,8 @@ #include -#include - #include "../../Defs.h" +#include "../../ReadOnlyMemoryMappedFile.hpp" #include "../../spdlog_with_specializations.hpp" namespace clp::streaming_compression::zstd { @@ -182,10 +181,7 @@ void Decompressor::open(FileReader& file_reader, size_t file_read_buffer_capacit void Decompressor::close() { switch (m_input_type) { case InputType::MemoryMappedCompressedFile: - if (m_memory_mapped_compressed_file.is_open()) { - // An existing file is memory mapped by the decompressor - m_memory_mapped_compressed_file.close(); - } + m_memory_mapped_file.reset(); break; case InputType::File: m_file_read_buffer.reset(); @@ -209,40 +205,12 @@ ErrorCode Decompressor::open(std::string const& compressed_file_path) { } m_input_type = InputType::MemoryMappedCompressedFile; - // Create memory mapping for compressed_file_path, use boost read only - // memory mapped file - boost::system::error_code boost_error_code; - size_t compressed_file_size - = boost::filesystem::file_size(compressed_file_path, boost_error_code); - if (boost_error_code) { - SPDLOG_ERROR( - "streaming_compression::zstd::Decompressor: Unable to obtain file size for " - "'{}' - {}.", - compressed_file_path.c_str(), - boost_error_code.message().c_str() - ); - return ErrorCode_Failure; - } - - boost::iostreams::mapped_file_params memory_map_params; - memory_map_params.path = compressed_file_path; - memory_map_params.flags = boost::iostreams::mapped_file::readonly; - memory_map_params.length = compressed_file_size; - // Try to map it to the same memory location as previous memory mapped - // file - memory_map_params.hint = m_memory_mapped_compressed_file.data(); - m_memory_mapped_compressed_file.open(memory_map_params); - if (!m_memory_mapped_compressed_file.is_open()) { - SPDLOG_ERROR( - "streaming_compression::zstd::Decompressor: Unable to memory map the " - "compressed file with path: {}", - compressed_file_path.c_str() - ); - return ErrorCode_Failure; - } + // Create read-only memory mapping for compressed_file_path + m_memory_mapped_file = std::make_unique(compressed_file_path); + auto const file_view{m_memory_mapped_file->get_view()}; // Configure input stream - m_compressed_stream_block = {m_memory_mapped_compressed_file.data(), compressed_file_size, 0}; + m_compressed_stream_block = {file_view.data(), file_view.size(), 0}; reset_stream(); diff --git a/components/core/src/clp/streaming_compression/zstd/Decompressor.hpp b/components/core/src/clp/streaming_compression/zstd/Decompressor.hpp index 665674373..cc9e90fe4 100644 --- a/components/core/src/clp/streaming_compression/zstd/Decompressor.hpp +++ b/components/core/src/clp/streaming_compression/zstd/Decompressor.hpp @@ -4,10 +4,10 @@ #include #include -#include #include #include "../../FileReader.hpp" +#include "../../ReadOnlyMemoryMappedFile.hpp" #include "../../TraceableException.hpp" #include "../Decompressor.hpp" @@ -125,7 +125,7 @@ class Decompressor : public ::clp::streaming_compression::Decompressor { // Compressed stream variables ZSTD_DStream* m_decompression_stream; - boost::iostreams::mapped_file_source m_memory_mapped_compressed_file; + std::unique_ptr m_memory_mapped_file; FileReader* m_file_reader; size_t m_file_reader_initial_pos; std::unique_ptr m_file_read_buffer; diff --git a/components/core/tests/test-MemoryMappedFile.cpp b/components/core/tests/test-MemoryMappedFile.cpp new file mode 100644 index 000000000..20d433f32 --- /dev/null +++ b/components/core/tests/test-MemoryMappedFile.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include + +#include + +#include "../src/clp/FileReader.hpp" +#include "../src/clp/ReaderInterface.hpp" +#include "../src/clp/ReadOnlyMemoryMappedFile.hpp" + +namespace { +/** + * Reads all content from a reader. + * @param reader + * @return The content. + */ +[[nodiscard]] auto read_content(clp::ReaderInterface& reader) -> std::vector; + +[[nodiscard]] auto get_test_dir() -> std::filesystem::path; + +auto read_content(clp::ReaderInterface& reader) -> std::vector { + constexpr size_t cBufferSize{4096}; + std::array read_buf{}; + std::vector buf; + for (bool has_more_content{true}; has_more_content;) { + size_t num_bytes_read{}; + has_more_content = reader.read(read_buf.data(), read_buf.size(), num_bytes_read); + buf.insert(buf.cend(), read_buf.cbegin(), read_buf.cbegin() + num_bytes_read); + } + return buf; +} + +auto get_test_dir() -> std::filesystem::path { + std::filesystem::path const current_file_path{__FILE__}; + return current_file_path.parent_path(); +} +} // namespace + +TEST_CASE("memory_mapped_file_view_basic", "[ReadOnlyMemoryMappedFile]") { + auto const test_input_path{ + get_test_dir() / std::filesystem::path{"test_network_reader_src"} / "random.log" + }; + clp::FileReader file_reader; + file_reader.open(test_input_path.string()); + auto const expected{read_content(file_reader)}; + file_reader.close(); + + clp::ReadOnlyMemoryMappedFile const mmap_file{test_input_path.string()}; + auto const view{mmap_file.get_view()}; + REQUIRE((view.size() == expected.size())); + REQUIRE(std::equal(view.begin(), view.end(), expected.cbegin())); +} + +TEST_CASE("memory_mapped_file_view_empty", "[ReadOnlyMemoryMappedFile]") { + auto const test_input_path{ + get_test_dir() / std::filesystem::path{"test_schema_files"} / "empty_schema.txt" + }; + + clp::ReadOnlyMemoryMappedFile const mmap_file{test_input_path.string()}; + auto const view{mmap_file.get_view()}; + REQUIRE(view.empty()); +} diff --git a/components/core/tests/test-StreamingCompression.cpp b/components/core/tests/test-StreamingCompression.cpp index cad66d028..b43316b3f 100644 --- a/components/core/tests/test-StreamingCompression.cpp +++ b/components/core/tests/test-StreamingCompression.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include From 92ba15a7d5ae3bbf667bb450532322763bbf5857 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:54:01 -0400 Subject: [PATCH 008/114] package: Rename "search" to "query" in search-cluster related variables to prepare for additional job types: (#449) - Rename search scheduler/worker/job/task to query scheduler/worker/job/task where appropriate. - Rename search_config to job_config in metadata DB. - Add QueryJob base class for SearchJob. --- .../scripts/native/search.py | 14 +- .../clp_package_utils/scripts/start_clp.py | 56 ++++---- .../clp_package_utils/scripts/stop_clp.py | 20 +-- .../clp-py-utils/clp_py_utils/clp_config.py | 18 +-- .../initialize-orchestration-db.py | 28 ++-- .../core/src/reducer/CommandLineArguments.cpp | 4 +- components/core/src/reducer/ServerContext.cpp | 10 +- components/core/src/reducer/ServerContext.hpp | 6 +- .../core/src/reducer/reducer_server.cpp | 2 +- .../executor/{search => query}/__init__.py | 0 .../executor/{search => query}/celery.py | 2 +- .../{search => query}/celeryconfig.py | 4 +- .../{search => query}/fs_search_task.py | 24 ++-- .../job_orchestration/reducer/reducer.py | 4 +- .../job_orchestration/scheduler/constants.py | 16 +-- .../scheduler/{search => query}/__init__.py | 0 .../query_scheduler.py} | 120 +++++++++--------- .../{search => query}/reducer_handler.py | 8 +- .../scheduler/scheduler_data.py | 17 ++- .../package-template/src/etc/clp-config.yml | 6 +- .../webui/imports/api/search/constants.js | 32 ++--- ...JobsDbManager.js => QueryJobsDbManager.js} | 54 ++++---- .../imports/api/search/server/methods.js | 28 ++-- components/webui/imports/utils/DbManager.js | 10 +- components/webui/server/main.js | 2 +- components/webui/settings.json | 2 +- .../quick-start-cluster-setup/multi-node.md | 26 ++-- 27 files changed, 259 insertions(+), 254 deletions(-) rename components/job-orchestration/job_orchestration/executor/{search => query}/__init__.py (100%) rename components/job-orchestration/job_orchestration/executor/{search => query}/celery.py (85%) rename components/job-orchestration/job_orchestration/executor/{search => query}/celeryconfig.py (83%) rename components/job-orchestration/job_orchestration/executor/{search => query}/fs_search_task.py (91%) rename components/job-orchestration/job_orchestration/scheduler/{search => query}/__init__.py (100%) rename components/job-orchestration/job_orchestration/scheduler/{search/search_scheduler.py => query/query_scheduler.py} (89%) rename components/job-orchestration/job_orchestration/scheduler/{search => query}/reducer_handler.py (96%) rename components/webui/imports/api/search/server/{SearchJobsDbManager.js => QueryJobsDbManager.js} (66%) diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/search.py b/components/clp-package-utils/clp_package_utils/scripts/native/search.py index 844630d3f..aa261d904 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/search.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/search.py @@ -13,9 +13,9 @@ import msgpack import pymongo -from clp_py_utils.clp_config import Database, ResultsCache, SEARCH_JOBS_TABLE_NAME +from clp_py_utils.clp_config import Database, QUERY_JOBS_TABLE_NAME, ResultsCache from clp_py_utils.sql_adapter import SQL_Adapter -from job_orchestration.scheduler.constants import SearchJobStatus +from job_orchestration.scheduler.constants import QueryJobStatus from job_orchestration.scheduler.job_config import AggregationConfig, SearchConfig from clp_package_utils.general import ( @@ -111,7 +111,7 @@ def create_and_monitor_job_in_db( ) as db_cursor: # Create job db_cursor.execute( - f"INSERT INTO `{SEARCH_JOBS_TABLE_NAME}` (`search_config`) VALUES (%s)", + f"INSERT INTO `{QUERY_JOBS_TABLE_NAME}` (`job_config`) VALUES (%s)", (msgpack.packb(search_config.dict()),), ) db_conn.commit() @@ -120,16 +120,16 @@ def create_and_monitor_job_in_db( # Wait for the job to be marked complete while True: db_cursor.execute( - f"SELECT `status` FROM `{SEARCH_JOBS_TABLE_NAME}` WHERE `id` = {job_id}" + f"SELECT `status` FROM `{QUERY_JOBS_TABLE_NAME}` WHERE `id` = {job_id}" ) # There will only ever be one row since it's impossible to have more than one job with # the same ID new_status = db_cursor.fetchall()[0]["status"] db_conn.commit() if new_status in ( - SearchJobStatus.SUCCEEDED, - SearchJobStatus.FAILED, - SearchJobStatus.CANCELLED, + QueryJobStatus.SUCCEEDED, + QueryJobStatus.FAILED, + QueryJobStatus.CANCELLED, ): break diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index c90671f46..a798d2112 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -21,13 +21,13 @@ COMPRESSION_WORKER_COMPONENT_NAME, CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME, + QUERY_JOBS_TABLE_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, QUEUE_COMPONENT_NAME, REDIS_COMPONENT_NAME, REDUCER_COMPONENT_NAME, RESULTS_CACHE_COMPONENT_NAME, - SEARCH_JOBS_TABLE_NAME, - SEARCH_SCHEDULER_COMPONENT_NAME, - SEARCH_WORKER_COMPONENT_NAME, WEBUI_COMPONENT_NAME, ) from job_orchestration.scheduler.constants import QueueName @@ -416,15 +416,15 @@ def start_compression_scheduler( ) -def start_search_scheduler( +def start_query_scheduler( instance_id: str, clp_config: CLPConfig, container_clp_config: CLPConfig, mounts: CLPDockerMounts, ): - module_name = "job_orchestration.scheduler.search.search_scheduler" + module_name = "job_orchestration.scheduler.query.query_scheduler" generic_start_scheduler( - SEARCH_SCHEDULER_COMPONENT_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, module_name, instance_id, clp_config, @@ -474,10 +474,10 @@ def generic_start_scheduler( "-e", ( f"RESULT_BACKEND=redis://default:{container_clp_config.redis.password}@" f"{container_clp_config.redis.host}:{container_clp_config.redis.port}/" - f"{container_clp_config.redis.search_backend_database}" + f"{container_clp_config.redis.query_backend_database}" ), "-e", f"CLP_LOGS_DIR={container_logs_dir}", - "-e", f"CLP_LOGGING_LEVEL={clp_config.search_scheduler.logging_level}", + "-e", f"CLP_LOGGING_LEVEL={clp_config.query_scheduler.logging_level}", "-u", f"{os.getuid()}:{os.getgid()}", "--mount", str(mounts.clp_home), ] @@ -529,24 +529,24 @@ def start_compression_worker( ) -def start_search_worker( +def start_query_worker( instance_id: str, clp_config: CLPConfig, container_clp_config: CLPConfig, num_cpus: int, mounts: CLPDockerMounts, ): - celery_method = "job_orchestration.executor.search" - celery_route = f"{QueueName.SEARCH}" + celery_method = "job_orchestration.executor.query" + celery_route = f"{QueueName.QUERY}" generic_start_worker( - SEARCH_WORKER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, instance_id, clp_config, - clp_config.search_worker, + clp_config.query_worker, container_clp_config, celery_method, celery_route, - clp_config.redis.search_backend_database, + clp_config.redis.query_backend_database, num_cpus, mounts, ) @@ -696,7 +696,7 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts "SqlDbClpArchivesTableName": f"{CLP_METADATA_TABLE_PREFIX}archives", "SqlDbClpFilesTableName": f"{CLP_METADATA_TABLE_PREFIX}files", "SqlDbCompressionJobsTableName": COMPRESSION_JOBS_TABLE_NAME, - "SqlDbSearchJobsTableName": SEARCH_JOBS_TABLE_NAME, + "SqlDbQueryJobsTableName": QUERY_JOBS_TABLE_NAME, }, "public": { "ClpStorageEngine": clp_config.package.storage_engine, @@ -839,11 +839,11 @@ def main(argv): component_args_parser.add_parser(REDIS_COMPONENT_NAME) component_args_parser.add_parser(RESULTS_CACHE_COMPONENT_NAME) component_args_parser.add_parser(COMPRESSION_SCHEDULER_COMPONENT_NAME) - component_args_parser.add_parser(SEARCH_SCHEDULER_COMPONENT_NAME) + component_args_parser.add_parser(QUERY_SCHEDULER_COMPONENT_NAME) compression_worker_parser = component_args_parser.add_parser(COMPRESSION_WORKER_COMPONENT_NAME) add_num_workers_argument(compression_worker_parser) - search_worker_parser = component_args_parser.add_parser(SEARCH_WORKER_COMPONENT_NAME) - add_num_workers_argument(search_worker_parser) + query_worker_parser = component_args_parser.add_parser(QUERY_WORKER_COMPONENT_NAME) + add_num_workers_argument(query_worker_parser) reducer_server_parser = component_args_parser.add_parser(REDUCER_COMPONENT_NAME) add_num_workers_argument(reducer_server_parser) component_args_parser.add_parser(WEBUI_COMPONENT_NAME) @@ -874,7 +874,7 @@ def main(argv): CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME, COMPRESSION_SCHEDULER_COMPONENT_NAME, - SEARCH_SCHEDULER_COMPONENT_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, WEBUI_COMPONENT_NAME, ): validate_and_load_db_credentials_file(clp_config, clp_home, True) @@ -883,9 +883,9 @@ def main(argv): CONTROLLER_TARGET_NAME, QUEUE_COMPONENT_NAME, COMPRESSION_SCHEDULER_COMPONENT_NAME, - SEARCH_SCHEDULER_COMPONENT_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, COMPRESSION_WORKER_COMPONENT_NAME, - SEARCH_WORKER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, ): validate_and_load_queue_credentials_file(clp_config, clp_home, True) if target in ( @@ -893,9 +893,9 @@ def main(argv): CONTROLLER_TARGET_NAME, REDIS_COMPONENT_NAME, COMPRESSION_SCHEDULER_COMPONENT_NAME, - SEARCH_SCHEDULER_COMPONENT_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, COMPRESSION_WORKER_COMPONENT_NAME, - SEARCH_WORKER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, ): validate_and_load_redis_credentials_file(clp_config, clp_home, True) @@ -908,7 +908,7 @@ def main(argv): if target in ( COMPRESSION_WORKER_COMPONENT_NAME, REDUCER_COMPONENT_NAME, - SEARCH_WORKER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, ): num_workers = parsed_args.num_workers else: @@ -951,14 +951,14 @@ def main(argv): COMPRESSION_SCHEDULER_COMPONENT_NAME, ): start_compression_scheduler(instance_id, clp_config, container_clp_config, mounts) - if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, SEARCH_SCHEDULER_COMPONENT_NAME): - start_search_scheduler(instance_id, clp_config, container_clp_config, mounts) + if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, QUERY_SCHEDULER_COMPONENT_NAME): + start_query_scheduler(instance_id, clp_config, container_clp_config, mounts) if target in (ALL_TARGET_NAME, COMPRESSION_WORKER_COMPONENT_NAME): start_compression_worker( instance_id, clp_config, container_clp_config, num_workers, mounts ) - if target in (ALL_TARGET_NAME, SEARCH_WORKER_COMPONENT_NAME): - start_search_worker(instance_id, clp_config, container_clp_config, num_workers, mounts) + if target in (ALL_TARGET_NAME, QUERY_WORKER_COMPONENT_NAME): + start_query_worker(instance_id, clp_config, container_clp_config, num_workers, mounts) if target in (ALL_TARGET_NAME, REDUCER_COMPONENT_NAME): start_reducer(instance_id, clp_config, container_clp_config, num_workers, mounts) if target in (ALL_TARGET_NAME, WEBUI_COMPONENT_NAME): diff --git a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py index 307e54236..00e3f7b6b 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py @@ -11,12 +11,12 @@ COMPRESSION_WORKER_COMPONENT_NAME, CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, QUEUE_COMPONENT_NAME, REDIS_COMPONENT_NAME, REDUCER_COMPONENT_NAME, RESULTS_CACHE_COMPONENT_NAME, - SEARCH_SCHEDULER_COMPONENT_NAME, - SEARCH_WORKER_COMPONENT_NAME, WEBUI_COMPONENT_NAME, ) @@ -88,9 +88,9 @@ def main(argv): component_args_parser.add_parser(REDUCER_COMPONENT_NAME) component_args_parser.add_parser(RESULTS_CACHE_COMPONENT_NAME) component_args_parser.add_parser(COMPRESSION_SCHEDULER_COMPONENT_NAME) - component_args_parser.add_parser(SEARCH_SCHEDULER_COMPONENT_NAME) + component_args_parser.add_parser(QUERY_SCHEDULER_COMPONENT_NAME) component_args_parser.add_parser(COMPRESSION_WORKER_COMPONENT_NAME) - component_args_parser.add_parser(SEARCH_WORKER_COMPONENT_NAME) + component_args_parser.add_parser(QUERY_WORKER_COMPONENT_NAME) component_args_parser.add_parser(WEBUI_COMPONENT_NAME) parsed_args = args_parser.parse_args(argv[1:]) @@ -116,8 +116,8 @@ def main(argv): COMPRESSION_SCHEDULER_COMPONENT_NAME, COMPRESSION_WORKER_COMPONENT_NAME, QUEUE_COMPONENT_NAME, - SEARCH_SCHEDULER_COMPONENT_NAME, - SEARCH_WORKER_COMPONENT_NAME, + QUERY_SCHEDULER_COMPONENT_NAME, + QUERY_WORKER_COMPONENT_NAME, ): validate_and_load_queue_credentials_file(clp_config, clp_home, False) except: @@ -146,14 +146,14 @@ def main(argv): container_config_file_path = logs_dir / f"{container_name}.yml" if container_config_file_path.exists(): container_config_file_path.unlink() - if target in (ALL_TARGET_NAME, SEARCH_WORKER_COMPONENT_NAME): - container_name = f"clp-{SEARCH_WORKER_COMPONENT_NAME}-{instance_id}" + if target in (ALL_TARGET_NAME, QUERY_WORKER_COMPONENT_NAME): + container_name = f"clp-{QUERY_WORKER_COMPONENT_NAME}-{instance_id}" stop_running_container(container_name, already_exited_containers, force) if target in (ALL_TARGET_NAME, COMPRESSION_WORKER_COMPONENT_NAME): container_name = f"clp-{COMPRESSION_WORKER_COMPONENT_NAME}-{instance_id}" stop_running_container(container_name, already_exited_containers, force) - if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, SEARCH_SCHEDULER_COMPONENT_NAME): - container_name = f"clp-{SEARCH_SCHEDULER_COMPONENT_NAME}-{instance_id}" + if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, QUERY_SCHEDULER_COMPONENT_NAME): + container_name = f"clp-{QUERY_SCHEDULER_COMPONENT_NAME}-{instance_id}" stop_running_container(container_name, already_exited_containers, force) container_config_file_path = logs_dir / f"{container_name}.yml" diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index 58cc84d63..b3410925e 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -22,17 +22,17 @@ REDUCER_COMPONENT_NAME = "reducer" RESULTS_CACHE_COMPONENT_NAME = "results_cache" COMPRESSION_SCHEDULER_COMPONENT_NAME = "compression_scheduler" -SEARCH_SCHEDULER_COMPONENT_NAME = "search_scheduler" +QUERY_SCHEDULER_COMPONENT_NAME = "query_scheduler" COMPRESSION_WORKER_COMPONENT_NAME = "compression_worker" -SEARCH_WORKER_COMPONENT_NAME = "search_worker" +QUERY_WORKER_COMPONENT_NAME = "query_worker" WEBUI_COMPONENT_NAME = "webui" # Target names ALL_TARGET_NAME = "" CONTROLLER_TARGET_NAME = "controller" -SEARCH_JOBS_TABLE_NAME = "search_jobs" -SEARCH_TASKS_TABLE_NAME = "search_tasks" +QUERY_JOBS_TABLE_NAME = "query_jobs" +QUERY_TASKS_TABLE_NAME = "query_tasks" COMPRESSION_JOBS_TABLE_NAME = "compression_jobs" COMPRESSION_TASKS_TABLE_NAME = "compression_tasks" @@ -163,7 +163,7 @@ def validate_logging_level(cls, field): return field -class SearchScheduler(BaseModel): +class QueryScheduler(BaseModel): host = "localhost" port = 7000 jobs_poll_delay: float = 0.1 # seconds @@ -197,7 +197,7 @@ def validate_logging_level(cls, field): return field -class SearchWorker(BaseModel): +class QueryWorker(BaseModel): logging_level: str = "INFO" @validator("logging_level") @@ -209,7 +209,7 @@ def validate_logging_level(cls, field): class Redis(BaseModel): host: str = "localhost" port: int = 6379 - search_backend_database: int = 0 + query_backend_database: int = 0 compression_backend_database: int = 1 # redis can perform authentication without a username password: typing.Optional[str] @@ -361,9 +361,9 @@ class CLPConfig(BaseModel): reducer: Reducer() = Reducer() results_cache: ResultsCache = ResultsCache() compression_scheduler: CompressionScheduler = CompressionScheduler() - search_scheduler: SearchScheduler = SearchScheduler() + query_scheduler: QueryScheduler = QueryScheduler() compression_worker: CompressionWorker = CompressionWorker() - search_worker: SearchWorker = SearchWorker() + query_worker: QueryWorker = QueryWorker() webui: WebUi = WebUi() credentials_file_path: pathlib.Path = CLP_DEFAULT_CREDENTIALS_FILE_PATH diff --git a/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py b/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py index 2a494c502..32a285c42 100644 --- a/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py +++ b/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py @@ -7,8 +7,8 @@ from job_orchestration.scheduler.constants import ( CompressionJobStatus, CompressionTaskStatus, - SearchJobStatus, - SearchTaskStatus, + QueryJobStatus, + QueryTaskStatus, ) from sql_adapter import SQL_Adapter @@ -16,8 +16,8 @@ COMPRESSION_JOBS_TABLE_NAME, COMPRESSION_TASKS_TABLE_NAME, Database, - SEARCH_JOBS_TABLE_NAME, - SEARCH_TASKS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, + QUERY_TASKS_TABLE_NAME, ) from clp_py_utils.core import read_yaml_config_file @@ -86,23 +86,24 @@ def main(argv): INDEX `job_id` (`job_id`) USING BTREE, INDEX `TASK_STATUS` (`status`) USING BTREE, INDEX `TASK_START_TIME` (`start_time`) USING BTREE, - CONSTRAINT `compression_tasks` FOREIGN KEY (`job_id`) - REFERENCES `compression_jobs` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION + CONSTRAINT `{COMPRESSION_TASKS_TABLE_NAME}` FOREIGN KEY (`job_id`) + REFERENCES `{COMPRESSION_JOBS_TABLE_NAME}` (`id`) + ON UPDATE NO ACTION ON DELETE NO ACTION ) ROW_FORMAT=DYNAMIC """ ) scheduling_db_cursor.execute( f""" - CREATE TABLE IF NOT EXISTS `{SEARCH_JOBS_TABLE_NAME}` ( + CREATE TABLE IF NOT EXISTS `{QUERY_JOBS_TABLE_NAME}` ( `id` INT NOT NULL AUTO_INCREMENT, - `status` INT NOT NULL DEFAULT '{SearchJobStatus.PENDING}', + `status` INT NOT NULL DEFAULT '{QueryJobStatus.PENDING}', `creation_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `num_tasks` INT NOT NULL DEFAULT '0', `num_tasks_completed` INT NOT NULL DEFAULT '0', `start_time` DATETIME(3) NULL DEFAULT NULL, `duration` FLOAT NULL DEFAULT NULL, - `search_config` VARBINARY(60000) NOT NULL, + `job_config` VARBINARY(60000) NOT NULL, PRIMARY KEY (`id`) USING BTREE, INDEX `JOB_STATUS` (`status`) USING BTREE ) ROW_FORMAT=DYNAMIC @@ -111,9 +112,9 @@ def main(argv): scheduling_db_cursor.execute( f""" - CREATE TABLE IF NOT EXISTS `{SEARCH_TASKS_TABLE_NAME}` ( + CREATE TABLE IF NOT EXISTS `{QUERY_TASKS_TABLE_NAME}` ( `id` BIGINT NOT NULL AUTO_INCREMENT, - `status` INT NOT NULL DEFAULT '{SearchTaskStatus.PENDING}', + `status` INT NOT NULL DEFAULT '{QueryTaskStatus.PENDING}', `creation_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `start_time` DATETIME(3) NULL DEFAULT NULL, `duration` FLOAT NULL DEFAULT NULL, @@ -123,8 +124,9 @@ def main(argv): INDEX `job_id` (`job_id`) USING BTREE, INDEX `TASK_STATUS` (`status`) USING BTREE, INDEX `TASK_START_TIME` (`start_time`) USING BTREE, - CONSTRAINT `search_tasks` FOREIGN KEY (`job_id`) - REFERENCES `search_jobs` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION + CONSTRAINT `{QUERY_TASKS_TABLE_NAME}` FOREIGN KEY (`job_id`) + REFERENCES `{QUERY_JOBS_TABLE_NAME}` (`id`) + ON UPDATE NO ACTION ON DELETE NO ACTION ) ROW_FORMAT=DYNAMIC """ ) diff --git a/components/core/src/reducer/CommandLineArguments.cpp b/components/core/src/reducer/CommandLineArguments.cpp index 2429fd9dc..fe9cf4a72 100644 --- a/components/core/src/reducer/CommandLineArguments.cpp +++ b/components/core/src/reducer/CommandLineArguments.cpp @@ -30,12 +30,12 @@ CommandLineArguments::parse_arguments(int argc, char const* argv[]) { "scheduler-host", po::value(&m_scheduler_host) ->default_value(m_scheduler_host), - "Host the search scheduler is running on" + "Host the query scheduler is running on" )( "scheduler-port", po::value(&m_scheduler_port) ->default_value(m_scheduler_port), - "Port the search scheduler is listening on" + "Port the query scheduler is listening on" )( "mongodb-uri", po::value(&m_mongodb_uri) diff --git a/components/core/src/reducer/ServerContext.cpp b/components/core/src/reducer/ServerContext.cpp index 8faa59c55..75b667da4 100644 --- a/components/core/src/reducer/ServerContext.cpp +++ b/components/core/src/reducer/ServerContext.cpp @@ -89,7 +89,7 @@ bool ServerContext::register_with_scheduler( try { boost::asio::connect(m_scheduler_socket, endpoints); } catch (boost::system::system_error& error) { - SPDLOG_ERROR("Failed to connect to search scheduler - {}", error.what()); + SPDLOG_ERROR("Failed to connect to query scheduler - {}", error.what()); return false; } @@ -120,12 +120,12 @@ bool ServerContext::register_with_scheduler( return true; } -bool ServerContext::ack_search_scheduler() { +bool ServerContext::ack_query_scheduler() { boost::system::error_code e; char const scheduler_response = 'y'; boost::asio::write(m_scheduler_socket, boost::asio::buffer(&scheduler_response, 1), e); if (e) { - SPDLOG_ERROR("Failed to notify search scheduler - {}", e.message()); + SPDLOG_ERROR("Failed to notify query scheduler - {}", e.message()); return false; } return true; @@ -253,7 +253,7 @@ bool ServerContext::try_finalize_results() { return false; } - // Notify the search scheduler that the results have been pushed - return ack_search_scheduler(); + // Notify the query scheduler that the results have been pushed + return ack_query_scheduler(); } } // namespace reducer diff --git a/components/core/src/reducer/ServerContext.hpp b/components/core/src/reducer/ServerContext.hpp index dc6fb1c4d..fbc2065ef 100644 --- a/components/core/src/reducer/ServerContext.hpp +++ b/components/core/src/reducer/ServerContext.hpp @@ -79,10 +79,10 @@ class ServerContext { bool register_with_scheduler(boost::asio::ip::tcp::resolver::results_type const& endpoints); /** - * Synchronously sends a generic acknowledgement to the search scheduler. + * Synchronously sends a generic acknowledgement to the query scheduler. * @return Whether the acknowledgement was sent successfully. */ - bool ack_search_scheduler(); + bool ack_query_scheduler(); /** * Increments the number of active receiver tasks which may receive some results. @@ -124,7 +124,7 @@ class ServerContext { /** * If all results have been received then this function tries to publish the pipeline's results - * to the results cache and notify the search scheduler. + * to the results cache and notify the query scheduler. * @return true if not all results have been received yet, or the results were published * successfully. * @return false otherwise. diff --git a/components/core/src/reducer/reducer_server.cpp b/components/core/src/reducer/reducer_server.cpp index 4c7bca348..ab35b7396 100644 --- a/components/core/src/reducer/reducer_server.cpp +++ b/components/core/src/reducer/reducer_server.cpp @@ -212,7 +212,7 @@ void SchedulerUpdateListenerTask::operator()( } // Synchronously notify the scheduler that the reducer is ready - if (false == m_server_ctx->ack_search_scheduler()) { + if (false == m_server_ctx->ack_query_scheduler()) { m_server_ctx->set_status(ServerStatus::RecoverableFailure); m_server_ctx->stop_event_loop(); return; diff --git a/components/job-orchestration/job_orchestration/executor/search/__init__.py b/components/job-orchestration/job_orchestration/executor/query/__init__.py similarity index 100% rename from components/job-orchestration/job_orchestration/executor/search/__init__.py rename to components/job-orchestration/job_orchestration/executor/query/__init__.py diff --git a/components/job-orchestration/job_orchestration/executor/search/celery.py b/components/job-orchestration/job_orchestration/executor/query/celery.py similarity index 85% rename from components/job-orchestration/job_orchestration/executor/search/celery.py rename to components/job-orchestration/job_orchestration/executor/query/celery.py index 81a36d815..7d09e03ea 100644 --- a/components/job-orchestration/job_orchestration/executor/search/celery.py +++ b/components/job-orchestration/job_orchestration/executor/query/celery.py @@ -2,7 +2,7 @@ from . import celeryconfig -app = Celery("search") +app = Celery("query") app.config_from_object(celeryconfig) if "__main__" == __name__: diff --git a/components/job-orchestration/job_orchestration/executor/search/celeryconfig.py b/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py similarity index 83% rename from components/job-orchestration/job_orchestration/executor/search/celeryconfig.py rename to components/job-orchestration/job_orchestration/executor/query/celeryconfig.py index 3dd99e670..4b9949091 100644 --- a/components/job-orchestration/job_orchestration/executor/search/celeryconfig.py +++ b/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py @@ -2,10 +2,10 @@ from job_orchestration.scheduler.constants import QueueName -imports = "job_orchestration.executor.search.fs_search_task" +imports = "job_orchestration.executor.query.fs_search_task" task_routes = { - "job_orchestration.executor.search.fs_search_task.search": QueueName.SEARCH, + "job_orchestration.executor.query.fs_search_task.search": QueueName.QUERY, } task_create_missing_queues = True diff --git a/components/job-orchestration/job_orchestration/executor/search/fs_search_task.py b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py similarity index 91% rename from components/job-orchestration/job_orchestration/executor/search/fs_search_task.py rename to components/job-orchestration/job_orchestration/executor/query/fs_search_task.py index 054b682c2..f51eae407 100644 --- a/components/job-orchestration/job_orchestration/executor/search/fs_search_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py @@ -9,12 +9,12 @@ from celery.app.task import Task from celery.utils.log import get_task_logger -from clp_py_utils.clp_config import Database, SEARCH_TASKS_TABLE_NAME, StorageEngine +from clp_py_utils.clp_config import Database, QUERY_TASKS_TABLE_NAME, StorageEngine from clp_py_utils.clp_logging import set_logging_level from clp_py_utils.sql_adapter import SQL_Adapter -from job_orchestration.executor.search.celery import app +from job_orchestration.executor.query.celery import app from job_orchestration.scheduler.job_config import SearchConfig -from job_orchestration.scheduler.scheduler_data import SearchTaskResult, SearchTaskStatus +from job_orchestration.scheduler.scheduler_data import QueryTaskResult, QueryTaskStatus # Setup logging logger = get_task_logger(__name__) @@ -29,7 +29,7 @@ def update_search_task_metadata( raise ValueError("No key-value pairs provided to update search task metadata") query = f""" - UPDATE {SEARCH_TASKS_TABLE_NAME} + UPDATE {QUERY_TASKS_TABLE_NAME} SET {', '.join([f'{k}="{v}"' for k, v in kv_pairs.items()])} WHERE id = {task_id} """ @@ -137,7 +137,7 @@ def search( sql_adapter = SQL_Adapter(Database.parse_obj(clp_metadata_db_conn_params)) start_time = datetime.datetime.now() - search_status = SearchTaskStatus.RUNNING + search_status = QueryTaskStatus.RUNNING with closing(sql_adapter.create_connection(True)) as db_conn, closing( db_conn.cursor(dictionary=True) ) as db_cursor: @@ -158,15 +158,15 @@ def search( update_search_task_metadata( db_cursor, task_id, - dict(status=SearchTaskStatus.FAILED, duration=0, start_time=start_time), + dict(status=QueryTaskStatus.FAILED, duration=0, start_time=start_time), ) db_conn.commit() clo_log_file.write(error_message) clo_log_file.close() - return SearchTaskResult( + return QueryTaskResult( task_id=task_id, - status=SearchTaskStatus.FAILED, + status=QueryTaskStatus.FAILED, duration=0, error_log_path=clo_log_path, ).dict() @@ -206,10 +206,10 @@ def sigterm_handler(_signo, _stack_frame): search_proc.communicate() return_code = search_proc.returncode if 0 != return_code: - search_status = SearchTaskStatus.FAILED + search_status = QueryTaskStatus.FAILED logger.error(f"Failed search task for job {job_id} - return_code={return_code}") else: - search_status = SearchTaskStatus.SUCCEEDED + search_status = QueryTaskStatus.SUCCEEDED logger.info(f"Search task completed for job {job_id}") # Close log files @@ -224,13 +224,13 @@ def sigterm_handler(_signo, _stack_frame): ) db_conn.commit() - search_task_result = SearchTaskResult( + search_task_result = QueryTaskResult( status=search_status, task_id=task_id, duration=duration, ) - if SearchTaskStatus.FAILED == search_status: + if QueryTaskStatus.FAILED == search_status: search_task_result.error_log_path = clo_log_path return search_task_result.dict() diff --git a/components/job-orchestration/job_orchestration/reducer/reducer.py b/components/job-orchestration/job_orchestration/reducer/reducer.py index cee6692df..7a91ab565 100644 --- a/components/job-orchestration/job_orchestration/reducer/reducer.py +++ b/components/job-orchestration/job_orchestration/reducer/reducer.py @@ -55,8 +55,8 @@ def main(argv: List[str]) -> int: # fmt: off reducer_cmd = [ str(clp_home / "bin" / "reducer-server"), - "--scheduler-host", clp_config.search_scheduler.host, - "--scheduler-port", str(clp_config.search_scheduler.port), + "--scheduler-host", clp_config.query_scheduler.host, + "--scheduler-port", str(clp_config.query_scheduler.port), "--mongodb-uri", clp_config.results_cache.get_uri(), "--upsert-interval", str(parsed_args.upsert_interval), "--reducer-host", clp_config.reducer.host, diff --git a/components/job-orchestration/job_orchestration/scheduler/constants.py b/components/job-orchestration/job_orchestration/scheduler/constants.py index adb130b3f..62f06f0cf 100644 --- a/components/job-orchestration/job_orchestration/scheduler/constants.py +++ b/components/job-orchestration/job_orchestration/scheduler/constants.py @@ -8,7 +8,7 @@ class QueueName: COMPRESSION = "compression" - SEARCH = "search" + QUERY = "query" class CompressionJobStatus(IntEnum): @@ -31,8 +31,8 @@ class CompressionTaskStatus(IntEnum): # When adding new states always add them to the end of this enum -# and make necessary changes in the UI, Search Scheduler, and Reducer -class SearchJobStatus(IntEnum): +# and make necessary changes in the UI, Query Scheduler, and Reducer +class QueryJobStatus(IntEnum): PENDING = 0 RUNNING = auto() SUCCEEDED = auto() @@ -41,8 +41,8 @@ class SearchJobStatus(IntEnum): CANCELLED = auto() @staticmethod - def from_str(label: str) -> SearchJobStatus: - return SearchJobStatus[label.upper()] + def from_str(label: str) -> QueryJobStatus: + return QueryJobStatus[label.upper()] def __str__(self) -> str: return str(self.value) @@ -51,7 +51,7 @@ def to_str(self) -> str: return str(self.name) -class SearchTaskStatus(IntEnum): +class QueryTaskStatus(IntEnum): PENDING = 0 RUNNING = auto() SUCCEEDED = auto() @@ -59,8 +59,8 @@ class SearchTaskStatus(IntEnum): CANCELLED = auto() @staticmethod - def from_str(label: str) -> SearchTaskStatus: - return SearchTaskStatus[label.upper()] + def from_str(label: str) -> QueryTaskStatus: + return QueryTaskStatus[label.upper()] def __str__(self) -> str: return str(self.value) diff --git a/components/job-orchestration/job_orchestration/scheduler/search/__init__.py b/components/job-orchestration/job_orchestration/scheduler/query/__init__.py similarity index 100% rename from components/job-orchestration/job_orchestration/scheduler/search/__init__.py rename to components/job-orchestration/job_orchestration/scheduler/query/__init__.py diff --git a/components/job-orchestration/job_orchestration/scheduler/search/search_scheduler.py b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py similarity index 89% rename from components/job-orchestration/job_orchestration/scheduler/search/search_scheduler.py rename to components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py index b287b3945..d8a045f31 100644 --- a/components/job-orchestration/job_orchestration/scheduler/search/search_scheduler.py +++ b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py @@ -1,5 +1,5 @@ """ -A scheduler for scheduling search jobs in the CLP package. +A scheduler for scheduling query jobs in the CLP package. NOTE: This scheduler currently only has partial handling for failures of the database. Specifically, in the event that the database is unreachable, the scheduler will continue running as if reads from @@ -32,23 +32,23 @@ from clp_py_utils.clp_config import ( CLP_METADATA_TABLE_PREFIX, CLPConfig, - SEARCH_JOBS_TABLE_NAME, - SEARCH_TASKS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, + QUERY_TASKS_TABLE_NAME, ) from clp_py_utils.clp_logging import get_logger, get_logging_formatter, set_logging_level from clp_py_utils.core import read_yaml_config_file from clp_py_utils.decorators import exception_default_value from clp_py_utils.sql_adapter import SQL_Adapter -from job_orchestration.executor.search.fs_search_task import search -from job_orchestration.scheduler.constants import SearchJobStatus, SearchTaskStatus +from job_orchestration.executor.query.fs_search_task import search +from job_orchestration.scheduler.constants import QueryJobStatus, QueryTaskStatus from job_orchestration.scheduler.job_config import SearchConfig -from job_orchestration.scheduler.scheduler_data import InternalJobState, SearchJob, SearchTaskResult -from job_orchestration.scheduler.search.reducer_handler import ( +from job_orchestration.scheduler.query.reducer_handler import ( handle_reducer_connection, ReducerHandlerMessage, ReducerHandlerMessageQueues, ReducerHandlerMessageType, ) +from job_orchestration.scheduler.scheduler_data import InternalJobState, QueryTaskResult, SearchJob from pydantic import ValidationError # Setup logging @@ -101,10 +101,10 @@ def fetch_new_search_jobs(db_conn) -> list: with contextlib.closing(db_conn.cursor(dictionary=True)) as db_cursor: db_cursor.execute( f""" - SELECT {SEARCH_JOBS_TABLE_NAME}.id as job_id, - {SEARCH_JOBS_TABLE_NAME}.search_config - FROM {SEARCH_JOBS_TABLE_NAME} - WHERE {SEARCH_JOBS_TABLE_NAME}.status={SearchJobStatus.PENDING} + SELECT {QUERY_JOBS_TABLE_NAME}.id as job_id, + {QUERY_JOBS_TABLE_NAME}.job_config + FROM {QUERY_JOBS_TABLE_NAME} + WHERE {QUERY_JOBS_TABLE_NAME}.status={QueryJobStatus.PENDING} """ ) return db_cursor.fetchall() @@ -121,9 +121,9 @@ def fetch_cancelling_search_jobs(db_conn) -> list: with contextlib.closing(db_conn.cursor(dictionary=True)) as db_cursor: db_cursor.execute( f""" - SELECT {SEARCH_JOBS_TABLE_NAME}.id as job_id - FROM {SEARCH_JOBS_TABLE_NAME} - WHERE {SEARCH_JOBS_TABLE_NAME}.status={SearchJobStatus.CANCELLING} + SELECT {QUERY_JOBS_TABLE_NAME}.id as job_id + FROM {QUERY_JOBS_TABLE_NAME} + WHERE {QUERY_JOBS_TABLE_NAME}.status={QueryJobStatus.CANCELLING} """ ) return db_cursor.fetchall() @@ -134,8 +134,8 @@ def set_job_or_task_status( db_conn, table_name: str, job_id: str, - status: SearchJobStatus | SearchTaskStatus, - prev_status: Optional[SearchJobStatus | SearchTaskStatus] = None, + status: QueryJobStatus | QueryTaskStatus, + prev_status: Optional[QueryJobStatus | QueryTaskStatus] = None, **kwargs, ) -> bool: """ @@ -152,10 +152,10 @@ def set_job_or_task_status( with the database. """ field_set_expressions = [f"status={status}"] - if SEARCH_JOBS_TABLE_NAME == table_name: + if QUERY_JOBS_TABLE_NAME == table_name: id_col_name = "id" field_set_expressions.extend([f'{k}="{v}"' for k, v in kwargs.items()]) - elif SEARCH_TASKS_TABLE_NAME == table_name: + elif QUERY_TASKS_TABLE_NAME == table_name: id_col_name = "job_id" field_set_expressions.extend([f"{k}={v}" for k, v in kwargs.items()]) else: @@ -193,28 +193,28 @@ async def handle_cancelling_search_jobs(db_conn_pool) -> None: set_job_or_task_status( db_conn, - SEARCH_TASKS_TABLE_NAME, + QUERY_TASKS_TABLE_NAME, job_id, - SearchTaskStatus.CANCELLED, - SearchTaskStatus.PENDING, + QueryTaskStatus.CANCELLED, + QueryTaskStatus.PENDING, duration=0, ) set_job_or_task_status( db_conn, - SEARCH_TASKS_TABLE_NAME, + QUERY_TASKS_TABLE_NAME, job_id, - SearchTaskStatus.CANCELLED, - SearchTaskStatus.RUNNING, + QueryTaskStatus.CANCELLED, + QueryTaskStatus.RUNNING, duration="TIMESTAMPDIFF(MICROSECOND, start_time, NOW())/1000000.0", ) if set_job_or_task_status( db_conn, - SEARCH_JOBS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, job_id, - SearchJobStatus.CANCELLED, - SearchJobStatus.CANCELLING, + QueryJobStatus.CANCELLED, + QueryJobStatus.CANCELLING, duration=(datetime.datetime.now() - job.start_time).total_seconds(), ): logger.info(f"Cancelled job {job_id}.") @@ -228,7 +228,7 @@ def insert_search_tasks_into_db(db_conn, job_id, archive_ids: List[str]) -> List for archive_id in archive_ids: cursor.execute( f""" - INSERT INTO {SEARCH_TASKS_TABLE_NAME} + INSERT INTO {QUERY_TASKS_TABLE_NAME} (job_id, archive_id) VALUES({job_id}, '{archive_id}') """ @@ -382,15 +382,15 @@ def handle_pending_search_jobs( if job_id in active_jobs: continue - search_config = SearchConfig.parse_obj(msgpack.unpackb(job["search_config"])) + search_config = SearchConfig.parse_obj(msgpack.unpackb(job["job_config"])) archives_for_search = get_archives_for_search(db_conn, search_config) if len(archives_for_search) == 0: if set_job_or_task_status( db_conn, - SEARCH_JOBS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, job_id, - SearchJobStatus.SUCCEEDED, - SearchJobStatus.PENDING, + QueryJobStatus.SUCCEEDED, + QueryJobStatus.PENDING, start_time=datetime.datetime.now(), num_tasks=0, duration=0, @@ -445,10 +445,10 @@ def handle_pending_search_jobs( job.start_time = start_time set_job_or_task_status( db_conn, - SEARCH_JOBS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, job_id, - SearchJobStatus.RUNNING, - SearchJobStatus.PENDING, + QueryJobStatus.RUNNING, + QueryJobStatus.PENDING, start_time=start_time, num_tasks=job.num_archives_to_search, ) @@ -509,10 +509,10 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): del active_jobs[job_id] set_job_or_task_status( db_conn, - SEARCH_JOBS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, job_id, - SearchJobStatus.FAILED, - SearchJobStatus.RUNNING, + QueryJobStatus.FAILED, + QueryJobStatus.RUNNING, duration=(datetime.datetime.now() - job.start_time).total_seconds(), ) continue @@ -520,13 +520,13 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): if returned_results is None: continue - new_job_status = SearchJobStatus.RUNNING + new_job_status = QueryJobStatus.RUNNING for task_result_obj in returned_results: - task_result = SearchTaskResult.parse_obj(task_result_obj) + task_result = QueryTaskResult.parse_obj(task_result_obj) task_id = task_result.task_id task_status = task_result.status - if not task_status == SearchTaskStatus.SUCCEEDED: - new_job_status = SearchJobStatus.FAILED + if not task_status == QueryTaskStatus.SUCCEEDED: + new_job_status = QueryJobStatus.FAILED logger.error( f"Search task job-{job_id}-task-{task_id} failed. " f"Check {task_result.error_log_path} for details." @@ -538,11 +538,11 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): f"{task_result.duration} second(s)." ) - if new_job_status != SearchJobStatus.FAILED: + if new_job_status != QueryJobStatus.FAILED: max_num_results = job.search_config.max_num_results # Check if we've searched all archives if len(job.remaining_archives_for_search) == 0: - new_job_status = SearchJobStatus.SUCCEEDED + new_job_status = QueryJobStatus.SUCCEEDED # Check if we've reached max results elif False == is_reducer_job and max_num_results > 0: if found_max_num_latest_results( @@ -551,17 +551,17 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): max_num_results, job.remaining_archives_for_search[0]["end_timestamp"], ): - new_job_status = SearchJobStatus.SUCCEEDED - if new_job_status == SearchJobStatus.RUNNING: + new_job_status = QueryJobStatus.SUCCEEDED + if new_job_status == QueryJobStatus.RUNNING: job.current_sub_job_async_task_result = None job.state = InternalJobState.WAITING_FOR_DISPATCH logger.info(f"Job {job_id} waiting for more archives to search.") set_job_or_task_status( db_conn, - SEARCH_JOBS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, job_id, - SearchJobStatus.RUNNING, - SearchJobStatus.RUNNING, + QueryJobStatus.RUNNING, + QueryJobStatus.RUNNING, num_tasks_completed=job.num_archives_searched, ) continue @@ -575,7 +575,7 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): msg = await job.reducer_handler_msg_queues.get_from_handler() if ReducerHandlerMessageType.FAILURE == msg.msg_type: reducer_failed = True - new_job_status = SearchJobStatus.FAILED + new_job_status = QueryJobStatus.FAILED elif ReducerHandlerMessageType.SUCCESS != msg.msg_type: error_msg = f"Unexpected msg_type: {msg.msg_type.name}" raise NotImplementedError(error_msg) @@ -584,13 +584,13 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): # job is cancelled (status = CANCELLING) while we're in this method. if set_job_or_task_status( db_conn, - SEARCH_JOBS_TABLE_NAME, + QUERY_JOBS_TABLE_NAME, job_id, new_job_status, num_tasks_completed=job.num_archives_searched, duration=(datetime.datetime.now() - job.start_time).total_seconds(), ): - if new_job_status == SearchJobStatus.SUCCEEDED: + if new_job_status == QueryJobStatus.SUCCEEDED: logger.info(f"Completed job {job_id}.") elif reducer_failed: logger.error(f"Completed job {job_id} with failing reducer.") @@ -644,13 +644,13 @@ async def handle_jobs( async def main(argv: List[str]) -> int: global reducer_connection_queue - args_parser = argparse.ArgumentParser(description="Wait for and run search jobs.") + args_parser = argparse.ArgumentParser(description="Wait for and run query jobs.") args_parser.add_argument("--config", "-c", required=True, help="CLP configuration file.") parsed_args = args_parser.parse_args(argv[1:]) # Setup logging to file - log_file = Path(os.getenv("CLP_LOGS_DIR")) / "search_scheduler.log" + log_file = Path(os.getenv("CLP_LOGS_DIR")) / "query_scheduler.log" logging_file_handler = logging.FileHandler(filename=log_file, encoding="utf-8") logging_file_handler.setFormatter(get_logging_formatter()) logger.addHandler(logging_file_handler) @@ -673,14 +673,14 @@ async def main(argv: List[str]) -> int: sql_adapter = SQL_Adapter(clp_config.database) - logger.debug(f"Job polling interval {clp_config.search_scheduler.jobs_poll_delay} seconds.") + logger.debug(f"Job polling interval {clp_config.query_scheduler.jobs_poll_delay} seconds.") try: reducer_handler = await asyncio.start_server( lambda reader, writer: handle_reducer_connection( reader, writer, reducer_connection_queue ), - clp_config.search_scheduler.host, - clp_config.search_scheduler.port, + clp_config.query_scheduler.host, + clp_config.query_scheduler.port, ) db_conn_pool = sql_adapter.create_connection_pool( logger=logger, pool_size=2, disable_localhost_socket_connection=True @@ -697,8 +697,8 @@ async def main(argv: List[str]) -> int: f"Connected to archive database" f" {clp_config.database.host}:{clp_config.database.port}." ) - logger.info("Search scheduler started.") - batch_size = clp_config.search_scheduler.num_archives_to_search_per_sub_job + logger.info("Query scheduler started.") + batch_size = clp_config.query_scheduler.num_archives_to_search_per_sub_job job_handler = asyncio.create_task( handle_jobs( db_conn_pool=db_conn_pool, @@ -706,7 +706,7 @@ async def main(argv: List[str]) -> int: True ), results_cache_uri=clp_config.results_cache.get_uri(), - jobs_poll_delay=clp_config.search_scheduler.jobs_poll_delay, + jobs_poll_delay=clp_config.query_scheduler.jobs_poll_delay, num_archives_to_search_per_sub_job=batch_size, ) ) diff --git a/components/job-orchestration/job_orchestration/scheduler/search/reducer_handler.py b/components/job-orchestration/job_orchestration/scheduler/query/reducer_handler.py similarity index 96% rename from components/job-orchestration/job_orchestration/scheduler/search/reducer_handler.py rename to components/job-orchestration/job_orchestration/scheduler/query/reducer_handler.py index f25d8afce..5d2ae538b 100644 --- a/components/job-orchestration/job_orchestration/scheduler/search/reducer_handler.py +++ b/components/job-orchestration/job_orchestration/scheduler/query/reducer_handler.py @@ -53,7 +53,7 @@ class _ReducerHandlerWaitState(Enum): JOB_CONFIG = enum.auto() JOB_CONFIG_ACK = enum.auto() - SEARCH_WORKERS_DONE = enum.auto() + QUERY_WORKERS_DONE = enum.auto() REDUCER_DONE = enum.auto() @@ -179,8 +179,8 @@ async def handle_reducer_connection( await msg_queues.put_to_listeners(msg) recv_reducer_msg_task = asyncio.create_task(reader.readexactly(1)) - current_wait_state = _ReducerHandlerWaitState.SEARCH_WORKERS_DONE - elif _ReducerHandlerWaitState.SEARCH_WORKERS_DONE == current_wait_state: + current_wait_state = _ReducerHandlerWaitState.QUERY_WORKERS_DONE + elif _ReducerHandlerWaitState.QUERY_WORKERS_DONE == current_wait_state: if recv_reducer_msg_task in done: await _handle_unexpected_msg_from_reducer(current_wait_state, msg_queues) return @@ -195,7 +195,7 @@ async def handle_reducer_connection( ) return - # Tell the reducer the search workers are done + # Tell the reducer the query workers are done await _send_msg_to_reducer(msgpack.packb({"done": True}), writer) recv_listener_msg_task = asyncio.create_task(msg_queues.get_from_listeners()) diff --git a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py index e590de46b..a3aa5f436 100644 --- a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py +++ b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py @@ -3,9 +3,9 @@ from enum import auto, Enum from typing import Any, Dict, List, Optional -from job_orchestration.scheduler.constants import CompressionTaskStatus, SearchTaskStatus +from job_orchestration.scheduler.constants import CompressionTaskStatus, QueryTaskStatus from job_orchestration.scheduler.job_config import SearchConfig -from job_orchestration.scheduler.search.reducer_handler import ReducerHandlerMessageQueues +from job_orchestration.scheduler.query.reducer_handler import ReducerHandlerMessageQueues from pydantic import BaseModel, validator @@ -35,15 +35,18 @@ class InternalJobState(Enum): RUNNING = auto() -class SearchJob(BaseModel): +class QueryJob(BaseModel): id: str - search_config: SearchConfig state: InternalJobState start_time: Optional[datetime.datetime] + current_sub_job_async_task_result: Optional[Any] + + +class SearchJob(QueryJob): + search_config: SearchConfig num_archives_to_search: int num_archives_searched: int remaining_archives_for_search: List[Dict[str, Any]] - current_sub_job_async_task_result: Optional[Any] reducer_acquisition_task: Optional[asyncio.Task] reducer_handler_msg_queues: Optional[ReducerHandlerMessageQueues] @@ -51,8 +54,8 @@ class Config: # To allow asyncio.Task and asyncio.Queue arbitrary_types_allowed = True -class SearchTaskResult(BaseModel): - status: SearchTaskStatus +class QueryTaskResult(BaseModel): + status: QueryTaskStatus task_id: str duration: float error_log_path: Optional[str] diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index a9ffcc924..740146ab9 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -20,7 +20,7 @@ # jobs_poll_delay: 0.1 # seconds # logging_level: "INFO" # -#search_scheduler: +#query_scheduler: # host: "localhost" # port: 7000 # jobs_poll_delay: 0.1 # seconds @@ -34,7 +34,7 @@ #redis: # host: "localhost" # port: 6379 -# search_backend_database: 0 +# query_backend_database: 0 # compression_backend_database: 1 # #reducer: @@ -51,7 +51,7 @@ #compression_worker: # logging_level: "INFO" # -#search_worker: +#query_worker: # logging_level: "INFO" # #webui: diff --git a/components/webui/imports/api/search/constants.js b/components/webui/imports/api/search/constants.js index 0d0be9e94..ec4c13ad6 100644 --- a/components/webui/imports/api/search/constants.js +++ b/components/webui/imports/api/search/constants.js @@ -58,27 +58,27 @@ const isOperationInProgress = (s) => ( ); /* eslint-disable sort-keys */ -let enumSearchJobStatus; +let enumQueryJobStatus; /** - * Enum of job statuses, matching the `SearchJobStatus` class in - * `job_orchestration.search_scheduler.constants`. + * Enum of job statuses, matching the `QueryJobStatus` class in + * `job_orchestration.query_scheduler.constants`. * * @enum {number} */ -const SEARCH_JOB_STATUS = Object.freeze({ - PENDING: (enumSearchJobStatus = 0), - RUNNING: ++enumSearchJobStatus, - SUCCEEDED: ++enumSearchJobStatus, - FAILED: ++enumSearchJobStatus, - CANCELLING: ++enumSearchJobStatus, - CANCELLED: ++enumSearchJobStatus, +const QUERY_JOB_STATUS = Object.freeze({ + PENDING: (enumQueryJobStatus = 0), + RUNNING: ++enumQueryJobStatus, + SUCCEEDED: ++enumQueryJobStatus, + FAILED: ++enumQueryJobStatus, + CANCELLING: ++enumQueryJobStatus, + CANCELLED: ++enumQueryJobStatus, }); /* eslint-enable sort-keys */ -const SEARCH_JOB_STATUS_WAITING_STATES = [ - SEARCH_JOB_STATUS.PENDING, - SEARCH_JOB_STATUS.RUNNING, - SEARCH_JOB_STATUS.CANCELLING, +const QUERY_JOB_STATUS_WAITING_STATES = [ + QUERY_JOB_STATUS.PENDING, + QUERY_JOB_STATUS.RUNNING, + QUERY_JOB_STATUS.CANCELLING, ]; /** @@ -112,8 +112,8 @@ export { isSearchSignalReq, isSearchSignalResp, MONGO_SORT_ORDER, - SEARCH_JOB_STATUS, - SEARCH_JOB_STATUS_WAITING_STATES, + QUERY_JOB_STATUS, + QUERY_JOB_STATUS_WAITING_STATES, SEARCH_MAX_NUM_RESULTS, SEARCH_RESULTS_FIELDS, SEARCH_SIGNAL, diff --git a/components/webui/imports/api/search/server/SearchJobsDbManager.js b/components/webui/imports/api/search/server/QueryJobsDbManager.js similarity index 66% rename from components/webui/imports/api/search/server/SearchJobsDbManager.js rename to components/webui/imports/api/search/server/QueryJobsDbManager.js index df1dc27fa..4d3bed94a 100644 --- a/components/webui/imports/api/search/server/SearchJobsDbManager.js +++ b/components/webui/imports/api/search/server/QueryJobsDbManager.js @@ -3,8 +3,8 @@ import msgpack from "@msgpack/msgpack"; import {sleep} from "/imports/utils/misc"; import { - SEARCH_JOB_STATUS, - SEARCH_JOB_STATUS_WAITING_STATES, + QUERY_JOB_STATUS, + QUERY_JOB_STATUS_WAITING_STATES, } from "../constants"; @@ -14,32 +14,32 @@ import { const JOB_COMPLETION_STATUS_POLL_INTERVAL_MILLIS = 0.5; /** - * Enum of the `search_jobs` table's column names. + * Enum of the `query_jobs` table's column names. * * @enum {string} */ -const SEARCH_JOBS_TABLE_COLUMN_NAMES = Object.freeze({ +const QUERY_JOBS_TABLE_COLUMN_NAMES = Object.freeze({ ID: "id", STATUS: "status", - SEARCH_CONFIG: "search_config", + JOB_CONFIG: "job_config", }); /** - * Class for submitting and monitoring search jobs in the database. + * Class for submitting and monitoring query jobs in the database. */ -class SearchJobsDbManager { +class QueryJobsDbManager { #sqlDbConnPool; - #searchJobsTableName; + #queryJobsTableName; /** * @param {import("mysql2/promise").Pool} sqlDbConnPool * @param {object} tableNames - * @param {string} tableNames.searchJobsTableName + * @param {string} tableNames.queryJobsTableName */ - constructor (sqlDbConnPool, {searchJobsTableName}) { + constructor (sqlDbConnPool, {queryJobsTableName}) { this.#sqlDbConnPool = sqlDbConnPool; - this.#searchJobsTableName = searchJobsTableName; + this.#queryJobsTableName = queryJobsTableName; } /** @@ -51,8 +51,8 @@ class SearchJobsDbManager { */ async submitSearchJob (searchConfig) { const [queryInsertResults] = await this.#sqlDbConnPool.query( - `INSERT INTO ${this.#searchJobsTableName} - (${SEARCH_JOBS_TABLE_COLUMN_NAMES.SEARCH_CONFIG}) + `INSERT INTO ${this.#queryJobsTableName} + (${QUERY_JOBS_TABLE_COLUMN_NAMES.JOB_CONFIG}) VALUES (?)`, [Buffer.from(msgpack.encode(searchConfig))], ); @@ -88,11 +88,11 @@ class SearchJobsDbManager { */ async submitQueryCancellation (jobId) { await this.#sqlDbConnPool.query( - `UPDATE ${this.#searchJobsTableName} - SET ${SEARCH_JOBS_TABLE_COLUMN_NAMES.STATUS} = ${SEARCH_JOB_STATUS.CANCELLING} - WHERE ${SEARCH_JOBS_TABLE_COLUMN_NAMES.ID} = ? - AND ${SEARCH_JOBS_TABLE_COLUMN_NAMES.STATUS} - IN (${SEARCH_JOB_STATUS.PENDING}, ${SEARCH_JOB_STATUS.RUNNING})`, + `UPDATE ${this.#queryJobsTableName} + SET ${QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS} = ${QUERY_JOB_STATUS.CANCELLING} + WHERE ${QUERY_JOBS_TABLE_COLUMN_NAMES.ID} = ? + AND ${QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS} + IN (${QUERY_JOB_STATUS.PENDING}, ${QUERY_JOB_STATUS.RUNNING})`, jobId, ); } @@ -111,9 +111,9 @@ class SearchJobsDbManager { try { const [queryRows] = await this.#sqlDbConnPool.query( ` - SELECT ${SEARCH_JOBS_TABLE_COLUMN_NAMES.STATUS} - FROM ${this.#searchJobsTableName} - WHERE ${SEARCH_JOBS_TABLE_COLUMN_NAMES.ID} = ? + SELECT ${QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS} + FROM ${this.#queryJobsTableName} + WHERE ${QUERY_JOBS_TABLE_COLUMN_NAMES.ID} = ? `, jobId, ); @@ -125,14 +125,14 @@ class SearchJobsDbManager { if (0 === rows.length) { throw new Error(`Job ${jobId} not found in database.`); } - const status = rows[0][SEARCH_JOBS_TABLE_COLUMN_NAMES.STATUS]; + const status = rows[0][QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS]; - if (false === SEARCH_JOB_STATUS_WAITING_STATES.includes(status)) { - if (SEARCH_JOB_STATUS.CANCELLED === status) { + if (false === QUERY_JOB_STATUS_WAITING_STATES.includes(status)) { + if (QUERY_JOB_STATUS.CANCELLED === status) { throw new Error(`Job ${jobId} was cancelled.`); - } else if (SEARCH_JOB_STATUS.SUCCEEDED !== status) { + } else if (QUERY_JOB_STATUS.SUCCEEDED !== status) { throw new Error(`Job ${jobId} exited with unexpected status=${status}: ` + - `${Object.keys(SEARCH_JOB_STATUS)[status]}.`); + `${Object.keys(QUERY_JOB_STATUS)[status]}.`); } break; } @@ -142,4 +142,4 @@ class SearchJobsDbManager { } } -export default SearchJobsDbManager; +export default QueryJobsDbManager; diff --git a/components/webui/imports/api/search/server/methods.js b/components/webui/imports/api/search/server/methods.js index b0b6a5851..695b6b4a6 100644 --- a/components/webui/imports/api/search/server/methods.js +++ b/components/webui/imports/api/search/server/methods.js @@ -9,24 +9,24 @@ import { } from "../constants"; import {ERROR_NAME_COLLECTION_DROPPED} from "../SearchJobCollectionsManager"; import {searchJobCollectionsManager} from "./collections"; -import SearchJobsDbManager from "./SearchJobsDbManager"; +import QueryJobsDbManager from "./QueryJobsDbManager"; /** - * @type {SearchJobsDbManager|null} + * @type {QueryJobsDbManager|null} */ -let searchJobsDbManager = null; +let queryJobsDbManager = null; /** - * Initializes the SearchJobsDbManager. + * Initializes the QueryJobsDbManager. * * @param {import("mysql2/promise").Pool} sqlDbConnPool * @param {object} tableNames - * @param {string} tableNames.searchJobsTableName + * @param {string} tableNames.queryJobsTableName * @throws {Error} on error. */ -const initSearchJobsDbManager = (sqlDbConnPool, {searchJobsTableName}) => { - searchJobsDbManager = new SearchJobsDbManager(sqlDbConnPool, {searchJobsTableName}); +const initQueryJobsDbManager = (sqlDbConnPool, {queryJobsTableName}) => { + queryJobsDbManager = new QueryJobsDbManager(sqlDbConnPool, {queryJobsTableName}); }; /** @@ -67,8 +67,8 @@ const updateSearchSignalWhenJobsFinish = async ({ }) => { let errorMsg; try { - await searchJobsDbManager.awaitJobCompletion(searchJobId); - await searchJobsDbManager.awaitJobCompletion(aggregationJobId); + await queryJobsDbManager.awaitJobCompletion(searchJobId); + await queryJobsDbManager.awaitJobCompletion(aggregationJobId); } catch (e) { errorMsg = e.message; } @@ -169,9 +169,9 @@ Meteor.methods({ let searchJobId; let aggregationJobId; try { - searchJobId = await searchJobsDbManager.submitSearchJob(args); + searchJobId = await queryJobsDbManager.submitSearchJob(args); aggregationJobId = - await searchJobsDbManager.submitAggregationJob(args, timeRangeBucketSizeMillis); + await queryJobsDbManager.submitAggregationJob(args, timeRangeBucketSizeMillis); } catch (e) { const errorMsg = "Unable to submit search/aggregation job to the SQL database."; logger.error(errorMsg, e.toString()); @@ -241,8 +241,8 @@ Meteor.methods({ `aggregationJobId=${aggregationJobId}`); try { - await searchJobsDbManager.submitQueryCancellation(searchJobId); - await searchJobsDbManager.submitQueryCancellation(aggregationJobId); + await queryJobsDbManager.submitQueryCancellation(searchJobId); + await queryJobsDbManager.submitQueryCancellation(aggregationJobId); updateSearchResultsMeta({ jobId: searchJobId, lastSignal: SEARCH_SIGNAL.RESP_QUERYING, @@ -260,4 +260,4 @@ Meteor.methods({ }, }); -export {initSearchJobsDbManager}; +export {initQueryJobsDbManager}; diff --git a/components/webui/imports/utils/DbManager.js b/components/webui/imports/utils/DbManager.js index 81a232343..6607e9c72 100644 --- a/components/webui/imports/utils/DbManager.js +++ b/components/webui/imports/utils/DbManager.js @@ -6,7 +6,7 @@ import { initCompressionDbManager, initStatsDbManager, } from "/imports/api/ingestion/server/publications"; -import {initSearchJobsDbManager} from "/imports/api/search/server/methods"; +import {initQueryJobsDbManager} from "/imports/api/search/server/methods"; import {logger} from "/imports/utils/logger"; @@ -32,7 +32,7 @@ let dbConnPool = null; * @param {string} tableNames.clpArchivesTableName * @param {string} tableNames.clpFilesTableName * @param {string} tableNames.compressionJobsTableName - * @param {string} tableNames.searchJobsTableName + * @param {string} tableNames.queryJobsTableName * @return {Promise} * @throws {Error} on error. */ @@ -46,7 +46,7 @@ const initDbManagers = async ({ clpArchivesTableName, clpFilesTableName, compressionJobsTableName, - searchJobsTableName, + queryJobsTableName, }) => { if (null !== dbConnPool) { throw Error("This method should not be called twice."); @@ -76,8 +76,8 @@ const initDbManagers = async ({ initCompressionDbManager(dbConnPool, { compressionJobsTableName, }); - initSearchJobsDbManager(dbConnPool, { - searchJobsTableName, + initQueryJobsDbManager(dbConnPool, { + queryJobsTableName, }); initStatsDbManager(dbConnPool, { clpArchivesTableName, diff --git a/components/webui/server/main.js b/components/webui/server/main.js index 93992d1d3..2660e16c1 100644 --- a/components/webui/server/main.js +++ b/components/webui/server/main.js @@ -67,7 +67,7 @@ Meteor.startup(async () => { clpArchivesTableName: Meteor.settings.private.SqlDbClpArchivesTableName, clpFilesTableName: Meteor.settings.private.SqlDbClpFilesTableName, compressionJobsTableName: Meteor.settings.private.SqlDbCompressionJobsTableName, - searchJobsTableName: Meteor.settings.private.SqlDbSearchJobsTableName, + queryJobsTableName: Meteor.settings.private.SqlDbQueryJobsTableName, }); }); diff --git a/components/webui/settings.json b/components/webui/settings.json index 7cf574b32..335ae0b51 100644 --- a/components/webui/settings.json +++ b/components/webui/settings.json @@ -7,7 +7,7 @@ "SqlDbClpArchivesTableName": "clp_archives", "SqlDbClpFilesTableName": "clp_files", "SqlDbCompressionJobsTableName": "compression_jobs", - "SqlDbSearchJobsTableName": "search_jobs" + "SqlDbQueryJobsTableName": "query_jobs" }, "public": { "AggregationResultsCollectionName": "aggregation-results", diff --git a/docs/src/user-guide/quick-start-cluster-setup/multi-node.md b/docs/src/user-guide/quick-start-cluster-setup/multi-node.md index aedc6c457..705f2f97a 100644 --- a/docs/src/user-guide/quick-start-cluster-setup/multi-node.md +++ b/docs/src/user-guide/quick-start-cluster-setup/multi-node.md @@ -22,15 +22,15 @@ worker components. The tables below list the components and their functions. :::{table} Controller components :align: left -| Component | Description | -|-----------------------|------------------------------------------------------------------| -| database | Database for archive metadata, compression jobs, and search jobs | -| queue | Task queue for schedulers | -| redis | Task result storage for workers | -| compression_scheduler | Scheduler for compression jobs | -| search_scheduler | Scheduler for search jobs | -| results_cache | Storage for the workers to return search results to the UI | -| webui | Web server for the UI | +| Component | Description | +|-----------------------|-----------------------------------------------------------------| +| database | Database for archive metadata, compression jobs, and query jobs | +| queue | Task queue for schedulers | +| redis | Task result storage for workers | +| compression_scheduler | Scheduler for compression jobs | +| query_scheduler | Scheduler for search/aggregation jobs | +| results_cache | Storage for the workers to return search results to the UI | +| webui | Web server for the UI | ::: :::{table} Worker components @@ -39,12 +39,12 @@ worker components. The tables below list the components and their functions. | Component | Description | |--------------------|--------------------------------------------------------------| | compression_worker | Worker processes for compression jobs | -| search_worker | Worker processes for search/aggregation jobs | +| query_worker | Worker processes for search/aggregation jobs | | reducer | Reducers for performing the final stages of aggregation jobs | ::: :::{note} -Running additional workers increases the parallelism of compression and search jobs. +Running additional workers increases the parallelism of compression and search/aggregation jobs. ::: ## Configuring CLP @@ -92,12 +92,12 @@ but all components in a group must be started before starting a component in the **Group 2 components:** * `compression_scheduler` -* `search_scheduler` +* `query_scheduler` **Group 3 components:** * `compression_worker` -* `search_worker` +* `query_worker` * `reducer` For each component, on the host where you want to run the component, run: From ea99f507e52619bfd1acd106565d42cb5546faff Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Sat, 22 Jun 2024 01:12:27 -0400 Subject: [PATCH 009/114] clo: Add CLI command to extract a compressed file as IR. (#437) --- components/core/src/clp/clo/CMakeLists.txt | 9 + .../core/src/clp/clo/CommandLineArguments.cpp | 618 ++++++++++++------ .../core/src/clp/clo/CommandLineArguments.hpp | 77 ++- components/core/src/clp/clo/OutputHandler.cpp | 23 +- components/core/src/clp/clo/OutputHandler.hpp | 4 +- components/core/src/clp/clo/clo.cpp | 380 ++++++++--- components/core/src/clp/clo/constants.hpp | 25 + .../core/src/clp/clp/FileDecompressor.hpp | 15 +- components/core/src/clp/clp/decompression.cpp | 29 +- components/core/src/clp/clp/utils.cpp | 3 +- components/core/src/clp/clp/utils.hpp | 3 +- .../executor/query/fs_search_task.py | 2 +- 12 files changed, 852 insertions(+), 336 deletions(-) create mode 100644 components/core/src/clp/clo/constants.hpp diff --git a/components/core/src/clp/clo/CMakeLists.txt b/components/core/src/clp/clo/CMakeLists.txt index 306b6049d..1eea2b5bb 100644 --- a/components/core/src/clp/clo/CMakeLists.txt +++ b/components/core/src/clp/clo/CMakeLists.txt @@ -4,6 +4,8 @@ set( ../BufferReader.hpp ../cli_utils.cpp ../cli_utils.hpp + ../clp/FileDecompressor.cpp + ../clp/FileDecompressor.hpp ../database_utils.cpp ../database_utils.hpp ../Defs.h @@ -20,6 +22,10 @@ set( ../ffi/ir_stream/decoding_methods.cpp ../ffi/ir_stream/decoding_methods.hpp ../ffi/ir_stream/decoding_methods.inc + ../ffi/ir_stream/encoding_methods.cpp + ../ffi/ir_stream/encoding_methods.hpp + ../ffi/ir_stream/utils.cpp + ../ffi/ir_stream/utils.hpp ../FileDescriptor.cpp ../FileDescriptor.hpp ../FileReader.cpp @@ -29,6 +35,8 @@ set( ../Grep.cpp ../Grep.hpp ../ir/LogEvent.hpp + ../ir/LogEventSerializer.cpp + ../ir/LogEventSerializer.hpp ../ir/parsing.cpp ../ir/parsing.hpp ../ir/parsing.inc @@ -115,6 +123,7 @@ set( clo.cpp CommandLineArguments.cpp CommandLineArguments.hpp + constants.hpp OutputHandler.cpp OutputHandler.hpp ) diff --git a/components/core/src/clp/clo/CommandLineArguments.cpp b/components/core/src/clp/clo/CommandLineArguments.cpp index 8f7d54a12..fffc3d783 100644 --- a/components/core/src/clp/clo/CommandLineArguments.cpp +++ b/components/core/src/clp/clo/CommandLineArguments.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ using std::endl; using std::exception; using std::invalid_argument; using std::string; +using std::string_view; using std::vector; namespace clp::clo { @@ -56,6 +58,248 @@ CommandLineArguments::parse_arguments(int argc, char const* argv[]) { ); // clang-format on + po::options_description general_positional_options; + char command_input{}; + general_positional_options.add_options()("command", po::value(&command_input))( + "command-args", + po::value>() + ); + po::positional_options_description general_positional_options_description; + general_positional_options_description.add("command", 1); + general_positional_options_description.add("command-args", -1); + + // Aggregate all options + po::options_description all_options; + all_options.add(options_general); + all_options.add(general_positional_options); + + // Parse options + try { + // Parse options specified on the command line + po::parsed_options parsed = po::command_line_parser(argc, argv) + .options(all_options) + .positional(general_positional_options_description) + .allow_unregistered() + .run(); + po::variables_map parsed_command_line_options; + store(parsed, parsed_command_line_options); + + // Handle config-file manually since Boost won't set it until we call notify, and we can't + // call notify until we parse the config file + if (0 != parsed_command_line_options.count("config-file")) { + config_file_path = parsed_command_line_options["config-file"].as(); + } + + // Parse options specified through the config file + // NOTE: Command line arguments will take priority over config file since they are parsed + // first and Boost doesn't replace existing options + std::ifstream config_file(config_file_path); + if (config_file.is_open()) { + // Allow unrecognized options in configuration file since some of them may be + // exclusively for clp or other applications + po::parsed_options parsed_config_file + = po::parse_config_file(config_file, all_options, true); + store(parsed_config_file, parsed_command_line_options); + config_file.close(); + } + + notify(parsed_command_line_options); + + // Handle --version + if (0 != parsed_command_line_options.count("version")) { + cerr << static_cast(cVersion) << endl; + return ParsingResult::InfoCommand; + } + + // Validate command + if (parsed_command_line_options.count("command") == 0) { + // Handle --help + if (0 != parsed_command_line_options.count("help")) { + if (argc > 2) { + SPDLOG_WARN("Ignoring all options besides --help."); + } + + print_basic_usage(); + cerr << "COMMAND is one of:" << endl; + cerr << " " << enum_to_underlying_type(Command::Search) << " - search" << endl; + cerr << " " << enum_to_underlying_type(Command::ExtractIr) << " - extract IR" + << endl; + cerr << endl; + cerr << "Try " << get_program_name() << " " + << enum_to_underlying_type(Command::Search) << " --help OR " + << get_program_name() << " " << enum_to_underlying_type(Command::ExtractIr) + << " --help for command-specific details." << endl; + cerr << endl; + + cerr << "Options can be specified on the command line or through a configuration " + "file." + << endl; + po::options_description visible_options; + visible_options.add(options_general); + cerr << visible_options << endl; + return ParsingResult::InfoCommand; + } + + throw invalid_argument("COMMAND not specified."); + } + switch (command_input) { + case enum_to_underlying_type(Command::Search): + m_command = static_cast(command_input); + return parse_search_arguments( + options_general, + parsed_command_line_options, + parsed.options, + argc + ); + case enum_to_underlying_type(Command::ExtractIr): + m_command = static_cast(command_input); + return parse_ir_extraction_arguments( + options_general, + parsed_command_line_options, + parsed.options, + argc + ); + default: + throw invalid_argument(string("Unknown command '") + command_input + "'"); + } + } catch (exception& e) { + SPDLOG_ERROR("{}", e.what()); + print_basic_usage(); + cerr << "Try " << get_program_name() << " --help for detailed usage instructions" << endl; + return ParsingResult::Failure; + } +} + +auto CommandLineArguments::parse_ir_extraction_arguments( + po::options_description const& options_general, + po::variables_map& parsed_command_line_options, + vector const& options, + int argc +) -> CommandLineArgumentsBase::ParsingResult { + // Define IR extraction options + po::options_description options_ir_extraction("IR Extraction Options"); + // clang-format off + options_ir_extraction + .add_options()( + "temp-output-dir", + po::value(&m_ir_temp_output_dir)->value_name("DIR"), + "Temporary output directory for IR chunks while they're being written" + )( + "target-size", + po::value(&m_ir_target_size)->value_name("SIZE"), + "Target size (B) for each IR chunk before a new chunk is created" + ); + // clang-format on + + // Define visible options + po::options_description visible_options; + visible_options.add(options_general); + visible_options.add(options_ir_extraction); + + // Define hidden positional options (not shown in Boost's program options help message) + po::options_description hidden_positional_options; + // clang-format off + hidden_positional_options.add_options()( + "archive-path", + po::value(&m_archive_path) + )( + "file-split-id", + po::value(&m_file_split_id) + )( + "output-dir", + po::value(&m_ir_output_dir) + )( + "mongodb-uri", + po::value(&m_ir_mongodb_uri) + )( + "mongodb-collection", + po::value(&m_ir_mongodb_collection) + ); + // clang-format on + po::positional_options_description positional_options_description; + positional_options_description.add("archive-path", 1); + positional_options_description.add("file-split-id", 1); + positional_options_description.add("output-dir", 1); + positional_options_description.add("mongodb-uri", 1); + positional_options_description.add("mongodb-collection", 1); + + // Aggregate all options + po::options_description all_options; + all_options.add(options_ir_extraction); + all_options.add(hidden_positional_options); + + // Parse extraction options + auto extraction_options{po::collect_unrecognized(options, po::include_positional)}; + // Erase the command from the beginning + extraction_options.erase(extraction_options.begin()); + po::store( + po::command_line_parser(extraction_options) + .options(all_options) + .positional(positional_options_description) + .run(), + parsed_command_line_options + ); + notify(parsed_command_line_options); + + // Handle --help + if (0 != parsed_command_line_options.count("help")) { + if (argc > 3) { + SPDLOG_WARN("Ignoring all options besides --help."); + } + + print_ir_extraction_basic_usage(); + cerr << "Examples:" << endl; + cerr << R"( # Extract file (split) with ID "8cf8d8f2-bf3f-42a2-90b2-6bc4ed0a36b4" from)" + << endl; + cerr << R"( # ARCHIVE_PATH as IR into OUTPUT_DIR from ARCHIVE_PATH, and send the metadata)" + << endl; + cerr << R"( # to mongodb://127.0.0.1:27017/test result collection)" << endl; + cerr << " " << get_program_name() + << " i ARCHIVE_PATH 8cf8d8f2-bf3f-42a2-90b2-6bc4ed0a36b4 OUTPUT_DIR " + "mongodb://127.0.0.1:27017/test result" + << endl; + cerr << endl; + + cerr << "Options can be specified on the command line or through a configuration " + "file." + << endl; + cerr << visible_options << endl; + return ParsingResult::InfoCommand; + } + + // Validate input arguments + if (m_archive_path.empty()) { + throw invalid_argument("ARCHIVE_PATH not specified or empty."); + } + + if (m_file_split_id.empty()) { + throw invalid_argument("FILE_SPLIT_ID not specified or empty."); + } + + if (m_ir_output_dir.empty()) { + throw invalid_argument("OUTPUT_DIR not specified or empty."); + } + + if (m_ir_mongodb_uri.empty()) { + throw invalid_argument("URI not specified or empty."); + } + + if (m_ir_mongodb_collection.empty()) { + throw invalid_argument("COLLECTION not specified or empty."); + } + + if (m_ir_temp_output_dir.empty()) { + m_ir_temp_output_dir = m_ir_output_dir; + } + return ParsingResult::Success; +} + +auto CommandLineArguments::parse_search_arguments( + po::options_description const& options_general, + po::variables_map& parsed_command_line_options, + vector const& options, + int argc +) -> CommandLineArgumentsBase::ParsingResult { // Define match controls po::options_description options_match_control("Match Controls"); options_match_control.add_options()( @@ -188,242 +432,185 @@ CommandLineArguments::parse_arguments(int argc, char const* argv[]) { // Aggregate all options po::options_description all_options; - all_options.add(options_general); all_options.add(options_match_control); all_options.add(options_aggregation); all_options.add(hidden_positional_options); // Parse options - try { - // Parse options specified on the command line - po::parsed_options parsed = po::command_line_parser(argc, argv) - .options(all_options) - .positional(positional_options_description) - .allow_unregistered() - .run(); - po::variables_map parsed_command_line_options; - store(parsed, parsed_command_line_options); - - // Handle config-file manually since Boost won't set it until we call notify, and we can't - // call notify until we parse the config file - if (parsed_command_line_options.count("config-file")) { - config_file_path = parsed_command_line_options["config-file"].as(); - } - - // Parse options specified through the config file - // NOTE: Command line arguments will take priority over config file since they are parsed - // first and Boost doesn't replace existing options - std::ifstream config_file(config_file_path); - if (config_file.is_open()) { - // Allow unrecognized options in configuration file since some of them may be - // exclusively for clp or other applications - po::parsed_options parsed_config_file - = po::parse_config_file(config_file, all_options, true); - store(parsed_config_file, parsed_command_line_options); - config_file.close(); - } - - notify(parsed_command_line_options); - - constexpr char cNetworkOutputHandlerName[] = "network"; - constexpr char cReducerOutputHandlerName[] = "reducer"; - constexpr char cResultsCacheOutputHandlerName[] = "results-cache"; - - // Handle --help - if (parsed_command_line_options.count("help")) { - if (argc > 2) { - SPDLOG_WARN("Ignoring all options besides --help."); - } - - print_basic_usage(); - cerr << "OUTPUT_HANDLER is one of:" << endl; - cerr << " " << static_cast(cNetworkOutputHandlerName) - << " - Output to a network destination" << endl; - cerr << " " << static_cast(cResultsCacheOutputHandlerName) - << " - Output to the results cache" << endl; - cerr << " " << static_cast(cReducerOutputHandlerName) - << " - Output to the reducer" << endl; - cerr << endl; - - cerr << "Examples:" << endl; - cerr << R"( # Search ARCHIVE_PATH for " ERROR " and send results to )" - "a network destination" - << endl; - cerr << " " << get_program_name() << R"( ARCHIVE_PATH " ERROR ")" - << " " << static_cast(cNetworkOutputHandlerName) - << " --host localhost --port 18000" << endl; - cerr << endl; - - cerr << R"( # Search ARCHIVE_PATH for " ERROR " and output the results )" - "by performing a count aggregation" - << endl; - cerr << " " << get_program_name() << R"( ARCHIVE_PATH " ERROR ")" - << " " << static_cast(cReducerOutputHandlerName) << " --count" - << " --host localhost --port 14009 --job-id 1" << endl; - cerr << endl; - - cerr << R"( # Search ARCHIVE_PATH for " ERROR " and send results to)" - R"( mongodb://127.0.0.1:27017/test "result" collection )" - << endl; - cerr << " " << get_program_name() << R"( ARCHIVE_PATH " ERROR ")" - << " " << static_cast(cResultsCacheOutputHandlerName) - << R"( --uri mongodb://127.0.0.1:27017/test --collection result)" << endl; - cerr << endl; - - cerr << "Options can be specified on the command line or through a configuration file." - << endl; - cerr << visible_options << endl; - return ParsingResult::InfoCommand; - } - - // Handle --version - if (parsed_command_line_options.count("version")) { - cerr << static_cast(cVersion) << endl; - return ParsingResult::InfoCommand; - } - - // Validate archive path was specified - if (m_archive_path.empty()) { - throw invalid_argument("ARCHIVE_PATH not specified or empty."); - } - - // Validate wildcard string - if (m_search_string.empty()) { - throw invalid_argument("Wildcard string not specified or empty."); + auto search_options{po::collect_unrecognized(options, po::include_positional)}; + search_options.erase(search_options.begin()); + auto parsed{po::command_line_parser(search_options) + .options(all_options) + .positional(positional_options_description) + .allow_unregistered() + .run()}; + po::store(parsed, parsed_command_line_options); + + notify(parsed_command_line_options); + + constexpr string_view cNetworkOutputHandlerName{"network"}; + constexpr string_view cReducerOutputHandlerName{"reducer"}; + constexpr string_view cResultsCacheOutputHandlerName{"results-cache"}; + + // Handle --help + if (0 != parsed_command_line_options.count("help")) { + if (argc > 3) { + SPDLOG_WARN("Ignoring all options besides --help."); } - // Validate timestamp range and compute m_search_begin_ts and m_search_end_ts - if (parsed_command_line_options.count("teq")) { - if (parsed_command_line_options.count("tgt") + parsed_command_line_options.count("tge") - + parsed_command_line_options.count("tlt") - + parsed_command_line_options.count("tle") - > 0) - { - throw invalid_argument( - "--teq cannot be specified with any other timestamp filtering option." - ); - } - - m_search_begin_ts = parsed_command_line_options["teq"].as(); - m_search_end_ts = parsed_command_line_options["teq"].as(); - } else { - if (parsed_command_line_options.count("tgt") + parsed_command_line_options.count("tge") - > 1) - { - throw invalid_argument("--tgt cannot be used with --tge."); - } - - // Set m_search_begin_ts - if (parsed_command_line_options.count("tgt")) { - m_search_begin_ts = parsed_command_line_options["tgt"].as() + 1; - } else if (parsed_command_line_options.count("tge")) { - m_search_begin_ts = parsed_command_line_options["tge"].as(); - } + print_search_basic_usage(); + cerr << "OUTPUT_HANDLER is one of:" << endl; + cerr << " " << cNetworkOutputHandlerName << " - Output to a network destination" << endl; + cerr << " " << cResultsCacheOutputHandlerName << " - Output to the results cache" << endl; + cerr << " " << cReducerOutputHandlerName << " - Output to the reducer" << endl; + cerr << endl; + + cerr << "Examples:" << endl; + cerr << R"( # Search ARCHIVE_PATH for " ERROR " and send results to )" + "a network destination" + << endl; + cerr << " " << get_program_name() << R"( ARCHIVE_PATH " ERROR ")" + << " " << cNetworkOutputHandlerName << " --host localhost --port 18000" << endl; + cerr << endl; + + cerr << R"( # Search ARCHIVE_PATH for " ERROR " and output the results )" + "by performing a count aggregation" + << endl; + cerr << " " << get_program_name() << R"( ARCHIVE_PATH " ERROR ")" + << " " << cReducerOutputHandlerName << " --count" + << " --host localhost --port 14009 --job-id 1" << endl; + cerr << endl; + + cerr << R"( # Search ARCHIVE_PATH for " ERROR " and send results to)" + R"( mongodb://127.0.0.1:27017/test "result" collection )" + << endl; + cerr << " " << get_program_name() << R"( ARCHIVE_PATH " ERROR ")" + << " " << cResultsCacheOutputHandlerName + << R"( --uri mongodb://127.0.0.1:27017/test --collection result)" << endl; + cerr << endl; + + cerr << "Options can be specified on the command line or through a configuration file." + << endl; + cerr << visible_options << endl; + return ParsingResult::InfoCommand; + } - if (parsed_command_line_options.count("tlt") + parsed_command_line_options.count("tle") - > 1) - { - throw invalid_argument("--tlt cannot be used with --tle."); - } + // Validate archive path was specified + if (m_archive_path.empty()) { + throw invalid_argument("ARCHIVE_PATH not specified or empty."); + } - // Set m_search_end_ts - if (parsed_command_line_options.count("tlt")) { - m_search_end_ts = parsed_command_line_options["tlt"].as() - 1; - } else if (parsed_command_line_options.count("tle")) { - m_search_end_ts = parsed_command_line_options["tle"].as(); - } + // Validate wildcard string + if (m_search_string.empty()) { + throw invalid_argument("Wildcard string not specified or empty."); + } - if (m_search_begin_ts > m_search_end_ts) { - throw invalid_argument( - "Timestamp range is invalid - begin timestamp is after end timestamp." - ); - } + // Validate timestamp range and compute m_search_begin_ts and m_search_end_ts + if (0 != parsed_command_line_options.count("teq")) { + if (parsed_command_line_options.count("tgt") + parsed_command_line_options.count("tge") + + parsed_command_line_options.count("tlt") + + parsed_command_line_options.count("tle") + > 0) + { + throw invalid_argument( + "--teq cannot be specified with any other timestamp filtering option." + ); } - // Validate file-path - if (parsed_command_line_options.count("file-path") > 0 && m_file_path.empty()) { - throw invalid_argument("file-path cannot be an empty string."); + m_search_begin_ts = parsed_command_line_options["teq"].as(); + m_search_end_ts = parsed_command_line_options["teq"].as(); + } else { + if (parsed_command_line_options.count("tgt") + parsed_command_line_options.count("tge") > 1) + { + throw invalid_argument("--tgt cannot be used with --tge."); } - // Validate count by time bucket size - if (parsed_command_line_options.count("count-by-time") > 0) { - m_do_count_by_time_aggregation = true; - if (m_count_by_time_bucket_size <= 0) { - throw std::invalid_argument("Value for count-by-time must be greater than zero."); - } + // Set m_search_begin_ts + if (0 != parsed_command_line_options.count("tgt")) { + m_search_begin_ts = parsed_command_line_options["tgt"].as() + 1; + } else if (0 != parsed_command_line_options.count("tge")) { + m_search_begin_ts = parsed_command_line_options["tge"].as(); } - // Validate output-handler - if (parsed_command_line_options.count("output-handler") == 0) { - throw invalid_argument("OUTPUT_HANDLER not specified."); - } - if (static_cast(cNetworkOutputHandlerName) == output_handler_name) { - m_output_handler_type = OutputHandlerType::Network; - } else if (static_cast(cReducerOutputHandlerName) == output_handler_name) { - m_output_handler_type = OutputHandlerType::Reducer; - } else if (static_cast(cResultsCacheOutputHandlerName) == output_handler_name) + if (parsed_command_line_options.count("tlt") + parsed_command_line_options.count("tle") > 1) { - m_output_handler_type = OutputHandlerType::ResultsCache; - } else if (output_handler_name.empty()) { - throw invalid_argument("OUTPUT_HANDLER cannot be an empty string."); - } else { - throw invalid_argument("Unknown OUTPUT_HANDLER: " + output_handler_name); + throw invalid_argument("--tlt cannot be used with --tle."); } - switch (m_output_handler_type) { - case OutputHandlerType::Network: - parse_network_dest_output_handler_options( - options_network_output_handler, - parsed.options, - parsed_command_line_options - ); - break; - case OutputHandlerType::Reducer: - parse_reducer_output_handler_options( - options_reducer_output_handler, - parsed.options, - parsed_command_line_options - ); - break; - case OutputHandlerType::ResultsCache: - parse_results_cache_output_handler_options( - options_results_cache_output_handler, - parsed.options, - parsed_command_line_options - ); - break; - default: - throw invalid_argument( - "Unhandled OutputHandlerType=" - + std::to_string(enum_to_underlying_type(m_output_handler_type)) - ); + // Set m_search_end_ts + if (0 != parsed_command_line_options.count("tlt")) { + m_search_end_ts = parsed_command_line_options["tlt"].as() - 1; + } else if (0 != parsed_command_line_options.count("tle")) { + m_search_end_ts = parsed_command_line_options["tle"].as(); } - bool aggregation_was_specified - = m_do_count_by_time_aggregation || m_do_count_results_aggregation; - if (aggregation_was_specified && OutputHandlerType::Reducer != m_output_handler_type) { + if (m_search_begin_ts > m_search_end_ts) { throw invalid_argument( - "Aggregations are only supported with the reducer output handler." + "Timestamp range is invalid - begin timestamp is after end timestamp." ); - } else if ((false == aggregation_was_specified - && OutputHandlerType::Reducer == m_output_handler_type)) - { - throw invalid_argument("The reducer output handler currently only supports count and " - "count-by-time aggregations."); } + } - if (m_do_count_by_time_aggregation && m_do_count_results_aggregation) { - throw std::invalid_argument( - "The --count-by-time and --count options are mutually exclusive." - ); + // Validate file-path + if (parsed_command_line_options.count("file-path") > 0 && m_file_path.empty()) { + throw invalid_argument("file-path cannot be an empty string."); + } + + // Validate count by time bucket size + if (parsed_command_line_options.count("count-by-time") > 0) { + m_do_count_by_time_aggregation = true; + if (m_count_by_time_bucket_size <= 0) { + throw std::invalid_argument("Value for count-by-time must be greater than zero."); } - } catch (exception& e) { - SPDLOG_ERROR("{}", e.what()); - print_basic_usage(); - cerr << "Try " << get_program_name() << " --help for detailed usage instructions" << endl; - return ParsingResult::Failure; } + // Validate output-handler + if (parsed_command_line_options.count("output-handler") == 0) { + throw invalid_argument("OUTPUT_HANDLER not specified."); + } + if (cNetworkOutputHandlerName == output_handler_name) { + m_output_handler_type = OutputHandlerType::Network; + parse_network_dest_output_handler_options( + options_network_output_handler, + parsed.options, + parsed_command_line_options + ); + } else if (cReducerOutputHandlerName == output_handler_name) { + m_output_handler_type = OutputHandlerType::Reducer; + parse_reducer_output_handler_options( + options_reducer_output_handler, + parsed.options, + parsed_command_line_options + ); + } else if (cResultsCacheOutputHandlerName == output_handler_name) { + m_output_handler_type = OutputHandlerType::ResultsCache; + parse_results_cache_output_handler_options( + options_results_cache_output_handler, + parsed.options, + parsed_command_line_options + ); + } else if (output_handler_name.empty()) { + throw invalid_argument("OUTPUT_HANDLER cannot be an empty string."); + } else { + throw invalid_argument("Unknown OUTPUT_HANDLER: " + output_handler_name); + } + + bool const aggregation_was_specified + = m_do_count_by_time_aggregation || m_do_count_results_aggregation; + if (aggregation_was_specified && OutputHandlerType::Reducer != m_output_handler_type) { + throw invalid_argument("Aggregations are only supported with the reducer output handler."); + } + if ((false == aggregation_was_specified && OutputHandlerType::Reducer == m_output_handler_type)) + { + throw invalid_argument("The reducer output handler currently only supports count and " + "count-by-time aggregations."); + } + + if (m_do_count_by_time_aggregation && m_do_count_results_aggregation) { + throw std::invalid_argument( + "The --count-by-time and --count options are mutually exclusive." + ); + } return ParsingResult::Success; } @@ -511,7 +698,18 @@ void CommandLineArguments::parse_results_cache_output_handler_options( } void CommandLineArguments::print_basic_usage() const { - cerr << "Usage: " << get_program_name() << " [OPTIONS]" - << R"( ARCHIVE_PATH "WILDCARD STRING" OUTPUT_HANDLER [OUTPUT_HANDLER_OPTIONS])" << endl; + cerr << "Usage: " << get_program_name() << " [OPTIONS] COMMAND [COMMAND ARGUMENTS]" << endl; +} + +void CommandLineArguments::print_search_basic_usage() const { + cerr << "Usage: " << get_program_name() << " " << enum_to_underlying_type(Command::Search) + << R"( [OPTIONS] ARCHIVE_PATH "WILDCARD STRING" OUTPUT_HANDLER [OUTPUT_HANDLER_OPTIONS])" + << endl; +} + +void CommandLineArguments::print_ir_extraction_basic_usage() const { + cerr << "Usage: " << get_program_name() << " " << enum_to_underlying_type(Command::ExtractIr) + << R"( [OPTIONS] ARCHIVE_PATH FILE_SPLIT_ID OUTPUT_DIR MONGODB_URI MONGODB_COLLECTION)" + << endl; } } // namespace clp::clo diff --git a/components/core/src/clp/clo/CommandLineArguments.hpp b/components/core/src/clp/clo/CommandLineArguments.hpp index 16c88bf26..9e6d311c3 100644 --- a/components/core/src/clp/clo/CommandLineArguments.hpp +++ b/components/core/src/clp/clo/CommandLineArguments.hpp @@ -1,8 +1,10 @@ #ifndef CLP_CLO_COMMANDLINEARGUMENTS_HPP #define CLP_CLO_COMMANDLINEARGUMENTS_HPP +#include #include #include +#include #include #include @@ -18,6 +20,11 @@ namespace clp::clo { class CommandLineArguments : public CommandLineArgumentsBase { public: // Types + enum class Command : char { + Search = 's', + ExtractIr = 'i', + }; + enum class OutputHandlerType : uint8_t { Network = 0, Reducer, @@ -36,8 +43,28 @@ class CommandLineArguments : public CommandLineArgumentsBase { // Methods ParsingResult parse_arguments(int argc, char const* argv[]) override; - std::string const& get_archive_path() const { return m_archive_path; } + [[nodiscard]] auto get_command() const -> Command { return m_command; } + + [[nodiscard]] auto get_archive_path() const -> std::string_view { return m_archive_path; } + + // IR extraction arguments + [[nodiscard]] auto get_file_split_id() const -> std::string const& { return m_file_split_id; } + + [[nodiscard]] size_t get_ir_target_size() const { return m_ir_target_size; } + [[nodiscard]] auto get_ir_output_dir() const -> std::string const& { return m_ir_output_dir; } + + [[nodiscard]] auto get_ir_temp_output_dir() const -> std::string const& { + return m_ir_temp_output_dir; + } + + [[nodiscard]] auto get_ir_mongodb_uri() const -> std::string const& { return m_ir_mongodb_uri; } + + [[nodiscard]] auto get_ir_mongodb_collection() const -> std::string const& { + return m_ir_mongodb_collection; + } + + // Search arguments bool ignore_case() const { return m_ignore_case; } std::string const& get_search_string() const { return m_search_string; } @@ -76,6 +103,40 @@ class CommandLineArguments : public CommandLineArgumentsBase { private: // Methods + /** + * Parses arguments for the search command + * @param options_general + * @param parsed_command_line_options + * @param options + * @param argc + * @return ParsingResult::Success if arguments were parsed without error + * @return ParsingResult::InfoCommand if `--help` was specified + * @throw invalid_argument if invalid arguments are provided + */ + [[nodiscard]] auto parse_search_arguments( + boost::program_options::options_description const& options_general, + boost::program_options::variables_map& parsed_command_line_options, + std::vector const& options, + int argc + ) -> CommandLineArgumentsBase::ParsingResult; + + /** + * Parses arguments for the IR extraction command + * @param options_general + * @param parsed_command_line_options + * @param options + * @param argc + * @return ParsingResult::Success if arguments were parsed without error + * @return ParsingResult::InfoCommand if `--help` was specified + * @throw invalid_argument if invalid arguments are provided + */ + [[nodiscard]] auto parse_ir_extraction_arguments( + boost::program_options::options_description const& options_general, + boost::program_options::variables_map& parsed_command_line_options, + std::vector const& options, + int argc + ) -> CommandLineArgumentsBase::ParsingResult; + /** * Validates output options related to the Network Destination output handler. * @param options_description @@ -116,9 +177,21 @@ class CommandLineArguments : public CommandLineArgumentsBase { ); void print_basic_usage() const override; + void print_search_basic_usage() const; + void print_ir_extraction_basic_usage() const; - // Search variables + Command m_command; std::string m_archive_path; + + // Variables for IR extraction + std::string m_file_split_id; + size_t m_ir_target_size{128ULL * 1024 * 1024}; + std::string m_ir_output_dir; + std::string m_ir_temp_output_dir; + std::string m_ir_mongodb_uri; + std::string m_ir_mongodb_collection; + + // Variables for search bool m_ignore_case; std::string m_search_string; std::string m_file_path; diff --git a/components/core/src/clp/clo/OutputHandler.cpp b/components/core/src/clp/clo/OutputHandler.cpp index 3cc5de4e0..bdf1bb1bd 100644 --- a/components/core/src/clp/clo/OutputHandler.cpp +++ b/components/core/src/clp/clo/OutputHandler.cpp @@ -10,6 +10,7 @@ #include "../../reducer/CountOperator.hpp" #include "../../reducer/network_utils.hpp" #include "../networking/socket_utils.hpp" +#include "constants.hpp" using clp::streaming_archive::reader::Message; using std::string; @@ -99,13 +100,25 @@ ErrorCode ResultsCacheOutputHandler::flush() { try { m_results.emplace_back(std::move(bsoncxx::builder::basic::make_document( bsoncxx::builder::basic::kvp( - "orig_file_path", + cResultsCacheKeys::OrigFileId, + std::move(result.orig_file_id) + ), + bsoncxx::builder::basic::kvp( + cResultsCacheKeys::SearchOutput::OrigFilePath, std::move(result.orig_file_path) ), - bsoncxx::builder::basic::kvp("orig_file_id", std::move(result.orig_file_id)), - bsoncxx::builder::basic::kvp("log_event_ix", result.log_event_ix), - bsoncxx::builder::basic::kvp("timestamp", result.timestamp), - bsoncxx::builder::basic::kvp("message", std::move(result.decompressed_message)) + bsoncxx::builder::basic::kvp( + cResultsCacheKeys::SearchOutput::LogEventIx, + result.log_event_ix + ), + bsoncxx::builder::basic::kvp( + cResultsCacheKeys::SearchOutput::Timestamp, + result.timestamp + ), + bsoncxx::builder::basic::kvp( + cResultsCacheKeys::SearchOutput::Message, + std::move(result.decompressed_message) + ) ))); count++; diff --git a/components/core/src/clp/clo/OutputHandler.hpp b/components/core/src/clp/clo/OutputHandler.hpp index 06c982c09..5f8b71f7d 100644 --- a/components/core/src/clp/clo/OutputHandler.hpp +++ b/components/core/src/clp/clo/OutputHandler.hpp @@ -56,7 +56,7 @@ class OutputHandler { * metadata about the file */ [[nodiscard]] virtual bool can_skip_file( - [[maybe_unused]] clp::streaming_archive::MetadataDB::FileIterator const& it + [[maybe_unused]] ::clp::streaming_archive::MetadataDB::FileIterator const& it ) { return false; } @@ -187,7 +187,7 @@ class ResultsCacheOutputHandler : public OutputHandler { */ ErrorCode flush() override; - [[nodiscard]] bool can_skip_file(clp::streaming_archive::MetadataDB::FileIterator const& it + [[nodiscard]] bool can_skip_file(::clp::streaming_archive::MetadataDB::FileIterator const& it ) override { return is_latest_results_full() && get_smallest_timestamp() > it.get_end_ts(); } diff --git a/components/core/src/clp/clo/clo.cpp b/components/core/src/clp/clo/clo.cpp index f0328dc3f..ce351f160 100644 --- a/components/core/src/clp/clo/clo.cpp +++ b/components/core/src/clp/clo/clo.cpp @@ -1,16 +1,21 @@ +#include #include #include +#include -#include #include #include #include "../../reducer/network_utils.hpp" +#include "../clp/FileDecompressor.hpp" #include "../Defs.h" #include "../Grep.hpp" +#include "../ir/constants.hpp" #include "../Profiler.hpp" #include "../spdlog_with_specializations.hpp" +#include "../Utils.hpp" #include "CommandLineArguments.hpp" +#include "constants.hpp" #include "OutputHandler.hpp" using clp::clo::CommandLineArguments; @@ -19,12 +24,17 @@ using clp::clo::CountOutputHandler; using clp::clo::NetworkOutputHandler; using clp::clo::OutputHandler; using clp::clo::ResultsCacheOutputHandler; +using clp::clp::FileDecompressor; using clp::CommandLineArgumentsBase; +using clp::create_directory; using clp::epochtime_t; using clp::ErrorCode; +using clp::ErrorCode_BadParam_DB_URI; using clp::ErrorCode_errno; +using clp::ErrorCode_FileExists; using clp::ErrorCode_Success; using clp::Grep; +using clp::ir::cIrFileExtension; using clp::load_lexer_from_file; using clp::Query; using clp::streaming_archive::MetadataDB; @@ -35,6 +45,7 @@ using clp::TraceableException; using std::cerr; using std::cout; using std::endl; +using std::runtime_error; using std::string; using std::to_string; using std::unique_ptr; @@ -81,16 +92,275 @@ static void search_files( /** * Searches an archive with the given path * @param command_line_args - * @param archive_path * @param output_handler * @return true on success, false otherwise */ static bool search_archive( CommandLineArguments const& command_line_args, - boost::filesystem::path const& archive_path, std::unique_ptr output_handler ); +namespace { +/** + * Extracts a file split as IR chunks, writing them to the local filesystem and writing their + * metadata to the results cache. + * @param command_line_args + * @return Whether the file split was successfully extracted. + */ +bool extract_ir(CommandLineArguments const& command_line_args); + +/** + * Performs a searches acccording to the given arguments. + * @param command_line_args + * @return Whether the search was successful. + */ +bool search(CommandLineArguments const& command_line_args); + +/** + * @param archive_path + * @return Whether the given path exists and contains an archive metadata file. + */ +bool validate_archive_path(std::filesystem::path const& archive_path); + +bool extract_ir(CommandLineArguments const& command_line_args) { + std::filesystem::path const archive_path{command_line_args.get_archive_path()}; + if (false == validate_archive_path(archive_path)) { + return false; + } + + try { + // Create output directory in case it doesn't exist + std::filesystem::path const output_dir{command_line_args.get_ir_output_dir()}; + if (auto const error_code = create_directory(output_dir.string(), 0700, true); + ErrorCode_Success != error_code) + { + SPDLOG_ERROR("Failed to create {} - {}", output_dir.string(), strerror(errno)); + return false; + } + + Archive archive_reader; + archive_reader.open(archive_path.string()); + archive_reader.refresh_dictionaries(); + + auto const& file_split_id = command_line_args.get_file_split_id(); + auto file_metadata_ix_ptr = archive_reader.get_file_iterator_by_split_id(file_split_id); + if (false == file_metadata_ix_ptr->has_next()) { + SPDLOG_ERROR( + "File split '{}' doesn't exist in archive '{}'", + file_split_id, + archive_path.string() + ); + return false; + } + + mongocxx::client client; + mongocxx::collection collection; + + try { + auto const mongo_uri{mongocxx::uri(command_line_args.get_ir_mongodb_uri())}; + client = mongocxx::client{mongo_uri}; + collection + = client[mongo_uri.database()][command_line_args.get_ir_mongodb_collection()]; + } catch (mongocxx::exception const& e) { + SPDLOG_ERROR("Failed to connect to results cache - {}", e.what()); + return false; + } + + std::vector results; + auto ir_output_handler = [&](std::filesystem::path const& src_ir_path, + string const& orig_file_id, + size_t begin_message_ix, + size_t end_message_ix, + bool is_last_ir_chunk) { + auto dest_ir_file_name = orig_file_id; + dest_ir_file_name += "_" + std::to_string(begin_message_ix); + dest_ir_file_name += "_" + std::to_string(end_message_ix); + dest_ir_file_name += cIrFileExtension; + + auto const dest_ir_path = output_dir / dest_ir_file_name; + try { + std::filesystem::rename(src_ir_path, dest_ir_path); + } catch (std::filesystem::filesystem_error const& e) { + SPDLOG_ERROR( + "Failed to rename '{}' to '{}' - {}", + src_ir_path.string(), + dest_ir_path.string(), + e.what() + ); + return false; + } + results.emplace_back(std::move(bsoncxx::builder::basic::make_document( + bsoncxx::builder::basic::kvp( + clp::clo::cResultsCacheKeys::IrOutput::Path, + dest_ir_path.string() + ), + bsoncxx::builder::basic::kvp( + clp::clo::cResultsCacheKeys::OrigFileId, + orig_file_id + ), + bsoncxx::builder::basic::kvp( + clp::clo::cResultsCacheKeys::IrOutput::BeginMsgIx, + static_cast(begin_message_ix) + ), + bsoncxx::builder::basic::kvp( + clp::clo::cResultsCacheKeys::IrOutput::EndMsgIx, + static_cast(end_message_ix) + ), + bsoncxx::builder::basic::kvp( + clp::clo::cResultsCacheKeys::IrOutput::IsLastIrChunk, + is_last_ir_chunk + ) + ))); + return true; + }; + + FileDecompressor file_decompressor; + if (false + == file_decompressor.decompress_to_ir( + archive_reader, + *file_metadata_ix_ptr, + command_line_args.get_ir_target_size(), + command_line_args.get_ir_temp_output_dir(), + ir_output_handler + )) + { + return false; + } + + // Write the metadata into the results cache + if (false == results.empty()) { + try { + collection.insert_many(results); + } catch (mongocxx::exception const& e) { + SPDLOG_ERROR("Failed to insert results into results cache - {}", e.what()); + return false; + } + results.clear(); + } + + file_metadata_ix_ptr.reset(nullptr); + + archive_reader.close(); + } catch (TraceableException& e) { + auto error_code = e.get_error_code(); + if (ErrorCode_errno == error_code) { + SPDLOG_ERROR( + "IR extraction failed: {}:{} {}, errno={}", + e.get_filename(), + e.get_line_number(), + e.what(), + errno + ); + } else { + SPDLOG_ERROR( + "IR extraction failed: {}:{} {}, error_code={}", + e.get_filename(), + e.get_line_number(), + e.what(), + error_code + ); + } + return false; + } + + return true; +} + +bool search(CommandLineArguments const& command_line_args) { + std::unique_ptr output_handler; + try { + switch (command_line_args.get_output_handler_type()) { + case CommandLineArguments::OutputHandlerType::Network: + output_handler = std::make_unique( + command_line_args.get_network_dest_host(), + command_line_args.get_network_dest_port() + ); + break; + case CommandLineArguments::OutputHandlerType::Reducer: { + auto const reducer_socket_fd = reducer::connect_to_reducer( + command_line_args.get_reducer_host(), + command_line_args.get_reducer_port(), + command_line_args.get_job_id() + ); + if (-1 == reducer_socket_fd) { + SPDLOG_ERROR("Failed to connect to reducer"); + return false; + } + + if (command_line_args.do_count_results_aggregation()) { + output_handler = std::make_unique(reducer_socket_fd); + } else if (command_line_args.do_count_by_time_aggregation()) { + output_handler = std::make_unique( + reducer_socket_fd, + command_line_args.get_count_by_time_bucket_size() + ); + } else { + SPDLOG_ERROR("Unhandled aggregation type."); + return false; + } + + break; + } + case CommandLineArguments::OutputHandlerType::ResultsCache: + output_handler = std::make_unique( + command_line_args.get_mongodb_uri(), + command_line_args.get_mongodb_collection(), + command_line_args.get_batch_size(), + command_line_args.get_max_num_results() + ); + break; + default: + SPDLOG_ERROR("Unhandled OutputHandlerType."); + return false; + } + } catch (clp::TraceableException& e) { + SPDLOG_ERROR("Failed to create output handler - {}", e.what()); + return false; + } + + try { + return search_archive(command_line_args, std::move(output_handler)); + } catch (TraceableException& e) { + auto error_code = e.get_error_code(); + if (ErrorCode_errno == error_code) { + SPDLOG_ERROR( + "Search failed: {}:{} {}, errno={}", + e.get_filename(), + e.get_line_number(), + e.what(), + errno + ); + } else { + SPDLOG_ERROR( + "Search failed: {}:{} {}, error_code={}", + e.get_filename(), + e.get_line_number(), + e.what(), + error_code + ); + } + return false; + } +} + +bool validate_archive_path(std::filesystem::path const& archive_path) { + if (false == std::filesystem::exists(archive_path)) { + SPDLOG_ERROR("Archive '{}' doesn't exist.", archive_path.string()); + return false; + } + auto const archive_metadata_file = archive_path / clp::streaming_archive::cMetadataFileName; + if (false == std::filesystem::exists(archive_metadata_file)) { + SPDLOG_ERROR( + "Archive metadata file '{}' doesn't exist. '{}' may not be an archive.", + archive_metadata_file.string(), + archive_path.string() + ); + return false; + } + return true; +} +} // namespace + static SearchFilesResult search_file( Query& query, Archive& archive, @@ -184,20 +454,10 @@ void search_files( static bool search_archive( CommandLineArguments const& command_line_args, - boost::filesystem::path const& archive_path, std::unique_ptr output_handler ) { - if (false == boost::filesystem::exists(archive_path)) { - SPDLOG_ERROR("Archive '{}' does not exist.", archive_path.c_str()); - return false; - } - auto archive_metadata_file = archive_path / clp::streaming_archive::cMetadataFileName; - if (false == boost::filesystem::exists(archive_metadata_file)) { - SPDLOG_ERROR( - "Archive metadata file '{}' does not exist. '{}' may not be an archive.", - archive_metadata_file.c_str(), - archive_path.c_str() - ); + std::filesystem::path const archive_path{command_line_args.get_archive_path()}; + if (false == validate_archive_path(archive_path)) { return false; } @@ -205,7 +465,7 @@ static bool search_archive( auto schema_file_path = archive_path / clp::streaming_archive::cSchemaFileName; unique_ptr forward_lexer, reverse_lexer; bool use_heuristic = true; - if (boost::filesystem::exists(schema_file_path)) { + if (std::filesystem::exists(schema_file_path)) { use_heuristic = false; // Create forward lexer forward_lexer.reset(new log_surgeon::lexers::ByteLexer()); @@ -302,85 +562,21 @@ int main(int argc, char const* argv[]) { break; } + // mongocxx static init mongocxx::instance mongocxx_instance{}; - std::unique_ptr output_handler; - try { - switch (command_line_args.get_output_handler_type()) { - case CommandLineArguments::OutputHandlerType::Network: - output_handler = std::make_unique( - command_line_args.get_network_dest_host(), - command_line_args.get_network_dest_port() - ); - break; - case CommandLineArguments::OutputHandlerType::Reducer: { - auto reducer_socket_fd = reducer::connect_to_reducer( - command_line_args.get_reducer_host(), - command_line_args.get_reducer_port(), - command_line_args.get_job_id() - ); - if (-1 == reducer_socket_fd) { - SPDLOG_ERROR("Failed to connect to reducer"); - return -1; - } - - if (command_line_args.do_count_results_aggregation()) { - output_handler = std::make_unique(reducer_socket_fd); - } else if (command_line_args.do_count_by_time_aggregation()) { - output_handler = std::make_unique( - reducer_socket_fd, - command_line_args.get_count_by_time_bucket_size() - ); - } else { - SPDLOG_ERROR("Unhandled aggregation type."); - return -1; - } - - break; - } - case CommandLineArguments::OutputHandlerType::ResultsCache: - output_handler = std::make_unique( - command_line_args.get_mongodb_uri(), - command_line_args.get_mongodb_collection(), - command_line_args.get_batch_size(), - command_line_args.get_max_num_results() - ); - break; - default: - SPDLOG_ERROR("Unhandled OutputHandlerType."); - return -1; + auto const& command = command_line_args.get_command(); + if (CommandLineArguments::Command::Search == command) { + if (false == search(command_line_args)) { + return -1; } - } catch (clp::TraceableException& e) { - SPDLOG_ERROR("Failed to create output handler - {}", e.what()); + } else if (CommandLineArguments::Command::ExtractIr == command) { + if (false == extract_ir(command_line_args)) { + return -1; + } + } else { + SPDLOG_ERROR("Command {} not implemented.", clp::enum_to_underlying_type(command)); return -1; } - auto const archive_path = boost::filesystem::path(command_line_args.get_archive_path()); - - int return_value = 0; - try { - if (false == search_archive(command_line_args, archive_path, std::move(output_handler))) { - return_value = -1; - } - } catch (TraceableException& e) { - auto error_code = e.get_error_code(); - if (ErrorCode_errno == error_code) { - SPDLOG_ERROR( - "Search failed: {}:{} {}, errno={}", - e.get_filename(), - e.get_line_number(), - e.what(), - errno - ); - } else { - SPDLOG_ERROR( - "Search failed: {}:{} {}, error_code={}", - e.get_filename(), - e.get_line_number(), - e.what(), - error_code - ); - } - return_value = -1; - } - return return_value; + return 0; } diff --git a/components/core/src/clp/clo/constants.hpp b/components/core/src/clp/clo/constants.hpp new file mode 100644 index 000000000..d2eb32db4 --- /dev/null +++ b/components/core/src/clp/clo/constants.hpp @@ -0,0 +1,25 @@ +#ifndef CLP_CLO_CONSTANTS_HPP +#define CLP_CLO_CONSTANTS_HPP + +// NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays, readability-identifier-naming) +namespace clp::clo::cResultsCacheKeys { +constexpr char OrigFileId[]{"orig_file_id"}; + +namespace IrOutput { +constexpr char Path[]{"path"}; +constexpr char BeginMsgIx[]{"begin_msg_ix"}; +constexpr char EndMsgIx[]{"end_msg_ix"}; +constexpr char IsLastIrChunk[]{"is_last_ir_chunk"}; +} // namespace IrOutput + +namespace SearchOutput { +constexpr char OrigFilePath[]{"orig_file_path"}; +constexpr char LogEventIx[]{"log_event_ix"}; +constexpr char Timestamp[]{"timestamp"}; +constexpr char Message[]{"message"}; +} // namespace SearchOutput +} // namespace clp::clo::cResultsCacheKeys + +// NOLINTEND(cppcoreguidelines-avoid-c-arrays, readability-identifier-naming) + +#endif // CLP_CLO_CONSTANTS_HPP diff --git a/components/core/src/clp/clp/FileDecompressor.hpp b/components/core/src/clp/clp/FileDecompressor.hpp index 6bcf86829..932cab7c5 100644 --- a/components/core/src/clp/clp/FileDecompressor.hpp +++ b/components/core/src/clp/clp/FileDecompressor.hpp @@ -3,10 +3,9 @@ #include #include +#include #include -#include - #include "../FileWriter.hpp" #include "../ir/constants.hpp" #include "../ir/LogEventSerializer.hpp" @@ -39,8 +38,8 @@ class FileDecompressor { * new IR chunk when the current IR chunk exceeds ir_target_size. * * @tparam IrOutputHandler Function to handle the resulting IR chunks. - * Signature: (boost::filesystem::path const& ir_file_path, string const& orig_file_id, - * size_t begin_message_ix, size_t end_message_ix) -> bool; + * Signature: (std::filesystem::path const& ir_file_path, string const& orig_file_id, + * size_t begin_message_ix, size_t end_message_ix, bool is_last_ir_chunk) -> bool; * The function returns whether it succeeded. * @param archive_reader * @param file_metadata_ix @@ -99,7 +98,7 @@ auto FileDecompressor::decompress_to_ir( return false; } - boost::filesystem::path ir_output_path{output_dir}; + std::filesystem::path ir_output_path{output_dir}; auto ir_file_name = m_encoded_file.get_id_as_string(); ir_file_name += ir::cIrFileExtension; ir_output_path /= ir_file_name; @@ -132,7 +131,8 @@ auto FileDecompressor::decompress_to_ir( ir_output_path, file_orig_id, begin_message_ix, - end_message_ix + end_message_ix, + false )) { return false; @@ -162,7 +162,8 @@ auto FileDecompressor::decompress_to_ir( auto const end_message_ix = begin_message_ix + ir_serializer.get_num_log_events(); ir_serializer.close(); - if (false == ir_output_handler(ir_output_path, file_orig_id, begin_message_ix, end_message_ix)) + if (false + == ir_output_handler(ir_output_path, file_orig_id, begin_message_ix, end_message_ix, true)) { return false; } diff --git a/components/core/src/clp/clp/decompression.cpp b/components/core/src/clp/clp/decompression.cpp index 5eb8fc898..6b87f6777 100644 --- a/components/core/src/clp/clp/decompression.cpp +++ b/components/core/src/clp/clp/decompression.cpp @@ -1,10 +1,8 @@ #include "decompression.hpp" +#include #include -#include -#include - #include "../ErrorCode.hpp" #include "../FileWriter.hpp" #include "../GlobalMySQLMetadataDB.hpp" @@ -31,7 +29,7 @@ bool decompress( ErrorCode error_code; // Create output directory in case it doesn't exist - auto output_dir = boost::filesystem::path(command_line_args.get_output_dir()); + auto output_dir = std::filesystem::path(command_line_args.get_output_dir()); error_code = create_directory(output_dir.parent_path().string(), 0700, true); if (ErrorCode_Success != error_code) { SPDLOG_ERROR("Failed to create {} - {}", output_dir.parent_path().c_str(), strerror(errno)); @@ -41,13 +39,13 @@ bool decompress( unordered_set decompressed_files; try { - auto archives_dir = boost::filesystem::path(command_line_args.get_archives_dir()); + auto archives_dir = std::filesystem::path(command_line_args.get_archives_dir()); auto const& global_metadata_db_config = command_line_args.get_metadata_db_config(); auto global_metadata_db = get_global_metadata_db(global_metadata_db_config, archives_dir); streaming_archive::reader::Archive archive_reader; - boost::filesystem::path empty_directory_path; + std::filesystem::path empty_directory_path; FileDecompressor file_decompressor; @@ -65,7 +63,7 @@ bool decompress( archive_ix->get_id(archive_id); auto archive_path = archives_dir / archive_id; - if (false == boost::filesystem::exists(archive_path)) { + if (false == std::filesystem::exists(archive_path)) { SPDLOG_WARN( "Archive {} does not exist in '{}'.", archive_id, @@ -181,11 +179,11 @@ bool decompress( global_metadata_db->close(); string final_path; - boost::system::error_code boost_error_code; + std::error_code std_error_code; for (auto const& temp_path_and_final_path : temp_path_to_final_path) { final_path = temp_path_and_final_path.second; for (size_t i = 1; i < SIZE_MAX; ++i) { - if (boost::filesystem::exists(final_path, boost_error_code)) { + if (std::filesystem::exists(final_path, std_error_code)) { final_path = temp_path_and_final_path.second; final_path += '.'; final_path += std::to_string(i); @@ -238,7 +236,7 @@ bool decompress_to_ir(CommandLineArguments& command_line_args) { ErrorCode error_code{}; // Create output directory in case it doesn't exist - auto output_dir = boost::filesystem::path(command_line_args.get_output_dir()); + std::filesystem::path output_dir{command_line_args.get_output_dir()}; error_code = create_directory(output_dir.parent_path().string(), 0700, true); if (ErrorCode_Success != error_code) { SPDLOG_ERROR("Failed to create {} - {}", output_dir.parent_path().c_str(), strerror(errno)); @@ -246,7 +244,7 @@ bool decompress_to_ir(CommandLineArguments& command_line_args) { } try { - auto archives_dir = boost::filesystem::path(command_line_args.get_archives_dir()); + std::filesystem::path archives_dir{command_line_args.get_archives_dir()}; auto const& global_metadata_db_config = command_line_args.get_metadata_db_config(); auto global_metadata_db = get_global_metadata_db(global_metadata_db_config, archives_dir); @@ -280,10 +278,11 @@ bool decompress_to_ir(CommandLineArguments& command_line_args) { return false; } - auto ir_output_handler = [&](boost::filesystem::path const& src_ir_path, + auto ir_output_handler = [&](std::filesystem::path const& src_ir_path, string const& orig_file_id, size_t begin_message_ix, - size_t end_message_ix) { + size_t end_message_ix, + [[maybe_unused]] bool is_last_ir_chunk) { auto dest_ir_file_name = orig_file_id; dest_ir_file_name += "_" + std::to_string(begin_message_ix); dest_ir_file_name += "_" + std::to_string(end_message_ix); @@ -291,8 +290,8 @@ bool decompress_to_ir(CommandLineArguments& command_line_args) { auto const dest_ir_path = output_dir / dest_ir_file_name; try { - boost::filesystem::rename(src_ir_path, dest_ir_path); - } catch (boost::filesystem::filesystem_error const& e) { + std::filesystem::rename(src_ir_path, dest_ir_path); + } catch (std::filesystem::filesystem_error const& e) { SPDLOG_ERROR( "Failed to rename from {} to {}. Error: {}", src_ir_path.c_str(), diff --git a/components/core/src/clp/clp/utils.cpp b/components/core/src/clp/clp/utils.cpp index 77ee4c344..5ba59e0d7 100644 --- a/components/core/src/clp/clp/utils.cpp +++ b/components/core/src/clp/clp/utils.cpp @@ -1,5 +1,6 @@ #include "utils.hpp" +#include #include #include @@ -207,7 +208,7 @@ bool validate_paths_exist(vector const& paths) { std::unique_ptr get_global_metadata_db( GlobalMetadataDBConfig const& global_metadata_db_config, - boost::filesystem::path const& archives_dir + std::filesystem::path const& archives_dir ) { switch (global_metadata_db_config.get_metadata_db_type()) { case GlobalMetadataDBConfig::MetadataDBType::SQLite: { diff --git a/components/core/src/clp/clp/utils.hpp b/components/core/src/clp/clp/utils.hpp index 4f58e1ee4..41e7a3694 100644 --- a/components/core/src/clp/clp/utils.hpp +++ b/components/core/src/clp/clp/utils.hpp @@ -1,6 +1,7 @@ #ifndef CLP_CLP_UTILS_HPP #define CLP_CLP_UTILS_HPP +#include #include #include @@ -87,7 +88,7 @@ bool validate_paths_exist(std::vector const& paths); */ std::unique_ptr get_global_metadata_db( GlobalMetadataDBConfig const& global_metadata_db_config, - boost::filesystem::path const& archives_dir + std::filesystem::path const& archives_dir ); } // namespace clp::clp diff --git a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py index f51eae407..fc143adfa 100644 --- a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py @@ -46,7 +46,7 @@ def make_command( results_collection: str, ): if StorageEngine.CLP == storage_engine: - command = [str(clp_home / "bin" / "clo"), str(archives_dir / archive_id)] + command = [str(clp_home / "bin" / "clo"), "s", str(archives_dir / archive_id)] if search_config.path_filter is not None: command.append("--file-path") command.append(search_config.path_filter) From 628ba3d99fa60ba4b366020f63b9befad7766c29 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:50:49 -0400 Subject: [PATCH 010/114] ffi: Add WIP Serializer class for the next IR stream format. (#446) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 2 + .../core/src/clp/ffi/ir_stream/Serializer.cpp | 72 +++++++++++ .../core/src/clp/ffi/ir_stream/Serializer.hpp | 96 +++++++++++++++ .../clp/ffi/ir_stream/protocol_constants.hpp | 1 + .../core/tests/test-ir_encoding_methods.cpp | 113 ++++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 components/core/src/clp/ffi/ir_stream/Serializer.cpp create mode 100644 components/core/src/clp/ffi/ir_stream/Serializer.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 99d3c8469..e3b62047a 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -304,6 +304,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/decoding_methods.inc src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp + src/clp/ffi/ir_stream/Serializer.cpp + src/clp/ffi/ir_stream/Serializer.hpp src/clp/ffi/ir_stream/utils.cpp src/clp/ffi/ir_stream/utils.hpp src/clp/ffi/ir_stream/protocol_constants.hpp diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp new file mode 100644 index 000000000..6a7128d9f --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -0,0 +1,72 @@ +#include "Serializer.hpp" + +#include +#include + +#include +#include + +#include "../../ir/types.hpp" +#include "../../time_types.hpp" +#include "../encoding_methods.hpp" +#include "encoding_methods.hpp" +#include "protocol_constants.hpp" +#include "utils.hpp" + +using clp::ir::eight_byte_encoded_variable_t; +using clp::ir::four_byte_encoded_variable_t; + +namespace clp::ffi::ir_stream { +template +auto Serializer::create( +) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { + static_assert( + (std::is_same_v + || std::is_same_v) + ); + + Serializer serializer; + auto& ir_buf{serializer.m_ir_buf}; + constexpr BufferView cMagicNumber{ + static_cast( + std::is_same_v + ? cProtocol::EightByteEncodingMagicNumber + : cProtocol::FourByteEncodingMagicNumber + ), + cProtocol::MagicNumberLength + }; + ir_buf.insert(ir_buf.cend(), cMagicNumber.begin(), cMagicNumber.end()); + + nlohmann::json metadata; + metadata.emplace(cProtocol::Metadata::VersionKey, cProtocol::Metadata::BetaVersionValue); + metadata.emplace(cProtocol::Metadata::VariablesSchemaIdKey, cVariablesSchemaVersion); + metadata.emplace( + cProtocol::Metadata::VariableEncodingMethodsIdKey, + cVariableEncodingMethodsVersion + ); + if (false == serialize_metadata(metadata, ir_buf)) { + return std::errc::protocol_error; + } + + return serializer; +} + +template +auto Serializer::change_utc_offset(UtcOffset utc_offset) -> void { + if (utc_offset != m_curr_utc_offset) { + m_curr_utc_offset = utc_offset; + } + serialize_utc_offset_change(m_curr_utc_offset, m_ir_buf); +} + +// Explicitly declare template specializations so that we can define the template methods in this +// file +template auto Serializer::create( +) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +template auto Serializer::create( +) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +template auto Serializer::change_utc_offset(UtcOffset utc_offset +) -> void; +template auto Serializer::change_utc_offset(UtcOffset utc_offset +) -> void; +} // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp new file mode 100644 index 000000000..4c8d48fc6 --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -0,0 +1,96 @@ +#ifndef CLP_FFI_IR_STREAM_SERIALIZER_HPP +#define CLP_FFI_IR_STREAM_SERIALIZER_HPP + +#include +#include +#include + +#include + +#include "../../time_types.hpp" +#include "../SchemaTree.hpp" + +namespace clp::ffi::ir_stream { +/** + * A work-in-progress class for serializing log events into the kv-pair IR format. + * + * This class: + * - maintains all necessary internal data structures to track serialization state; + * - provides APIs to serialize log events into the IR format; and + * - provides APIs to access the serialized IR bytes. + * + * NOTE: + * - This class is designed only to provide serialization functionalities. Callers are responsible + * for writing the serialized bytes into I/O streams. + * - This class doesn't provide an API to terminate the IR stream. Callers should + * terminate the stream by flushing this class' IR buffer to the I/O stream and then writing + * `clp::ffi::ir_stream::cProtocol::Eof` to the I/O stream. + * @tparam encoded_variable_t Type of encoded variables in the serialized IR stream. + */ +template +class Serializer { +public: + // Types + using Buffer = std::vector; + using BufferView = std::span; + + // Factory functions + /** + * Creates an IR serializer and serializes the stream's preamble. + * @return A result containing the serializer or an error code indicating the failure: + * - std::errc::protocol_error on failure to serialize the preamble. + */ + [[nodiscard]] static auto create( + ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + + // Disable copy constructor/assignment operator + Serializer(Serializer const&) = delete; + auto operator=(Serializer const&) -> Serializer& = delete; + + // Define default move constructor/assignment operator + Serializer(Serializer&&) = default; + auto operator=(Serializer&&) -> Serializer& = default; + + // Destructor + ~Serializer() = default; + + // Methods + /** + * @return A view of the underlying IR buffer which contains the serialized IR bytes. + */ + [[nodiscard]] auto get_ir_buf_view() const -> BufferView { + return {m_ir_buf.data(), m_ir_buf.size()}; + } + + /** + * Clears the underlying IR buffer. + */ + auto clear_ir_buf() -> void { m_ir_buf.clear(); } + + /** + * @return The current UTC offset. + */ + [[nodiscard]] auto get_curr_utc_offset() const -> UtcOffset { return m_curr_utc_offset; } + + /** + * Changes the UTC offset and serializes a UTC offset change packet, if the given UTC offset is + * different than the current UTC offset. + * @param utc_offset + */ + auto change_utc_offset(UtcOffset utc_offset) -> void; + +private: + // Constructors + Serializer() = default; + + UtcOffset m_curr_utc_offset{0}; + Buffer m_ir_buf; + SchemaTree m_schema_tree; + + Buffer m_schema_tree_node_buf; + Buffer m_key_group_buf; + Buffer m_value_group_buf; +}; +} // namespace clp::ffi::ir_stream + +#endif diff --git a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp index d442209de..f9fd7ed78 100644 --- a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp +++ b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp @@ -13,6 +13,7 @@ constexpr int8_t LengthUShort = 0x12; constexpr char VersionKey[] = "VERSION"; constexpr char VersionValue[] = "0.0.2"; +constexpr char BetaVersionValue[] = "0.1.0-beta"; // The following regex can be used to validate a Semantic Versioning string. The source of the // regex can be found here: https://semver.org/ diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index e56ea4e86..167803e58 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -1,14 +1,17 @@ #include #include +#include #include #include #include "../src/clp/BufferReader.hpp" +#include "../src/clp/ErrorCode.hpp" #include "../src/clp/ffi/encoding_methods.hpp" #include "../src/clp/ffi/ir_stream/decoding_methods.hpp" #include "../src/clp/ffi/ir_stream/encoding_methods.hpp" #include "../src/clp/ffi/ir_stream/protocol_constants.hpp" +#include "../src/clp/ffi/ir_stream/Serializer.hpp" #include "../src/clp/ir/LogEventDeserializer.hpp" #include "../src/clp/ir/types.hpp" #include "../src/clp/time_types.hpp" @@ -30,6 +33,7 @@ using clp::ffi::ir_stream::encoded_tag_t; using clp::ffi::ir_stream::get_encoding_type; using clp::ffi::ir_stream::IRErrorCode; using clp::ffi::ir_stream::serialize_utc_offset_change; +using clp::ffi::ir_stream::Serializer; using clp::ffi::ir_stream::validate_protocol_version; using clp::ffi::wildcard_query_matches_any_encoded_var; using clp::ir::eight_byte_encoded_variable_t; @@ -115,6 +119,19 @@ template */ [[nodiscard]] auto get_current_ts() -> epoch_time_ms_t; +/** + * Flushes and clears serialized data from the serializer's underlying IR buffer into the given byte + * buffer. + * @tparam encoded_variable_t + * @param serializer + * @param byte_buf + */ +template +auto flush_and_clear_serializer_buffer( + Serializer& serializer, + std::vector& byte_buf +) -> void; + template [[nodiscard]] auto serialize_log_events( vector const& log_events, @@ -214,6 +231,16 @@ auto create_test_log_events() -> vector { auto get_current_ts() -> epoch_time_ms_t { return duration_cast(system_clock::now().time_since_epoch()).count(); } + +template +auto flush_and_clear_serializer_buffer( + Serializer& serializer, + vector& byte_buf +) -> void { + auto const view{serializer.get_ir_buf_view()}; + byte_buf.insert(byte_buf.cend(), view.begin(), view.end()); + serializer.clear_ir_buf(); +} } // namespace /** @@ -858,3 +885,89 @@ TEMPLATE_TEST_CASE( REQUIRE(result.has_error()); REQUIRE(std::errc::no_message_available == result.error()); } + +TEMPLATE_TEST_CASE( + "ffi_ir_stream_Serializer_creation", + "[clp][ffi][ir_stream][Serializer]", + four_byte_encoded_variable_t, + eight_byte_encoded_variable_t +) { + // This is a unit test for the kv-pair IR serializer. Currently, we haven't yet implemented a + // deserializer, so we can only test whether the preamble packet is serialized correctly. + vector ir_buf; + + auto result{Serializer::create()}; + REQUIRE((false == result.has_error())); + + auto& serializer{result.value()}; + flush_and_clear_serializer_buffer(serializer, ir_buf); + REQUIRE(serializer.get_ir_buf_view().empty()); + + constexpr UtcOffset cBeijingUtcOffset{8 * 60 * 60 * 1000}; + serializer.change_utc_offset(cBeijingUtcOffset); + flush_and_clear_serializer_buffer(serializer, ir_buf); + REQUIRE(serializer.get_ir_buf_view().empty()); + + ir_buf.push_back(clp::ffi::ir_stream::cProtocol::Eof); + + BufferReader buffer_reader{size_checked_pointer_cast(ir_buf.data()), ir_buf.size()}; + + bool is_four_byte_encoding{}; + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == get_encoding_type(buffer_reader, is_four_byte_encoding)) + ); + if constexpr (std::is_same_v) { + REQUIRE(is_four_byte_encoding); + } else { + REQUIRE((false == is_four_byte_encoding)); + } + + encoded_tag_t metadata_type{}; + vector metadata_bytes; + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == deserialize_preamble(buffer_reader, metadata_type, metadata_bytes)) + ); + REQUIRE((clp::ffi::ir_stream::cProtocol::Metadata::EncodingJson == metadata_type)); + string_view const metadata_view{ + size_checked_pointer_cast(metadata_bytes.data()), + metadata_bytes.size() + }; + nlohmann::json const metadata = nlohmann::json::parse(metadata_view); + + nlohmann::json expected_metadata; + expected_metadata.emplace( + clp::ffi::ir_stream::cProtocol::Metadata::VersionKey, + clp::ffi::ir_stream::cProtocol::Metadata::BetaVersionValue + ); + expected_metadata.emplace( + clp::ffi::ir_stream::cProtocol::Metadata::VariablesSchemaIdKey, + clp::ffi::cVariablesSchemaVersion + ); + expected_metadata.emplace( + clp::ffi::ir_stream::cProtocol::Metadata::VariableEncodingMethodsIdKey, + clp::ffi::cVariableEncodingMethodsVersion + ); + REQUIRE((expected_metadata == metadata)); + + encoded_tag_t encoded_tag{}; + REQUIRE((IRErrorCode::IRErrorCode_Success == deserialize_tag(buffer_reader, encoded_tag))); + REQUIRE((clp::ffi::ir_stream::cProtocol::Payload::UtcOffsetChange == encoded_tag)); + UtcOffset utc_offset_change{0}; + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == deserialize_utc_offset_change(buffer_reader, utc_offset_change)) + ); + REQUIRE((cBeijingUtcOffset == utc_offset_change)); + + REQUIRE((IRErrorCode::IRErrorCode_Success == deserialize_tag(buffer_reader, encoded_tag))); + REQUIRE((clp::ffi::ir_stream::cProtocol::Eof == encoded_tag)); + + char eof{}; + size_t num_bytes_read{}; + REQUIRE( + (clp::ErrorCode_EndOfFile == buffer_reader.try_read(&eof, 1, num_bytes_read) + && 0 == num_bytes_read) + ); +} From a40a661bf3a11186f5317f0d85c77a7b6408fb26 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:35:49 -0400 Subject: [PATCH 011/114] Taskfile: Replace utility tasks with ones from `yscope-dev-utils`. (#456) --- .gitmodules | 3 ++ Taskfile.yml | 116 +++++++---------------------------------- docs/tasks.yml | 14 ++--- lint-tasks.yml | 10 ++-- tools/yscope-dev-utils | 1 + 5 files changed, 35 insertions(+), 109 deletions(-) create mode 160000 tools/yscope-dev-utils diff --git a/.gitmodules b/.gitmodules index 614f0871e..f433a706e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,3 +23,6 @@ [submodule "components/core/submodules/abseil-cpp"] path = components/core/submodules/abseil-cpp url = https://github.com/abseil/abseil-cpp.git +[submodule "tools/yscope-dev-utils"] + path = tools/yscope-dev-utils + url = https://github.com/y-scope/yscope-dev-utils.git diff --git a/Taskfile.yml b/Taskfile.yml index 256898d55..edce5c074 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -3,6 +3,7 @@ version: "3" includes: docs: "docs/tasks.yml" lint: "lint-tasks.yml" + utils: "tools/yscope-dev-utils/taskfiles/utils.yml" vars: # Paths @@ -60,7 +61,7 @@ tasks: - "init" - "job-orchestration" - "package-venv" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -97,7 +98,7 @@ tasks: cd "{{.OUTPUT_DIR}}/var/www/programs/server" PATH="{{.G_WEBUI_NODEJS_BIN_DIR}}":$PATH npm install # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -163,7 +164,7 @@ tasks: deps: - "init" - "meteor" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -187,7 +188,7 @@ tasks: # Remove temp files generated by `meteor build` before checksum - "find node_modules -type f -name '.meteor-portable-2.json' -exec rm {} +" # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -223,14 +224,14 @@ tasks: OUTPUT_DIR: "submodules" deps: - "init" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - "tools/scripts/deps-download/download-all.sh" # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -251,7 +252,7 @@ tasks: TAR_PATH: "{{.OUTPUT_TMP_DIR}}/{{.TAR_NAME}}" deps: - "init" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -266,7 +267,7 @@ tasks: - "mv '{{.EXTRACTED_DIR}}' '{{.OUTPUT_DIR}}'" - "rm -rf '{{.OUTPUT_TMP_DIR}}'" # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -337,12 +338,12 @@ tasks: # `/parents/A` -> `/parents/B` rather than `/parents/A` -> `/parents/B/A` - "rsync --archive '{{.G_PACKAGE_BUILD_DIR}}/' '{{.OUTPUT_DIR}}'" # Set the storage engine for the package - - task: "replace-text" + - task: "utils:replace-text" vars: FILE_PATH: "{{.OUTPUT_DIR}}/lib/python3/site-packages/clp_py_utils/clp_config.py" SED_EXP: >- s/([[:space:]]*storage_engine: str = ")[^"]+"/\1{{.STORAGE_ENGINE}}"/ - - task: "replace-text" + - task: "utils:replace-text" vars: FILE_PATH: "{{.OUTPUT_DIR}}/etc/clp-config.yml" SED_EXP: >- @@ -364,18 +365,18 @@ tasks: OUTPUT_DIR: "{{.G_PACKAGE_VENV_DIR}}" deps: - "init" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - - task: "create-venv" + - task: "utils:create-venv" vars: LABEL: "package" OUTPUT_DIR: "{{.OUTPUT_DIR}}" REQUIREMENTS_FILE: "requirements.txt" # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -427,7 +428,7 @@ tasks: deps: - "init" - "meteor" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -435,7 +436,7 @@ tasks: - "rm -rf '{{.OUTPUT_DIR}}'" - "PATH='{{.G_METEOR_BUILD_DIR}}':$PATH meteor npm install --production" # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -456,18 +457,18 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.COMPONENT}}-venv.md5" deps: - "init" - - task: "validate-checksum" + - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - - task: "create-venv" + - task: "utils:create-venv" vars: LABEL: "{{.COMPONENT}}" OUTPUT_DIR: "{{.OUTPUT_DIR}}" REQUIREMENTS_FILE: "{{.ROOT_DIR}}/requirements.txt" # This command must be last - - task: "compute-checksum" + - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -487,87 +488,8 @@ tasks: cmds: - "rm -rf dist" - create-venv: - internal: true - requires: - vars: ["LABEL", "OUTPUT_DIR", "REQUIREMENTS_FILE"] - label: "create-venv-{{.LABEL}}" - cmds: - - "rm -rf '{{.OUTPUT_DIR}}'" - - "python3 -m venv '{{.OUTPUT_DIR}}'" - # Remove calls to `hash` from the venv activation script since Task uses `gosh` rather than - # `bash`. - # NOTE: Older versions of Python's venv would only call `hash` if they detected the running - # shell was one that had the command, but that's not the case in newer versions. - - task: "replace-text" - vars: - FILE_PATH: "{{.OUTPUT_DIR}}/bin/activate" - SED_EXP: >- - s/^([[:space:]]*)hash[[:space:]]+.*/\1true/g - - |- - . "{{.OUTPUT_DIR}}/bin/activate" - pip3 install --upgrade pip - pip3 install --upgrade -r "{{.REQUIREMENTS_FILE}}" - init: internal: true run: "once" silent: true cmd: "mkdir -p '{{.G_BUILD_DIR}}'" - - compute-checksum: - desc: "Tries to compute a checksum for the given directory and output it to a file." - internal: true - # Ignore errors so that dependent tasks don't fail - ignore_error: true - silent: true - requires: - vars: ["DATA_DIR", "OUTPUT_FILE"] - cmds: - - >- - tar cf - - --directory "{{.DATA_DIR}}" - --group=0 - --mtime='UTC 1970-01-01' - --numeric-owner - --owner=0 - --sort=name - {{.CHECKSUM_TAR_BASE_ARGS}} . 2> /dev/null - | md5sum > {{.OUTPUT_FILE}} - - validate-checksum: - desc: "Validates the checksum of the given directory matches the checksum in the given file, or - deletes the checksum file otherwise." - internal: true - silent: true - requires: - vars: ["CHECKSUM_FILE", "DATA_DIR"] - vars: - TMP_CHECKSUM_FILE: "{{.CHECKSUM_FILE}}.tmp" - cmds: - - task: "compute-checksum" - vars: - DATA_DIR: "{{.DATA_DIR}}" - OUTPUT_FILE: "{{.TMP_CHECKSUM_FILE}}" - - defer: "rm -f '{{.TMP_CHECKSUM_FILE}}'" - # Check that the directory exists and the checksum matches; otherwise delete the checksum file - - >- - ( - test -d "{{.DATA_DIR}}" - && diff -q '{{.TMP_CHECKSUM_FILE}}' '{{.CHECKSUM_FILE}}' 2> /dev/null - ) || rm -f '{{.CHECKSUM_FILE}}' - - replace-text: - desc: "Task to replace some text in a file using sed." - internal: true - requires: - vars: ["FILE_PATH", "SED_EXP"] - cmds: - - |- - # NOTE: - # 1. We can't use `sed -i` since `-i` has different syntax on Linux and macOS - # 2. We can't use `--regexp` instead of `-E` since `--regexp` is not supported on macOS - src="{{.FILE_PATH}}" - dst="{{.FILE_PATH}}.tmp" - sed -E '{{.SED_EXP}}' "${src}" > "${dst}" - mv "${dst}" "${src}" diff --git a/docs/tasks.yml b/docs/tasks.yml index 05ec8aeef..44f5709c5 100644 --- a/docs/tasks.yml +++ b/docs/tasks.yml @@ -25,7 +25,7 @@ tasks: dir: "{{.TASKFILE_DIR}}" deps: - ":init" - - task: ":validate-checksum" + - task: ":utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -43,7 +43,7 @@ tasks: --builder html \ src "{{.OUTPUT_DIR}}" # This command must be last - - task: ":compute-checksum" + - task: ":utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -63,18 +63,18 @@ tasks: REQUIREMENTS_FILE: "docs/requirements.txt" deps: - ":init" - - task: ":validate-checksum" + - task: ":utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - - task: ":create-venv" + - task: ":utils:create-venv" vars: LABEL: "docs" OUTPUT_DIR: "{{.OUTPUT_DIR}}" REQUIREMENTS_FILE: "{{.REQUIREMENTS_FILE}}" # This command must be last - - task: ":compute-checksum" + - task: ":utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -91,7 +91,7 @@ tasks: OUTPUT_DIR: "{{.G_NODE_DEPS_DIR}}" deps: - ":init" - - task: ":validate-checksum" + - task: ":utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -99,7 +99,7 @@ tasks: - "rm -rf '{{.OUTPUT_DIR}}'" - "npm --prefix '{{.OUTPUT_DIR}}' install http-server" # This command must be last - - task: ":compute-checksum" + - task: ":utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" diff --git a/lint-tasks.yml b/lint-tasks.yml index ba5c30fbf..996b49734 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -166,7 +166,7 @@ tasks: deps: - ":init" - ":webui-node-modules" - - task: ":validate-checksum" + - task: ":utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" @@ -180,7 +180,7 @@ tasks: - "rm -rf '{{.OUTPUT_DIR}}'" - "PATH='{{.G_LINTER_NODEJS_BIN_DIR}}':$PATH npm update" # This command must be last - - task: ":compute-checksum" + - task: ":utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" @@ -199,18 +199,18 @@ tasks: OUTPUT_DIR: "{{.G_LINT_VENV_DIR}}" deps: - ":init" - - task: ":validate-checksum" + - task: ":utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - - task: ":create-venv" + - task: ":utils:create-venv" vars: LABEL: "lint" OUTPUT_DIR: "{{.OUTPUT_DIR}}" REQUIREMENTS_FILE: "lint-requirements.txt" # This command must be last - - task: ":compute-checksum" + - task: ":utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" diff --git a/tools/yscope-dev-utils b/tools/yscope-dev-utils new file mode 160000 index 000000000..ff1611e6f --- /dev/null +++ b/tools/yscope-dev-utils @@ -0,0 +1 @@ +Subproject commit ff1611e6f9b116da27dc7f8f71797829c22d0b1a From 94509a8384351d726bd7a4f46d140b89d3f3310b Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Mon, 24 Jun 2024 18:29:35 -0400 Subject: [PATCH 012/114] package: Add support for different query job types: (#452) - Add abstract classes for QueryJobType and QueryJobConfig. - Submit and track job type in the search jobs table. - Guard search-job specific handling in the scheduler. --- .../scripts/native/search.py | 10 +- .../initialize-orchestration-db.py | 1 + .../executor/query/fs_search_task.py | 12 +- .../job_orchestration/scheduler/constants.py | 10 + .../job_orchestration/scheduler/job_config.py | 5 +- .../scheduler/query/query_scheduler.py | 338 ++++++++++-------- .../scheduler/scheduler_data.py | 25 +- .../webui/imports/api/search/constants.js | 14 + .../api/search/server/QueryJobsDbManager.js | 10 +- 9 files changed, 253 insertions(+), 172 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/search.py b/components/clp-package-utils/clp_package_utils/scripts/native/search.py index aa261d904..9041b0006 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/search.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/search.py @@ -15,8 +15,8 @@ import pymongo from clp_py_utils.clp_config import Database, QUERY_JOBS_TABLE_NAME, ResultsCache from clp_py_utils.sql_adapter import SQL_Adapter -from job_orchestration.scheduler.constants import QueryJobStatus -from job_orchestration.scheduler.job_config import AggregationConfig, SearchConfig +from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType +from job_orchestration.scheduler.job_config import AggregationConfig, SearchJobConfig from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, @@ -83,7 +83,7 @@ def create_and_monitor_job_in_db( do_count_aggregation: bool | None, count_by_time_bucket_size: int | None, ): - search_config = SearchConfig( + search_config = SearchJobConfig( query_string=wildcard_query, begin_timestamp=begin_timestamp, end_timestamp=end_timestamp, @@ -111,8 +111,8 @@ def create_and_monitor_job_in_db( ) as db_cursor: # Create job db_cursor.execute( - f"INSERT INTO `{QUERY_JOBS_TABLE_NAME}` (`job_config`) VALUES (%s)", - (msgpack.packb(search_config.dict()),), + f"INSERT INTO `{QUERY_JOBS_TABLE_NAME}` (`job_config`, `type`) VALUES (%s, %s)", + (msgpack.packb(search_config.dict()), QueryJobType.SEARCH_OR_AGGREGATION), ) db_conn.commit() job_id = db_cursor.lastrowid diff --git a/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py b/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py index 32a285c42..1ed727367 100644 --- a/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py +++ b/components/clp-py-utils/clp_py_utils/initialize-orchestration-db.py @@ -97,6 +97,7 @@ def main(argv): f""" CREATE TABLE IF NOT EXISTS `{QUERY_JOBS_TABLE_NAME}` ( `id` INT NOT NULL AUTO_INCREMENT, + `type` INT NOT NULL, `status` INT NOT NULL DEFAULT '{QueryJobStatus.PENDING}', `creation_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `num_tasks` INT NOT NULL DEFAULT '0', diff --git a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py index fc143adfa..81ff757a2 100644 --- a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py @@ -13,7 +13,7 @@ from clp_py_utils.clp_logging import set_logging_level from clp_py_utils.sql_adapter import SQL_Adapter from job_orchestration.executor.query.celery import app -from job_orchestration.scheduler.job_config import SearchConfig +from job_orchestration.scheduler.job_config import SearchJobConfig from job_orchestration.scheduler.scheduler_data import QueryTaskResult, QueryTaskStatus # Setup logging @@ -41,7 +41,7 @@ def make_command( clp_home: Path, archives_dir: Path, archive_id: str, - search_config: SearchConfig, + search_config: SearchJobConfig, results_cache_uri: str, results_collection: str, ): @@ -113,7 +113,7 @@ def search( self: Task, job_id: str, task_id: int, - search_config_obj: dict, + job_config_obj: dict, archive_id: str, clp_metadata_db_conn_params: dict, results_cache_uri: str, @@ -133,7 +133,7 @@ def search( logger.info(f"Started task for job {job_id}") - search_config = SearchConfig.parse_obj(search_config_obj) + search_config = SearchJobConfig.parse_obj(job_config_obj) sql_adapter = SQL_Adapter(Database.parse_obj(clp_metadata_db_conn_params)) start_time = datetime.datetime.now() @@ -168,7 +168,7 @@ def search( task_id=task_id, status=QueryTaskStatus.FAILED, duration=0, - error_log_path=clo_log_path, + error_log_path=str(clo_log_path), ).dict() update_search_task_metadata( @@ -231,6 +231,6 @@ def sigterm_handler(_signo, _stack_frame): ) if QueryTaskStatus.FAILED == search_status: - search_task_result.error_log_path = clo_log_path + search_task_result.error_log_path = str(clo_log_path) return search_task_result.dict() diff --git a/components/job-orchestration/job_orchestration/scheduler/constants.py b/components/job-orchestration/job_orchestration/scheduler/constants.py index 62f06f0cf..b640524d9 100644 --- a/components/job-orchestration/job_orchestration/scheduler/constants.py +++ b/components/job-orchestration/job_orchestration/scheduler/constants.py @@ -67,3 +67,13 @@ def __str__(self) -> str: def to_str(self) -> str: return str(self.name) + + +class QueryJobType(IntEnum): + SEARCH_OR_AGGREGATION = 0 + + def __str__(self) -> str: + return str(self.value) + + def to_str(self) -> str: + return str(self.name) diff --git a/components/job-orchestration/job_orchestration/scheduler/job_config.py b/components/job-orchestration/job_orchestration/scheduler/job_config.py index 93d4ede4e..528dce21a 100644 --- a/components/job-orchestration/job_orchestration/scheduler/job_config.py +++ b/components/job-orchestration/job_orchestration/scheduler/job_config.py @@ -39,7 +39,10 @@ class AggregationConfig(BaseModel): count_by_time_bucket_size: typing.Optional[int] = None # Milliseconds -class SearchConfig(BaseModel): +class QueryJobConfig(BaseModel): ... + + +class SearchJobConfig(QueryJobConfig): query_string: str max_num_results: int tags: typing.Optional[typing.List[str]] = None diff --git a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py index d8a045f31..5331051ae 100644 --- a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py +++ b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py @@ -24,7 +24,7 @@ import pathlib import sys from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Dict, List, Optional import celery import msgpack @@ -40,22 +40,27 @@ from clp_py_utils.decorators import exception_default_value from clp_py_utils.sql_adapter import SQL_Adapter from job_orchestration.executor.query.fs_search_task import search -from job_orchestration.scheduler.constants import QueryJobStatus, QueryTaskStatus -from job_orchestration.scheduler.job_config import SearchConfig +from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType, QueryTaskStatus +from job_orchestration.scheduler.job_config import SearchJobConfig from job_orchestration.scheduler.query.reducer_handler import ( handle_reducer_connection, ReducerHandlerMessage, ReducerHandlerMessageQueues, ReducerHandlerMessageType, ) -from job_orchestration.scheduler.scheduler_data import InternalJobState, QueryTaskResult, SearchJob +from job_orchestration.scheduler.scheduler_data import ( + InternalJobState, + QueryJob, + QueryTaskResult, + SearchJob, +) from pydantic import ValidationError # Setup logging logger = get_logger("search-job-handler") # Dictionary of active jobs indexed by job id -active_jobs: Dict[str, SearchJob] = {} +active_jobs: Dict[str, QueryJob] = {} reducer_connection_queue: Optional[asyncio.Queue] = None @@ -91,18 +96,19 @@ async def release_reducer_for_job(job: SearchJob): @exception_default_value(default=[]) -def fetch_new_search_jobs(db_conn) -> list: +def fetch_new_query_jobs(db_conn) -> list: """ - Fetches search jobs with status=PENDING from the database. + Fetches query jobs with status=PENDING from the database. :param db_conn: - :return: The pending search jobs on success. An empty list if an exception occurs while + :return: The pending query jobs on success. An empty list if an exception occurs while interacting with the database. """ with contextlib.closing(db_conn.cursor(dictionary=True)) as db_cursor: db_cursor.execute( f""" SELECT {QUERY_JOBS_TABLE_NAME}.id as job_id, - {QUERY_JOBS_TABLE_NAME}.job_config + {QUERY_JOBS_TABLE_NAME}.job_config, + {QUERY_JOBS_TABLE_NAME}.type FROM {QUERY_JOBS_TABLE_NAME} WHERE {QUERY_JOBS_TABLE_NAME}.status={QueryJobStatus.PENDING} """ @@ -124,6 +130,7 @@ def fetch_cancelling_search_jobs(db_conn) -> list: SELECT {QUERY_JOBS_TABLE_NAME}.id as job_id FROM {QUERY_JOBS_TABLE_NAME} WHERE {QUERY_JOBS_TABLE_NAME}.status={QueryJobStatus.CANCELLING} + AND {QUERY_JOBS_TABLE_NAME}.type={QueryJobType.SEARCH_OR_AGGREGATION} """ ) return db_cursor.fetchall() @@ -222,7 +229,7 @@ async def handle_cancelling_search_jobs(db_conn_pool) -> None: logger.error(f"Failed to cancel job {job_id}.") -def insert_search_tasks_into_db(db_conn, job_id, archive_ids: List[str]) -> List[int]: +def insert_query_tasks_into_db(db_conn, job_id, archive_ids: List[str]) -> List[int]: task_ids = [] with contextlib.closing(db_conn.cursor()) as cursor: for archive_id in archive_ids: @@ -241,7 +248,7 @@ def insert_search_tasks_into_db(db_conn, job_id, archive_ids: List[str]) -> List @exception_default_value(default=[]) def get_archives_for_search( db_conn, - search_config: SearchConfig, + search_config: SearchJobConfig, ): query = f"""SELECT id as archive_id, end_timestamp FROM {CLP_METADATA_TABLE_PREFIX}archives @@ -273,18 +280,17 @@ def get_archives_for_search( def get_task_group_for_job( archive_ids: List[str], task_ids: List[int], - job_id: str, - search_config: SearchConfig, + job: QueryJob, clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, ): - search_config_obj = search_config.dict() + job_config_obj = job.get_config().dict() return celery.group( search.s( - job_id=job_id, + job_id=job.id, archive_id=archive_ids[i], task_id=task_ids[i], - search_config_obj=search_config_obj, + job_config_obj=job_config_obj, clp_metadata_db_conn_params=clp_metadata_db_conn_params, results_cache_uri=results_cache_uri, ) @@ -292,22 +298,20 @@ def get_task_group_for_job( ) -def dispatch_search_job( +def dispatch_query_job( db_conn, - job: SearchJob, - archives_for_search: List[Dict[str, any]], + job: QueryJob, + archive_ids: List[str], clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, ) -> None: global active_jobs - archive_ids = [archive["archive_id"] for archive in archives_for_search] - task_ids = insert_search_tasks_into_db(db_conn, job.id, archive_ids) + task_ids = insert_query_tasks_into_db(db_conn, job.id, archive_ids) task_group = get_task_group_for_job( archive_ids, task_ids, - job.id, - job.search_config, + job, clp_metadata_db_conn_params, results_cache_uri, ) @@ -360,7 +364,7 @@ async def acquire_reducer_for_job(job: SearchJob): logger.info(f"Got reducer for job {job.id} at {reducer_host}:{reducer_port}") -def handle_pending_search_jobs( +def handle_pending_query_jobs( db_conn_pool, clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, @@ -370,57 +374,68 @@ def handle_pending_search_jobs( reducer_acquisition_tasks = [] - pending_jobs = [ - job for job in active_jobs.values() if InternalJobState.WAITING_FOR_DISPATCH == job.state + pending_search_jobs = [ + job + for job in active_jobs.values() + if InternalJobState.WAITING_FOR_DISPATCH == job.state + and job.get_type() == QueryJobType.SEARCH_OR_AGGREGATION ] with contextlib.closing(db_conn_pool.connect()) as db_conn: - for job in fetch_new_search_jobs(db_conn): + for job in fetch_new_query_jobs(db_conn): job_id = str(job["job_id"]) - - # Avoid double-dispatch when a job is WAITING_FOR_REDUCER - if job_id in active_jobs: - continue - - search_config = SearchConfig.parse_obj(msgpack.unpackb(job["job_config"])) - archives_for_search = get_archives_for_search(db_conn, search_config) - if len(archives_for_search) == 0: - if set_job_or_task_status( - db_conn, - QUERY_JOBS_TABLE_NAME, - job_id, - QueryJobStatus.SUCCEEDED, - QueryJobStatus.PENDING, - start_time=datetime.datetime.now(), - num_tasks=0, - duration=0, - ): - logger.info(f"No matching archives, skipping job {job['job_id']}.") - continue - - new_search_job = SearchJob( - id=job_id, - search_config=search_config, - state=InternalJobState.WAITING_FOR_DISPATCH, - num_archives_to_search=len(archives_for_search), - num_archives_searched=0, - remaining_archives_for_search=archives_for_search, - ) - - if search_config.aggregation_config is not None: - new_search_job.search_config.aggregation_config.job_id = job["job_id"] - new_search_job.state = InternalJobState.WAITING_FOR_REDUCER - new_search_job.reducer_acquisition_task = asyncio.create_task( - acquire_reducer_for_job(new_search_job) + job_type = job["type"] + job_config = job["job_config"] + + if QueryJobType.SEARCH_OR_AGGREGATION == job_type: + # Avoid double-dispatch when a job is WAITING_FOR_REDUCER + if job_id in active_jobs: + continue + + search_config = SearchJobConfig.parse_obj(msgpack.unpackb(job_config)) + archives_for_search = get_archives_for_search(db_conn, search_config) + if len(archives_for_search) == 0: + if set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + QueryJobStatus.SUCCEEDED, + QueryJobStatus.PENDING, + start_time=datetime.datetime.now(), + num_tasks=0, + duration=0, + ): + logger.info(f"No matching archives, skipping job {job_id}.") + continue + + new_search_job = SearchJob( + id=job_id, + search_config=search_config, + state=InternalJobState.WAITING_FOR_DISPATCH, + num_archives_to_search=len(archives_for_search), + num_archives_searched=0, + remaining_archives_for_search=archives_for_search, ) - reducer_acquisition_tasks.append(new_search_job.reducer_acquisition_task) + + if search_config.aggregation_config is not None: + new_search_job.search_config.aggregation_config.job_id = int(job_id) + new_search_job.state = InternalJobState.WAITING_FOR_REDUCER + new_search_job.reducer_acquisition_task = asyncio.create_task( + acquire_reducer_for_job(new_search_job) + ) + reducer_acquisition_tasks.append(new_search_job.reducer_acquisition_task) + else: + pending_search_jobs.append(new_search_job) + active_jobs[job_id] = new_search_job else: - pending_jobs.append(new_search_job) - active_jobs[job_id] = new_search_job + # NOTE: We're skipping the job for this iteration, but its status will remain + # unchanged. So this log will print again in the next iteration unless the user + # cancels the job. + logger.error(f"Unexpected job type: {job_type}, skipping job {job_id}") + continue - for job in pending_jobs: + for job in pending_search_jobs: job_id = job.id - if ( job.search_config.network_address is None and len(job.remaining_archives_for_search) > num_archives_to_search_per_sub_job @@ -435,11 +450,13 @@ def handle_pending_search_jobs( archives_for_search = job.remaining_archives_for_search job.remaining_archives_for_search = [] - dispatch_search_job( - db_conn, job, archives_for_search, clp_metadata_db_conn_params, results_cache_uri + archive_ids_for_search = [archive["archive_id"] for archive in archives_for_search] + + dispatch_query_job( + db_conn, job, archive_ids_for_search, clp_metadata_db_conn_params, results_cache_uri ) logger.info( - f"Dispatched job {job_id} with {len(archives_for_search)} archives to search." + f"Dispatched job {job_id} with {len(archive_ids_for_search)} archives to search." ) start_time = datetime.datetime.now() job.start_time = start_time @@ -487,6 +504,92 @@ def found_max_num_latest_results( return max_timestamp_in_remaining_archives <= min_timestamp_in_top_results +async def handle_finished_search_job( + db_conn, job: SearchJob, task_results: Optional[Any], results_cache_uri: str +) -> None: + global active_jobs + + job_id = job.id + is_reducer_job = job.reducer_handler_msg_queues is not None + new_job_status = QueryJobStatus.RUNNING + for task_result_obj in task_results: + task_result = QueryTaskResult.parse_obj(task_result_obj) + task_id = task_result.task_id + task_status = task_result.status + if not task_status == QueryTaskStatus.SUCCEEDED: + new_job_status = QueryJobStatus.FAILED + logger.error( + f"Search task job-{job_id}-task-{task_id} failed. " + f"Check {task_result.error_log_path} for details." + ) + else: + job.num_archives_searched += 1 + logger.info( + f"Search task job-{job_id}-task-{task_id} succeeded in " + f"{task_result.duration} second(s)." + ) + + if new_job_status != QueryJobStatus.FAILED: + max_num_results = job.search_config.max_num_results + # Check if we've searched all archives + if len(job.remaining_archives_for_search) == 0: + new_job_status = QueryJobStatus.SUCCEEDED + # Check if we've reached max results + elif False == is_reducer_job and max_num_results > 0: + if found_max_num_latest_results( + results_cache_uri, + job_id, + max_num_results, + job.remaining_archives_for_search[0]["end_timestamp"], + ): + new_job_status = QueryJobStatus.SUCCEEDED + if new_job_status == QueryJobStatus.RUNNING: + job.current_sub_job_async_task_result = None + job.state = InternalJobState.WAITING_FOR_DISPATCH + logger.info(f"Job {job_id} waiting for more archives to search.") + set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + QueryJobStatus.RUNNING, + QueryJobStatus.RUNNING, + num_tasks_completed=job.num_archives_searched, + ) + return + + reducer_failed = False + if is_reducer_job: + # Notify reducer that it should have received all results + msg = ReducerHandlerMessage(ReducerHandlerMessageType.SUCCESS) + await job.reducer_handler_msg_queues.put_to_handler(msg) + + msg = await job.reducer_handler_msg_queues.get_from_handler() + if ReducerHandlerMessageType.FAILURE == msg.msg_type: + reducer_failed = True + new_job_status = QueryJobStatus.FAILED + elif ReducerHandlerMessageType.SUCCESS != msg.msg_type: + error_msg = f"Unexpected msg_type: {msg.msg_type.name}" + raise NotImplementedError(error_msg) + + # We set the status regardless of the job's previous status to handle the case where the + # job is cancelled (status = CANCELLING) while we're in this method. + if set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + new_job_status, + num_tasks_completed=job.num_archives_searched, + duration=(datetime.datetime.now() - job.start_time).total_seconds(), + ): + if new_job_status == QueryJobStatus.SUCCEEDED: + logger.info(f"Completed job {job_id}.") + elif reducer_failed: + logger.error(f"Completed job {job_id} with failing reducer.") + else: + logger.info(f"Completed job {job_id} with failing tasks.") + del active_jobs[job_id] + + async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): global active_jobs @@ -495,16 +598,15 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): id for id, job in active_jobs.items() if InternalJobState.RUNNING == job.state ]: job = active_jobs[job_id] - is_reducer_job = job.reducer_handler_msg_queues is not None - try: returned_results = try_getting_task_result(job.current_sub_job_async_task_result) except Exception as e: logger.error(f"Job `{job_id}` failed: {e}.") # Clean up - if is_reducer_job: - msg = ReducerHandlerMessage(ReducerHandlerMessageType.FAILURE) - await job.reducer_handler_msg_queues.put_to_handler(msg) + if QueryJobType.SEARCH_OR_AGGREGATION == job.get_type(): + if job.reducer_handler_msg_queues is not None: + msg = ReducerHandlerMessage(ReducerHandlerMessageType.FAILURE) + await job.reducer_handler_msg_queues.put_to_handler(msg) del active_jobs[job_id] set_job_or_task_status( @@ -519,84 +621,14 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): if returned_results is None: continue - - new_job_status = QueryJobStatus.RUNNING - for task_result_obj in returned_results: - task_result = QueryTaskResult.parse_obj(task_result_obj) - task_id = task_result.task_id - task_status = task_result.status - if not task_status == QueryTaskStatus.SUCCEEDED: - new_job_status = QueryJobStatus.FAILED - logger.error( - f"Search task job-{job_id}-task-{task_id} failed. " - f"Check {task_result.error_log_path} for details." - ) - else: - job.num_archives_searched += 1 - logger.info( - f"Search task job-{job_id}-task-{task_id} succeeded in " - f"{task_result.duration} second(s)." - ) - - if new_job_status != QueryJobStatus.FAILED: - max_num_results = job.search_config.max_num_results - # Check if we've searched all archives - if len(job.remaining_archives_for_search) == 0: - new_job_status = QueryJobStatus.SUCCEEDED - # Check if we've reached max results - elif False == is_reducer_job and max_num_results > 0: - if found_max_num_latest_results( - results_cache_uri, - job_id, - max_num_results, - job.remaining_archives_for_search[0]["end_timestamp"], - ): - new_job_status = QueryJobStatus.SUCCEEDED - if new_job_status == QueryJobStatus.RUNNING: - job.current_sub_job_async_task_result = None - job.state = InternalJobState.WAITING_FOR_DISPATCH - logger.info(f"Job {job_id} waiting for more archives to search.") - set_job_or_task_status( - db_conn, - QUERY_JOBS_TABLE_NAME, - job_id, - QueryJobStatus.RUNNING, - QueryJobStatus.RUNNING, - num_tasks_completed=job.num_archives_searched, + job_type = job.get_type() + if QueryJobType.SEARCH_OR_AGGREGATION == job_type: + search_job: SearchJob = job + await handle_finished_search_job( + db_conn, search_job, returned_results, results_cache_uri ) - continue - - reducer_failed = False - if is_reducer_job: - # Notify reducer that it should have received all results - msg = ReducerHandlerMessage(ReducerHandlerMessageType.SUCCESS) - await job.reducer_handler_msg_queues.put_to_handler(msg) - - msg = await job.reducer_handler_msg_queues.get_from_handler() - if ReducerHandlerMessageType.FAILURE == msg.msg_type: - reducer_failed = True - new_job_status = QueryJobStatus.FAILED - elif ReducerHandlerMessageType.SUCCESS != msg.msg_type: - error_msg = f"Unexpected msg_type: {msg.msg_type.name}" - raise NotImplementedError(error_msg) - - # We set the status regardless of the job's previous status to handle the case where the - # job is cancelled (status = CANCELLING) while we're in this method. - if set_job_or_task_status( - db_conn, - QUERY_JOBS_TABLE_NAME, - job_id, - new_job_status, - num_tasks_completed=job.num_archives_searched, - duration=(datetime.datetime.now() - job.start_time).total_seconds(), - ): - if new_job_status == QueryJobStatus.SUCCEEDED: - logger.info(f"Completed job {job_id}.") - elif reducer_failed: - logger.error(f"Completed job {job_id} with failing reducer.") - else: - logger.info(f"Completed job {job_id} with failing tasks.") - del active_jobs[job_id] + else: + logger.error(f"Unexpected job type: {job_type}, skipping job {job_id}") async def handle_job_updates(db_conn_pool, results_cache_uri: str, jobs_poll_delay: float): @@ -619,7 +651,7 @@ async def handle_jobs( tasks = [handle_updating_task] while True: - reducer_acquisition_tasks = handle_pending_search_jobs( + reducer_acquisition_tasks = handle_pending_query_jobs( db_conn_pool, clp_metadata_db_conn_params, results_cache_uri, diff --git a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py index a3aa5f436..d337e0806 100644 --- a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py +++ b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py @@ -1,10 +1,15 @@ import asyncio import datetime +from abc import ABC, abstractmethod from enum import auto, Enum from typing import Any, Dict, List, Optional -from job_orchestration.scheduler.constants import CompressionTaskStatus, QueryTaskStatus -from job_orchestration.scheduler.job_config import SearchConfig +from job_orchestration.scheduler.constants import ( + CompressionTaskStatus, + QueryJobType, + QueryTaskStatus, +) +from job_orchestration.scheduler.job_config import QueryJobConfig, SearchJobConfig from job_orchestration.scheduler.query.reducer_handler import ReducerHandlerMessageQueues from pydantic import BaseModel, validator @@ -35,21 +40,33 @@ class InternalJobState(Enum): RUNNING = auto() -class QueryJob(BaseModel): +class QueryJob(BaseModel, ABC): id: str state: InternalJobState start_time: Optional[datetime.datetime] current_sub_job_async_task_result: Optional[Any] + @abstractmethod + def get_type(self) -> QueryJobType: ... + + @abstractmethod + def get_config(self) -> QueryJobConfig: ... + class SearchJob(QueryJob): - search_config: SearchConfig + search_config: SearchJobConfig num_archives_to_search: int num_archives_searched: int remaining_archives_for_search: List[Dict[str, Any]] reducer_acquisition_task: Optional[asyncio.Task] reducer_handler_msg_queues: Optional[ReducerHandlerMessageQueues] + def get_type(self) -> QueryJobType: + return QueryJobType.SEARCH_OR_AGGREGATION + + def get_config(self) -> QueryJobConfig: + return self.search_config + class Config: # To allow asyncio.Task and asyncio.Queue arbitrary_types_allowed = True diff --git a/components/webui/imports/api/search/constants.js b/components/webui/imports/api/search/constants.js index ec4c13ad6..fbc0c3188 100644 --- a/components/webui/imports/api/search/constants.js +++ b/components/webui/imports/api/search/constants.js @@ -81,6 +81,19 @@ const QUERY_JOB_STATUS_WAITING_STATES = [ QUERY_JOB_STATUS.CANCELLING, ]; +/* eslint-disable sort-keys */ +let enumQueryType; +/** + * Enum of job type, matching the `QueryJobType` class in + * `job_orchestration.query_scheduler.constants`. + * + * @enum {number} + */ +const QUERY_JOB_TYPE = Object.freeze({ + SEARCH_OR_AGGREGATION: (enumQueryType = 0), +}); +/* eslint-enable sort-keys */ + /** * Enum of Mongo Collection sort orders. * @@ -114,6 +127,7 @@ export { MONGO_SORT_ORDER, QUERY_JOB_STATUS, QUERY_JOB_STATUS_WAITING_STATES, + QUERY_JOB_TYPE, SEARCH_MAX_NUM_RESULTS, SEARCH_RESULTS_FIELDS, SEARCH_SIGNAL, diff --git a/components/webui/imports/api/search/server/QueryJobsDbManager.js b/components/webui/imports/api/search/server/QueryJobsDbManager.js index 4d3bed94a..835aae796 100644 --- a/components/webui/imports/api/search/server/QueryJobsDbManager.js +++ b/components/webui/imports/api/search/server/QueryJobsDbManager.js @@ -5,6 +5,7 @@ import {sleep} from "/imports/utils/misc"; import { QUERY_JOB_STATUS, QUERY_JOB_STATUS_WAITING_STATES, + QUERY_JOB_TYPE, } from "../constants"; @@ -21,6 +22,7 @@ const JOB_COMPLETION_STATUS_POLL_INTERVAL_MILLIS = 0.5; const QUERY_JOBS_TABLE_COLUMN_NAMES = Object.freeze({ ID: "id", STATUS: "status", + TYPE: "type", JOB_CONFIG: "job_config", }); @@ -52,9 +54,11 @@ class QueryJobsDbManager { async submitSearchJob (searchConfig) { const [queryInsertResults] = await this.#sqlDbConnPool.query( `INSERT INTO ${this.#queryJobsTableName} - (${QUERY_JOBS_TABLE_COLUMN_NAMES.JOB_CONFIG}) - VALUES (?)`, - [Buffer.from(msgpack.encode(searchConfig))], + (${QUERY_JOBS_TABLE_COLUMN_NAMES.JOB_CONFIG}, + ${QUERY_JOBS_TABLE_COLUMN_NAMES.TYPE}) + VALUES (?, ?)`, + [Buffer.from(msgpack.encode(searchConfig)), + QUERY_JOB_TYPE.SEARCH_OR_AGGREGATION], ); return queryInsertResults.insertId; From 01d57372bc1133ca5bb9f0b8efe28fc7e5244406 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Tue, 25 Jun 2024 11:53:19 -0400 Subject: [PATCH 013/114] clp-s: Add support for chunking output into different files during timestamp-ordered decompression (#451) Co-authored-by: wraymo <37269683+wraymo@users.noreply.github.com> --- .../core/src/clp_s/CommandLineArguments.cpp | 13 ++++ .../core/src/clp_s/CommandLineArguments.hpp | 3 + components/core/src/clp_s/JsonConstructor.cpp | 66 ++++++++++++++++--- components/core/src/clp_s/JsonConstructor.hpp | 5 +- components/core/src/clp_s/clp-s.cpp | 1 + 5 files changed, 76 insertions(+), 12 deletions(-) diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index 3b715aff7..77e896160 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -287,11 +287,19 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { extraction_options.add(input_options); po::options_description decompression_options("Decompression Options"); + // clang-format off decompression_options.add_options()( "ordered", po::bool_switch(&m_ordered_decompression), "Enable decompression in ascending timestamp order for this archive" + )( + "ordered-chunk-size", + po::value(&m_ordered_chunk_size) + ->default_value(m_ordered_chunk_size), + "Number of records to include in each output file when decompressing records " + "in ascending timestamp order" ); + // clang-format on extraction_options.add(decompression_options); po::positional_options_description positional_options; @@ -336,6 +344,11 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { if (m_output_dir.empty()) { throw std::invalid_argument("No output directory specified"); } + + if (0 != m_ordered_chunk_size && false == m_ordered_decompression) { + throw std::invalid_argument("ordered-chunk-size must be used with ordered argument" + ); + } } else if ((char)Command::Search == command_input) { std::string archives_dir; std::string query; diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 4c367509a..0f3d8c556 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -106,6 +106,8 @@ class CommandLineArguments { bool get_ordered_decompression() const { return m_ordered_decompression; } + size_t get_ordered_chunk_size() const { return m_ordered_chunk_size; } + private: // Methods /** @@ -170,6 +172,7 @@ class CommandLineArguments { size_t m_max_document_size{512ULL * 1024 * 1024}; // 512 MB bool m_structurize_arrays{false}; bool m_ordered_decompression{false}; + size_t m_ordered_chunk_size{0}; // Metadata db variables std::optional m_metadata_db_config; diff --git a/components/core/src/clp_s/JsonConstructor.cpp b/components/core/src/clp_s/JsonConstructor.cpp index e48d370d1..68151a1a7 100644 --- a/components/core/src/clp_s/JsonConstructor.cpp +++ b/components/core/src/clp_s/JsonConstructor.cpp @@ -16,7 +16,8 @@ JsonConstructor::JsonConstructor(JsonConstructorOption const& option) : m_output_dir(option.output_dir), m_archives_dir(option.archives_dir), m_ordered{option.ordered}, - m_archive_id(option.archive_id) { + m_archive_id(option.archive_id), + m_ordered_chunk_size(option.ordered_chunk_size) { std::error_code error_code; if (false == std::filesystem::create_directory(option.output_dir, error_code) && error_code) { throw OperationFailed( @@ -44,24 +45,25 @@ JsonConstructor::JsonConstructor(JsonConstructorOption const& option) } void JsonConstructor::store() { - FileWriter writer; - // TODO: change this when doing chunking - writer.open(m_output_dir + "/original", FileWriter::OpenMode::CreateIfNonexistentForAppending); - m_archive_reader = std::make_unique(); m_archive_reader->open(m_archives_dir, m_archive_id); m_archive_reader->read_dictionaries_and_metadata(); if (false == m_ordered) { + FileWriter writer; + writer.open( + m_output_dir + "/original", + FileWriter::OpenMode::CreateIfNonexistentForAppending + ); m_archive_reader->store(writer); + + writer.close(); } else { - construct_in_order(writer); + construct_in_order(); } m_archive_reader->close(); - - writer.close(); } -void JsonConstructor::construct_in_order(FileWriter& writer) { +void JsonConstructor::construct_in_order() { std::string buffer; auto tables = m_archive_reader->read_all_tables(); using ReaderPointer = std::shared_ptr; @@ -72,15 +74,59 @@ void JsonConstructor::construct_in_order(FileWriter& writer) { // Clear tables vector so that memory gets deallocated after we have marshalled all records for // a given table tables.clear(); + + epochtime_t first_timestamp{0}; + epochtime_t last_timestamp{0}; + size_t num_records_marshalled{0}; + auto src_path = std::filesystem::path(m_output_dir) / m_archive_id; + FileWriter writer; + writer.open(src_path, FileWriter::OpenMode::CreateForWriting); + + auto finalize_chunk = [&](bool open_new_writer) { + writer.close(); + std::string new_file_name = src_path.string() + "_" + std::to_string(first_timestamp) + "_" + + std::to_string(last_timestamp) + ".jsonl"; + auto new_file_path = std::filesystem::path(new_file_name); + std::error_code ec; + std::filesystem::rename(src_path, new_file_path, ec); + if (ec) { + throw OperationFailed(ErrorCodeFailure, __FILE__, __LINE__, ec.message()); + } + + if (open_new_writer) { + writer.open(src_path, FileWriter::OpenMode::CreateForWriting); + } + }; + while (false == record_queue.empty()) { ReaderPointer next = record_queue.top(); record_queue.pop(); + last_timestamp = next->get_next_timestamp(); + if (0 == num_records_marshalled) { + first_timestamp = last_timestamp; + } next->get_next_message(buffer); if (false == next->done()) { record_queue.emplace(std::move(next)); } writer.write(buffer.c_str(), buffer.length()); + num_records_marshalled += 1; + + if (0 != m_ordered_chunk_size && num_records_marshalled >= m_ordered_chunk_size) { + finalize_chunk(true); + num_records_marshalled = 0; + } + } + + if (num_records_marshalled > 0) { + finalize_chunk(false); + } else { + writer.close(); + std::error_code ec; + std::filesystem::remove(src_path, ec); + if (ec) { + throw OperationFailed(ErrorCodeFailure, __FILE__, __LINE__, ec.message()); + } } - writer.close(); } } // namespace clp_s diff --git a/components/core/src/clp_s/JsonConstructor.hpp b/components/core/src/clp_s/JsonConstructor.hpp index 0324924b9..22a2daf59 100644 --- a/components/core/src/clp_s/JsonConstructor.hpp +++ b/components/core/src/clp_s/JsonConstructor.hpp @@ -20,6 +20,7 @@ struct JsonConstructorOption { std::string archive_id; std::string output_dir; bool ordered; + size_t ordered_chunk_size; }; class JsonConstructor { @@ -55,14 +56,14 @@ class JsonConstructor { /** * Reads all of the tables from m_archive_reader and writes all of the records * they contain to writer in timestamp order. - * @param writer */ - void construct_in_order(FileWriter& writer); + void construct_in_order(); std::string m_archives_dir; std::string m_archive_id; std::string m_output_dir; bool m_ordered{false}; + size_t m_ordered_chunk_size{0}; std::unique_ptr m_archive_reader; }; diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 74235e0e1..d01ed0fe0 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -273,6 +273,7 @@ int main(int argc, char const* argv[]) { option.output_dir = command_line_arguments.get_output_dir(); option.ordered = command_line_arguments.get_ordered_decompression(); option.archives_dir = archives_dir; + option.ordered_chunk_size = command_line_arguments.get_ordered_chunk_size(); try { auto const& archive_id = command_line_arguments.get_archive_id(); if (false == archive_id.empty()) { From 14d923413b9c4ea90017d85f9be4ebd67700ca48 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:48:40 -0400 Subject: [PATCH 014/114] docs: Add tooling to check and validate build: (#447) - Add script to check for invalid links. - Add workflow to validate build. - Fail on warnings. - Fix invalid link in log-viewer-webui README. Co-authored-by: Henry8192 <50559854+Henry8192@users.noreply.github.com> --- .github/workflows/clp-docs.yaml | 38 ++++++++ components/log-viewer-webui/README.md | 2 +- docs/tasks.yml | 4 + tools/scripts/find-broken-docs-links.py | 117 ++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/clp-docs.yaml create mode 100644 tools/scripts/find-broken-docs-links.py diff --git a/.github/workflows/clp-docs.yaml b/.github/workflows/clp-docs.yaml new file mode 100644 index 000000000..2f0a68e77 --- /dev/null +++ b/.github/workflows/clp-docs.yaml @@ -0,0 +1,38 @@ +name: "clp-docs" + +on: + pull_request: + push: + workflow_dispatch: + +concurrency: + group: "${{github.workflow}}-${{github.ref}}" + # Cancel in-progress jobs for efficiency + cancel-in-progress: true + +jobs: + build: + strategy: + matrix: + os: ["macos-latest", "ubuntu-latest"] + runs-on: "${{matrix.os}}" + steps: + - uses: "actions/checkout@v4" + with: + submodules: "recursive" + + - uses: "actions/setup-python@v5" + with: + python-version: "3.10" + + - name: "Install task" + shell: "bash" + run: "npm install -g @go-task/cli" + + - if: "matrix.os == 'macos-latest'" + name: "Install coreutils (for md5sum)" + run: "brew install coreutils" + + - name: "Build docs" + shell: "bash" + run: "task docs:site" diff --git a/components/log-viewer-webui/README.md b/components/log-viewer-webui/README.md index 265385dc6..e052ec9d9 100644 --- a/components/log-viewer-webui/README.md +++ b/components/log-viewer-webui/README.md @@ -4,6 +4,6 @@ A webapp that allows us to serve the [log-viewer] and integrate it with CLP's [w See the [docs] for more details. -[docs]: https://docs.yscope.com/clp/main/dev-guide/components-log-viewer-webui.md +[docs]: https://docs.yscope.com/clp/main/dev-guide/components-log-viewer-webui [log-viewer]: https://github.com/y-scope/yscope-log-viewer [webui]: ../webui diff --git a/docs/tasks.yml b/docs/tasks.yml index 44f5709c5..45e2cf05e 100644 --- a/docs/tasks.yml +++ b/docs/tasks.yml @@ -34,12 +34,16 @@ tasks: # Call `clean` before building since `sphinx-build --write-all --fresh-env` isn't always # equivalent to building from scratch. - task: "clean" + - "python3 '{{.ROOT_DIR}}/tools/scripts/find-broken-docs-links.py'" - |- . "{{.G_DOCS_VENV_DIR}}/bin/activate" sphinx-build \ --write-all \ --fresh-env \ --conf-dir conf \ + --nitpicky \ + --fail-on-warning \ + --keep-going \ --builder html \ src "{{.OUTPUT_DIR}}" # This command must be last diff --git a/tools/scripts/find-broken-docs-links.py b/tools/scripts/find-broken-docs-links.py new file mode 100644 index 000000000..349e927ef --- /dev/null +++ b/tools/scripts/find-broken-docs-links.py @@ -0,0 +1,117 @@ +import os +import subprocess +import sys +from pathlib import Path + + +def main(argv): + repo_root = _get_repo_root() + + found_violation = False + + # Check for docs.yscope.com links with ".md" suffixes + if _check_tracked_files( + r"docs\.yscope\.com/.+\.md", + repo_root, + repo_root, + "docs.yscope.com links cannot have \".md\" suffixes." + ): + found_violation = True + + # Check for sphinx :link: attributes that have ".md" suffixes + if _check_tracked_files( + r":link:[[:space:]]*.+\.md", + repo_root, + repo_root / "docs", + "sphinx :link: attributes cannot have \".md\" suffixes" + ): + found_violation = True + + if found_violation: + return 1 + + return 0 + + +def _get_repo_root() -> Path: + path_str = subprocess.check_output( + ["git", "rev-parse", "--show-toplevel"], + cwd=Path(__file__).parent, + text=True + ) + return Path(path_str.strip()) + + +def _check_tracked_files( + pattern: str, + repo_root: Path, + dir_to_search: Path, + error_msg: str +) -> bool: + """ + Check for a pattern in all tracked files in the repo (except this script). + :param pattern: The pattern to search for. + :param repo_root: The root of the repository. + :param dir_to_search: The directory to search in. + :param error_msg: Error message if the pattern is found. + :return: Whether the pattern was found in any file. + """ + found_matches = False + + # NOTE: "-z" ensures the paths won't be quoted (while delimiting them using '\0') + for path_str in subprocess.check_output( + [ + "git", + "ls-files", + "--cached", + "--exclude-standard", + "-z", + str(dir_to_search.relative_to(repo_root)) + ], + cwd=repo_root, + text=True, + ).split("\0"): + path = Path(path_str) + + # Skip directories and this script + if path == __file__ or (repo_root / path).is_dir(): + continue + + try: + for match in subprocess.check_output( + [ + "grep", + "--extended-regexp", + "--line-number", + "--with-filename", + pattern, + path + ], + cwd=repo_root, + text=True, + ).splitlines(): + _parse_and_print_match(match, error_msg) + found_matches = True + except subprocess.CalledProcessError: + pass + + return found_matches + + +def _parse_and_print_match(match: str, error_msg: str): + """ + Parses and prints grep matches in a format relevant to the current environment. + :param match: The match to parse and print. + :param error_msg: Error message if the pattern is found. + """ + if os.getenv("GITHUB_ACTIONS") == "true": + # Print a GitHub Actions error annotation + file, line, _ = match.split(":", 2) + print(f"::error file={file},line={line}::{error_msg}") + else: + print(error_msg, file=sys.stderr) + print(match, file=sys.stderr) + + +if "__main__" == __name__: + sys.exit(main(sys.argv)) From 8a2c0a818cdf4ff252ad15d22713c3a20b3c28d1 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Tue, 25 Jun 2024 19:20:21 -0400 Subject: [PATCH 015/114] clp-s: Ensure ArchiveWriterOption is fully initialized when splitting archives. (#462) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/src/clp_s/JsonParser.cpp | 24 ++++++++---------------- components/core/src/clp_s/JsonParser.hpp | 4 +--- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index c4fe7a43e..d73643a64 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -11,9 +11,7 @@ namespace clp_s { JsonParser::JsonParser(JsonParserOption const& option) - : m_archives_dir(option.archives_dir), - m_num_messages(0), - m_compression_level(option.compression_level), + : m_num_messages(0), m_target_encoded_size(option.target_encoded_size), m_max_document_size(option.max_document_size), m_timestamp_key(option.timestamp_key), @@ -30,14 +28,13 @@ JsonParser::JsonParser(JsonParserOption const& option) FileUtils::find_all_files(file_path, m_file_paths); } - ArchiveWriterOption archive_writer_option; - archive_writer_option.archives_dir = m_archives_dir; - archive_writer_option.id = m_generator(); - archive_writer_option.compression_level = option.compression_level; - archive_writer_option.print_archive_stats = option.print_archive_stats; + m_archive_options.archives_dir = option.archives_dir; + m_archive_options.compression_level = option.compression_level; + m_archive_options.print_archive_stats = option.print_archive_stats; + m_archive_options.id = m_generator(); m_archive_writer = std::make_unique(option.metadata_db); - m_archive_writer->open(archive_writer_option); + m_archive_writer->open(m_archive_options); } void JsonParser::parse_obj_in_array(ondemand::object line, int32_t parent_node_id) { @@ -505,13 +502,8 @@ void JsonParser::store() { void JsonParser::split_archive() { m_archive_writer->close(); - - ArchiveWriterOption archive_writer_option; - archive_writer_option.archives_dir = m_archives_dir; - archive_writer_option.id = m_generator(); - archive_writer_option.compression_level = m_compression_level; - - m_archive_writer->open(archive_writer_option); + m_archive_options.id = m_generator(); + m_archive_writer->open(m_archive_options); } } // namespace clp_s diff --git a/components/core/src/clp_s/JsonParser.hpp b/components/core/src/clp_s/JsonParser.hpp index a0010e66f..f65f4c4b1 100644 --- a/components/core/src/clp_s/JsonParser.hpp +++ b/components/core/src/clp_s/JsonParser.hpp @@ -93,10 +93,7 @@ class JsonParser { void split_archive(); int m_num_messages; - int m_compression_level; std::vector m_file_paths; - std::string m_archives_dir; - std::string m_schema_tree_path; Schema m_current_schema; ParsedMessage m_current_parsed_message; @@ -106,6 +103,7 @@ class JsonParser { boost::uuids::random_generator m_generator; std::unique_ptr m_archive_writer; + ArchiveWriterOption m_archive_options{}; size_t m_target_encoded_size; size_t m_max_document_size; bool m_structurize_arrays{false}; From 249816b5cb0412ce40ac79cb57f5bfbbd6900c3e Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 27 Jun 2024 00:40:34 -0400 Subject: [PATCH 016/114] Add support for validating and escaping UTF-8 strings. (#453) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 5 + components/core/src/clp/ffi/utils.cpp | 89 +++++++++ components/core/src/clp/ffi/utils.hpp | 31 ++++ components/core/src/clp/utf8_utils.cpp | 55 ++++++ components/core/src/clp/utf8_utils.hpp | 144 +++++++++++++++ components/core/tests/test-utf8_utils.cpp | 209 ++++++++++++++++++++++ 6 files changed, 533 insertions(+) create mode 100644 components/core/src/clp/ffi/utils.cpp create mode 100644 components/core/src/clp/ffi/utils.hpp create mode 100644 components/core/src/clp/utf8_utils.cpp create mode 100644 components/core/src/clp/utf8_utils.hpp create mode 100644 components/core/tests/test-utf8_utils.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index e3b62047a..7cba49acb 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -326,6 +326,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/search/Subquery.hpp src/clp/ffi/search/WildcardToken.cpp src/clp/ffi/search/WildcardToken.hpp + src/clp/ffi/utils.cpp + src/clp/ffi/utils.hpp src/clp/FileDescriptor.cpp src/clp/FileDescriptor.hpp src/clp/FileReader.cpp @@ -438,6 +440,8 @@ set(SOURCE_FILES_unitTest src/clp/TraceableException.hpp src/clp/time_types.hpp src/clp/type_utils.hpp + src/clp/utf8_utils.cpp + src/clp/utf8_utils.hpp src/clp/Utils.cpp src/clp/Utils.hpp src/clp/VariableDictionaryEntry.cpp @@ -472,6 +476,7 @@ set(SOURCE_FILES_unitTest tests/test-StreamingCompression.cpp tests/test-string_utils.cpp tests/test-TimestampPattern.cpp + tests/test-utf8_utils.cpp tests/test-Utils.cpp ) add_executable(unitTest ${SOURCE_FILES_unitTest} ${SOURCE_FILES_clp_s_unitTest}) diff --git a/components/core/src/clp/ffi/utils.cpp b/components/core/src/clp/ffi/utils.cpp new file mode 100644 index 000000000..c85c47701 --- /dev/null +++ b/components/core/src/clp/ffi/utils.cpp @@ -0,0 +1,89 @@ +#include "utils.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../utf8_utils.hpp" + +using std::string; +using std::string_view; + +namespace clp::ffi { +auto validate_and_escape_utf8_string(string_view raw) -> std::optional { + std::optional ret_val; + auto& escaped{ret_val.emplace()}; + escaped.reserve(raw.size() + (raw.size() / 2)); + if (false == validate_and_append_escaped_utf8_string(raw, escaped)) { + return std::nullopt; + } + return ret_val; +} + +auto validate_and_append_escaped_utf8_string(std::string_view src, std::string& dst) -> bool { + string_view::const_iterator next_char_to_copy_it{src.cbegin()}; + + auto escape_handler = [&](string_view::const_iterator it) -> void { + // Allocate 6 + 1 size buffer to format control characters as "\u00bb", with the last byte + // used by `snprintf` to append '\0' + constexpr size_t cControlCharacterBufSize{7}; + std::array buf{}; + std::string_view escaped_char; + bool escape_required{true}; + switch (*it) { + case '\b': + escaped_char = "\\b"; + break; + case '\t': + escaped_char = "\\t"; + break; + case '\n': + escaped_char = "\\n"; + break; + case '\f': + escaped_char = "\\f"; + break; + case '\r': + escaped_char = "\\r"; + break; + case '\\': + escaped_char = "\\\\"; + break; + case '"': + escaped_char = "\\\""; + break; + default: { + constexpr uint8_t cLargestControlCharacter{0x1F}; + auto const byte{static_cast(*it)}; + if (cLargestControlCharacter >= byte) { + std::ignore = snprintf(buf.data(), buf.size(), "\\u00%02x", byte); + escaped_char = {buf.data(), buf.size() - 1}; + } else { + escape_required = false; + } + break; + } + } + if (escape_required) { + dst.append(next_char_to_copy_it, it); + dst += escaped_char; + next_char_to_copy_it = it + 1; + } + }; + + if (false == validate_utf8_string(src, escape_handler)) { + return false; + } + + if (src.cend() != next_char_to_copy_it) { + dst.append(next_char_to_copy_it, src.cend()); + } + + return true; +} +} // namespace clp::ffi diff --git a/components/core/src/clp/ffi/utils.hpp b/components/core/src/clp/ffi/utils.hpp new file mode 100644 index 000000000..26823da9c --- /dev/null +++ b/components/core/src/clp/ffi/utils.hpp @@ -0,0 +1,31 @@ +#ifndef CLP_FFI_UTILS_HPP +#define CLP_FFI_UTILS_HPP + +#include +#include +#include + +namespace clp::ffi { +/** + * Validates whether the given string is UTF-8 encoded, and escapes any characters to make the + * string compatible with the JSON specification. + * @param raw The raw string to escape. + * @return The escaped string on success. + * @return std::nullopt if the string contains any non-UTF-8-encoded byte sequences. + */ +[[nodiscard]] auto validate_and_escape_utf8_string(std::string_view raw +) -> std::optional; + +/** + * Validates whether `src` is UTF-8 encoded, and appends `src` to `dst` while escaping any + * characters to make the appended string compatible with the JSON specification. + * @param src The string to validate and escape. + * @param dst Returns `dst` with an escaped version of `src` appended. + * @return Whether `src` is a valid UTF-8-encoded string. NOTE: Even if `src` is not UTF-8 encoded, + * `dst` may be modified. + */ +[[nodiscard]] auto +validate_and_append_escaped_utf8_string(std::string_view src, std::string& dst) -> bool; +} // namespace clp::ffi + +#endif // CLP_FFI_UTILS_HPP diff --git a/components/core/src/clp/utf8_utils.cpp b/components/core/src/clp/utf8_utils.cpp new file mode 100644 index 000000000..06fafd659 --- /dev/null +++ b/components/core/src/clp/utf8_utils.cpp @@ -0,0 +1,55 @@ +#include "utf8_utils.hpp" + +#include +#include +#include + +namespace clp { +auto is_utf8_encoded(std::string_view str) -> bool { + auto escape_handler = []([[maybe_unused]] std::string_view::const_iterator it) -> void {}; + return validate_utf8_string(str, escape_handler); +} + +namespace utf8_utils_internal { +auto parse_and_validate_lead_byte( + uint8_t byte, + size_t& num_continuation_bytes, + uint32_t& code_point, + uint32_t& code_point_lower_bound, + uint32_t& code_point_upper_bound +) -> bool { + if ((byte & cFourByteUtf8CharHeaderMask) == cFourByteUtf8CharHeader) { + num_continuation_bytes = 3; + code_point = (~cFourByteUtf8CharHeaderMask & byte); + code_point_lower_bound = cFourByteUtf8CharCodePointLowerBound; + code_point_upper_bound = cFourByteUtf8CharCodePointUpperBound; + } else if ((byte & cThreeByteUtf8CharHeaderMask) == cThreeByteUtf8CharHeader) { + num_continuation_bytes = 2; + code_point = (~cThreeByteUtf8CharHeaderMask & byte); + code_point_lower_bound = cThreeByteUtf8CharCodePointLowerBound; + code_point_upper_bound = cThreeByteUtf8CharCodePointUpperBound; + } else if ((byte & cTwoByteUtf8CharHeaderMask) == cTwoByteUtf8CharHeader) { + num_continuation_bytes = 1; + code_point = (~cTwoByteUtf8CharHeaderMask & byte); + code_point_lower_bound = cTwoByteUtf8CharCodePointLowerBound; + code_point_upper_bound = cTwoByteUtf8CharCodePointUpperBound; + } else { + return false; + } + return true; +} + +auto is_ascii_char(uint8_t byte) -> bool { + return cOneByteUtf8CharCodePointUpperBound >= byte; +} + +auto is_valid_utf8_continuation_byte(uint8_t byte) -> bool { + return (byte & cUtf8ContinuationByteMask) == cUtf8ContinuationByteHeader; +} + +auto parse_continuation_byte(uint32_t code_point, uint8_t continuation_byte) -> uint32_t { + return (code_point << cUtf8NumContinuationByteCodePointBits) + + (continuation_byte & cUtf8ContinuationByteCodePointMask); +} +} // namespace utf8_utils_internal +} // namespace clp diff --git a/components/core/src/clp/utf8_utils.hpp b/components/core/src/clp/utf8_utils.hpp new file mode 100644 index 000000000..fe9569b00 --- /dev/null +++ b/components/core/src/clp/utf8_utils.hpp @@ -0,0 +1,144 @@ +#ifndef CLP_UTF8_UTILS_HPP +#define CLP_UTF8_UTILS_HPP + +#include +#include +#include + +namespace clp { +// Constants +// Lead byte signature +constexpr uint8_t cTwoByteUtf8CharHeaderMask{0xE0}; // 0b111x_xxxx +constexpr uint8_t cTwoByteUtf8CharHeader{0xC0}; // 0b110x_xxxx +constexpr uint8_t cThreeByteUtf8CharHeaderMask{0xF0}; // 0b1111_xxxx +constexpr uint8_t cThreeByteUtf8CharHeader{0xE0}; // 0b1110_xxxx +constexpr uint8_t cFourByteUtf8CharHeaderMask{0xF8}; // 0b1111_1xxx +constexpr uint8_t cFourByteUtf8CharHeader{0xF0}; // 0b1111_0xxx + +// Code point ranges (inclusive) +constexpr uint32_t cOneByteUtf8CharCodePointLowerBound{0}; +constexpr uint32_t cOneByteUtf8CharCodePointUpperBound{0x7F}; +constexpr uint32_t cTwoByteUtf8CharCodePointLowerBound{0x80}; +constexpr uint32_t cTwoByteUtf8CharCodePointUpperBound{0x7FF}; +constexpr uint32_t cThreeByteUtf8CharCodePointLowerBound{0x800}; +constexpr uint32_t cThreeByteUtf8CharCodePointUpperBound{0xFFFF}; +constexpr uint32_t cFourByteUtf8CharCodePointLowerBound{0x1'0000}; +constexpr uint32_t cFourByteUtf8CharCodePointUpperBound{0x10'FFFF}; + +// Continuation byte +constexpr uint32_t cUtf8ContinuationByteMask{0xC0}; +constexpr uint32_t cUtf8ContinuationByteHeader{0x80}; +constexpr uint32_t cUtf8ContinuationByteCodePointMask{0x3F}; +constexpr uint8_t cUtf8NumContinuationByteCodePointBits{6}; + +/** + * Validates whether the given string is UTF-8 encoded, optionally escaping ASCII characters using + * the given handler. + * @tparam EscapeHandler Method to optionally escape any ASCII character in the string. + * @param src + * @param escape_handler + * @return Whether the input is a valid UTF-8 encoded string. + */ +template +requires std::is_invocable_v +[[nodiscard]] auto validate_utf8_string(std::string_view src, EscapeHandler escape_handler) -> bool; + +/** + * @param str + * @return Whether the input is a valid UTF-8 encoded string. + */ +[[nodiscard]] auto is_utf8_encoded(std::string_view str) -> bool; + +namespace utf8_utils_internal { +/** + * Validates whether the given byte is a valid lead byte for a multi-byte UTF-8 character, parses + * the byte, and returns the parsed properties as well as associated properties. + * @param byte Byte to validate. + * @param num_continuation_bytes Returns the number of continuation bytes expected. + * @param code_point Returns the code point bits parsed from the lead byte. + * @param code_point_lower_bound Returns the lower bound of the code point range for the UTF-8 + * character. + * @param code_point_upper_bound Returns the upper bound of the code point range for the UTF-8 + * character. + * @return Whether the input byte is a valid lead byte for a multi-byte UTF-8 character. + */ +[[nodiscard]] auto parse_and_validate_lead_byte( + uint8_t byte, + size_t& num_continuation_bytes, + uint32_t& code_point, + uint32_t& code_point_lower_bound, + uint32_t& code_point_upper_bound +) -> bool; + +/** + * @param byte + * @return Whether the given byte is a valid ASCII character. + */ +[[nodiscard]] auto is_ascii_char(uint8_t byte) -> bool; + +/* + * @param byte + * @return Whether the input byte is a valid UTF-8 continuation byte. + */ +[[nodiscard]] auto is_valid_utf8_continuation_byte(uint8_t byte) -> bool; + +/** + * Parses the code-point bits from the given continuation byte and combines them with the given + * code point. + * @param code_point + * @param continuation_byte + * @return The updated code point. + */ +[[nodiscard]] auto +parse_continuation_byte(uint32_t code_point, uint8_t continuation_byte) -> uint32_t; +} // namespace utf8_utils_internal + +template +requires std::is_invocable_v +auto validate_utf8_string(std::string_view src, EscapeHandler escape_handler) -> bool { + size_t num_continuation_bytes_to_validate{0}; + uint32_t code_point{}; + uint32_t code_point_lower_bound{}; + uint32_t code_point_upper_bound{}; + + // NOLINTNEXTLINE(readability-qualified-auto) + for (auto it{src.cbegin()}; it != src.cend(); ++it) { + auto const byte{static_cast(*it)}; + if (0 == num_continuation_bytes_to_validate) { + if (utf8_utils_internal::is_ascii_char(byte)) { + escape_handler(it); + } else if (false + == utf8_utils_internal::parse_and_validate_lead_byte( + byte, + num_continuation_bytes_to_validate, + code_point, + code_point_lower_bound, + code_point_upper_bound + )) + { + return false; + } + } else { + if (false == utf8_utils_internal::is_valid_utf8_continuation_byte(byte)) { + return false; + } + code_point = utf8_utils_internal::parse_continuation_byte(code_point, byte); + --num_continuation_bytes_to_validate; + if (0 == num_continuation_bytes_to_validate + && (code_point < code_point_lower_bound || code_point_upper_bound < code_point)) + { + return false; + } + } + } + + if (0 != num_continuation_bytes_to_validate) { + // Incomplete UTF-8 character + return false; + } + + return true; +} +} // namespace clp + +#endif // CLP_UTF8_UTILS_HPP diff --git a/components/core/tests/test-utf8_utils.cpp b/components/core/tests/test-utf8_utils.cpp new file mode 100644 index 000000000..77324eaf9 --- /dev/null +++ b/components/core/tests/test-utf8_utils.cpp @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../src/clp/ffi/utils.hpp" +#include "../src/clp/utf8_utils.hpp" + +using clp::ffi::validate_and_escape_utf8_string; +using clp::is_utf8_encoded; + +namespace { +/** + * @param raw + * @return The input string after escaping any characters that are invalid in JSON strings. + */ +[[nodiscard]] auto get_expected_escaped_string(std::string_view raw) -> std::string; + +/** + * Generates a UTF-8 encoded byte sequence with the given code point and number of continuation + * bytes. The range of the code point is not validated, which means the generated byte sequence can + * be invalid (overlong or exceeding the valid range of UTF-8 code points). + * @param code_point + * @param num_continuation_bytes + * @return The encoded UTF-8 byte sequence. + */ +[[nodiscard]] auto +generate_utf8_byte_sequence(uint32_t code_point, size_t num_continuation_bytes) -> std::string; + +auto get_expected_escaped_string(std::string_view raw) -> std::string { + nlohmann::json const json_str = raw; // Don't use '{}' initializer + auto const dumped_str{json_str.dump()}; + // Strip the quotes that nlohmann::json adds + return {dumped_str.begin() + 1, dumped_str.end() - 1}; +} + +auto generate_utf8_byte_sequence(uint32_t code_point, size_t num_continuation_bytes) + -> std::string { + REQUIRE((1 <= num_continuation_bytes && num_continuation_bytes <= 3)); + std::vector encoded_bytes; + while (encoded_bytes.size() < num_continuation_bytes) { + auto const least_significant_byte{static_cast(code_point)}; + encoded_bytes.push_back(static_cast( + (least_significant_byte & ~clp::cUtf8ContinuationByteMask) + | clp::cUtf8ContinuationByteHeader + )); + code_point >>= clp::cUtf8NumContinuationByteCodePointBits; + } + + uint8_t lead_byte_code_point_mask{}; + uint8_t lead_byte_header{}; + if (1 == num_continuation_bytes) { + lead_byte_code_point_mask = static_cast(~clp::cTwoByteUtf8CharHeaderMask); + lead_byte_header = clp::cTwoByteUtf8CharHeader; + } else if (2 == num_continuation_bytes) { + lead_byte_code_point_mask = static_cast(~clp::cThreeByteUtf8CharHeaderMask); + lead_byte_header = clp::cThreeByteUtf8CharHeader; + } else { // 3 == num_continuation_bytes + lead_byte_code_point_mask = static_cast(~clp::cFourByteUtf8CharHeaderMask); + lead_byte_header = clp::cFourByteUtf8CharHeader; + } + encoded_bytes.push_back(static_cast( + (static_cast(code_point) & lead_byte_code_point_mask) | lead_byte_header + )); + + return {encoded_bytes.rbegin(), encoded_bytes.rend()}; +} +} // namespace + +TEST_CASE("escape_utf8_string_basic", "[utf8_utils]") { + std::string test_str; + std::optional actual; + + // Test empty string + actual = validate_and_escape_utf8_string(test_str); + REQUIRE((actual.has_value() && actual.value() == get_expected_escaped_string(test_str))); + + // Test string that has nothing to escape + test_str = "This string has nothing to escape :)"; + actual = validate_and_escape_utf8_string(test_str); + REQUIRE((actual.has_value() && actual.value() == get_expected_escaped_string(test_str))); + + // Test string with all single byte UTF-8 characters, including those we escape. + test_str.clear(); + for (uint8_t i{0}; i <= static_cast(INT8_MAX); ++i) { + test_str.push_back(static_cast(i)); + } + // Shuffle characters randomly + // NOLINTNEXTLINE(cert-msc32-c, cert-msc51-cpp) + std::shuffle(test_str.begin(), test_str.end(), std::default_random_engine{}); + actual = validate_and_escape_utf8_string(test_str); + REQUIRE((actual.has_value() && actual.value() == get_expected_escaped_string(test_str))); + + // Test valid UTF-8 chars with continuation bytes + std::vector const valid_utf8{ + "\n", + "\xF0\xA0\x80\x8F", // https://en.wiktionary.org/wiki/%F0%A0%80%8F + "a", + "\xE4\xB8\xAD", // https://en.wiktionary.org/wiki/%E4%B8%AD + "\x1F", + "\xC2\xA2", // ¢ + "\\" + }; + test_str.clear(); + for (auto const& str : valid_utf8) { + test_str.append(str); + } + actual = validate_and_escape_utf8_string(test_str); + REQUIRE((actual.has_value() && actual.value() == get_expected_escaped_string(test_str))); +} + +TEST_CASE("escape_utf8_string_with_invalid_continuation", "[utf8_utils]") { + std::string test_str; + + auto const valid_utf8_byte_sequence = GENERATE( + generate_utf8_byte_sequence(0x80, 1), + generate_utf8_byte_sequence(0x800, 2), + generate_utf8_byte_sequence(0x1'0000, 3) + ); + + // Test incomplete continuation bytes + auto const begin_it{valid_utf8_byte_sequence.cbegin()}; + std::string const valid{"Valid"}; + for (auto end_it{valid_utf8_byte_sequence.cend() - 1}; + valid_utf8_byte_sequence.cbegin() != end_it; + --end_it) + { + std::string const incomplete_byte_sequence{begin_it, end_it}; + + test_str = valid + incomplete_byte_sequence; + REQUIRE((false == is_utf8_encoded(test_str))); + REQUIRE((false == validate_and_escape_utf8_string(test_str).has_value())); + + test_str = incomplete_byte_sequence + valid; + REQUIRE((false == is_utf8_encoded(test_str))); + REQUIRE((false == validate_and_escape_utf8_string(test_str).has_value())); + } + + // Test invalid lead byte + test_str = valid_utf8_byte_sequence; + constexpr char cInvalidLeadByte{'\xFF'}; + test_str.front() = cInvalidLeadByte; + REQUIRE((false == is_utf8_encoded(test_str))); + REQUIRE((false == validate_and_escape_utf8_string(test_str).has_value())); + + // Test invalid continuation bytes + for (size_t idx{1}; idx < valid_utf8_byte_sequence.size(); ++idx) { + test_str = valid_utf8_byte_sequence; + constexpr uint8_t cInvalidContinuationByteMask{0x40}; + test_str.at(idx) |= cInvalidContinuationByteMask; + REQUIRE((false == is_utf8_encoded(test_str))); + REQUIRE((false == validate_and_escape_utf8_string(test_str).has_value())); + } +} + +TEST_CASE("validate_utf8_code_point_ranges", "[utf8_utils]") { + // Test 1 byte encoding code point range + for (auto code_point{clp::cOneByteUtf8CharCodePointLowerBound}; + code_point <= clp::cOneByteUtf8CharCodePointUpperBound; + ++code_point) + { + REQUIRE(is_utf8_encoded(std::string{static_cast(code_point)})); + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 1)))); + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 2)))); + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 3)))); + } + + // Test 2 byte encoding code point range + for (auto code_point{clp::cTwoByteUtf8CharCodePointLowerBound}; + code_point <= clp::cTwoByteUtf8CharCodePointUpperBound; + ++code_point) + { + REQUIRE(is_utf8_encoded(generate_utf8_byte_sequence(code_point, 1))); + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 2)))); + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 3)))); + } + + // Test 3 byte encoding code point range + for (auto code_point{clp::cThreeByteUtf8CharCodePointLowerBound}; + code_point <= clp::cThreeByteUtf8CharCodePointUpperBound; + ++code_point) + { + REQUIRE(is_utf8_encoded(generate_utf8_byte_sequence(code_point, 2))); + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 3)))); + } + + // Test 4 byte encoding code point range + for (auto code_point{clp::cFourByteUtf8CharCodePointLowerBound}; + code_point <= clp::cFourByteUtf8CharCodePointUpperBound; + ++code_point) + { + REQUIRE(is_utf8_encoded(generate_utf8_byte_sequence(code_point, 3))); + } + + // Test 4 byte encoding code point out of range + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + for (auto code_point{clp::cFourByteUtf8CharCodePointUpperBound + 1}; code_point <= 0x1F'FFFF; + ++code_point) + { + REQUIRE((false == is_utf8_encoded(generate_utf8_byte_sequence(code_point, 3)))); + } +} From 9ba04514e00cd32e36e724515c7ae8d1e2fb7da4 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Thu, 27 Jun 2024 22:25:48 -0400 Subject: [PATCH 017/114] clp-package: Add handling for IR extraction jobs to the query scheduler and workers. (#460) --- .../clp_package_utils/general.py | 15 ++ .../clp_package_utils/scripts/start_clp.py | 37 ++- .../clp-py-utils/clp_py_utils/clp_config.py | 44 +++- .../executor/query/celeryconfig.py | 6 +- .../executor/query/extract_ir_task.py | 115 +++++++++ .../executor/query/fs_search_task.py | 174 ++++---------- .../job_orchestration/executor/query/utils.py | 135 +++++++++++ .../job_orchestration/scheduler/constants.py | 1 + .../job_orchestration/scheduler/job_config.py | 7 + .../scheduler/query/query_scheduler.py | 227 ++++++++++++++++-- .../scheduler/scheduler_data.py | 17 +- .../package-template/src/etc/clp-config.yml | 10 +- .../webui/imports/api/search/constants.js | 1 + docs/src/dev-guide/components-webui.md | 2 +- 14 files changed, 625 insertions(+), 166 deletions(-) create mode 100644 components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py create mode 100644 components/job-orchestration/job_orchestration/executor/query/utils.py diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index 29c421109..ce0f10309 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -69,6 +69,7 @@ def __init__(self, clp_home: pathlib.Path, docker_clp_home: pathlib.Path): self.data_dir: typing.Optional[DockerMount] = None self.logs_dir: typing.Optional[DockerMount] = None self.archives_output_dir: typing.Optional[DockerMount] = None + self.ir_output_dir: typing.Optional[DockerMount] = None def get_clp_home(): @@ -224,6 +225,19 @@ def generate_container_config(clp_config: CLPConfig, clp_home: pathlib.Path): container_clp_config.archive_output.directory, ) + container_clp_config.ir_output.directory = pathlib.Path("/") / "mnt" / "ir-output" + if not is_path_already_mounted( + clp_home, + CONTAINER_CLP_HOME, + clp_config.ir_output.directory, + container_clp_config.ir_output.directory, + ): + docker_mounts.ir_output_dir = DockerMount( + DockerMountType.BIND, + clp_config.ir_output.directory, + container_clp_config.ir_output.directory, + ) + return container_clp_config, docker_mounts @@ -391,6 +405,7 @@ def validate_results_cache_config( def validate_worker_config(clp_config: CLPConfig): clp_config.validate_input_logs_dir() clp_config.validate_archive_output_dir() + clp_config.validate_ir_output_dir() def validate_webui_config( diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index a798d2112..5ba5bbe15 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -8,8 +8,8 @@ import subprocess import sys import time -import typing import uuid +from typing import Any, Dict, List, Optional import yaml from clp_py_utils.clp_config import ( @@ -526,6 +526,8 @@ def start_compression_worker( clp_config.redis.compression_backend_database, num_cpus, mounts, + None, + None, ) @@ -538,6 +540,13 @@ def start_query_worker( ): celery_method = "job_orchestration.executor.query" celery_route = f"{QueueName.QUERY}" + + query_worker_mount = [mounts.ir_output_dir] + query_worker_env = { + "CLP_IR_OUTPUT_DIR": container_clp_config.ir_output.directory, + "CLP_IR_COLLECTION": clp_config.results_cache.ir_collection_name, + } + generic_start_worker( QUERY_WORKER_COMPONENT_NAME, instance_id, @@ -549,6 +558,8 @@ def start_query_worker( clp_config.redis.query_backend_database, num_cpus, mounts, + query_worker_env, + query_worker_mount, ) @@ -563,6 +574,8 @@ def generic_start_worker( redis_database: int, num_cpus: int, mounts: CLPDockerMounts, + worker_specific_env: Dict[str, Any], + worker_specific_mount: List[Optional[DockerMount]], ): logger.info(f"Starting {component_name}...") @@ -578,6 +591,7 @@ def generic_start_worker( # Create necessary directories clp_config.archive_output.directory.mkdir(parents=True, exist_ok=True) + clp_config.ir_output.directory.mkdir(parents=True, exist_ok=True) clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" # fmt: off @@ -605,19 +619,28 @@ def generic_start_worker( "-e", f"CLP_LOGGING_LEVEL={worker_config.logging_level}", "-e", f"CLP_STORAGE_ENGINE={clp_config.package.storage_engine}", "-u", f"{os.getuid()}:{os.getgid()}", - "--mount", str(mounts.clp_home), ] + if worker_specific_env: + for env_name, env_value in worker_specific_env.items(): + container_start_cmd.append("-e") + container_start_cmd.append(f"{env_name}={env_value}") + # fmt: on necessary_mounts = [ + mounts.clp_home, mounts.data_dir, mounts.logs_dir, mounts.archives_output_dir, mounts.input_logs_dir, ] + if worker_specific_mount: + necessary_mounts.extend(worker_specific_mount) + for mount in necessary_mounts: - if mount: - container_start_cmd.append("--mount") - container_start_cmd.append(str(mount)) + if not mount: + raise ValueError(f"Required mount configuration is empty: {necessary_mounts}") + container_start_cmd.append("--mount") + container_start_cmd.append(str(mount)) container_start_cmd.append(clp_config.execution_container) worker_cmd = [ @@ -645,8 +668,8 @@ def generic_start_worker( def update_meteor_settings( parent_key_prefix: str, - settings: typing.Dict[str, typing.Any], - updates: typing.Dict[str, typing.Any], + settings: Dict[str, Any], + updates: Dict[str, Any], ): """ Recursively updates the given Meteor settings object with the values from `updates`. diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index b3410925e..0c0ce6893 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -254,7 +254,8 @@ def validate_upsert_interval(cls, field): class ResultsCache(BaseModel): host: str = "localhost" port: int = 27017 - db_name: str = "clp-search" + db_name: str = "clp-query-results" + ir_collection_name: str = "ir-files" @validator("host") def validate_host(cls, field): @@ -268,6 +269,12 @@ def validate_db_name(cls, field): raise ValueError(f"{RESULTS_CACHE_COMPONENT_NAME}.db_name cannot be empty.") return field + @validator("ir_collection_name") + def validate_ir_collection_name(cls, field): + if "" == field: + raise ValueError(f"{RESULTS_CACHE_COMPONENT_NAME}.ir_collection_name cannot be empty.") + return field + def get_uri(self): return f"mongodb://{self.host}:{self.port}/{self.db_name}" @@ -321,6 +328,32 @@ def dump_to_primitive_dict(self): return d +class IrOutput(BaseModel): + directory: pathlib.Path = pathlib.Path("var") / "data" / "ir" + target_uncompressed_size: int = 128 * 1024 * 1024 + + @validator("directory") + def validate_directory(cls, field): + if "" == field: + raise ValueError("directory can not be empty") + return field + + @validator("target_uncompressed_size") + def validate_target_uncompressed_size(cls, field): + if field <= 0: + raise ValueError("target_uncompressed_size must be greater than 0") + return field + + def make_config_paths_absolute(self, clp_home: pathlib.Path): + self.directory = make_config_path_absolute(clp_home, self.directory) + + def dump_to_primitive_dict(self): + d = self.dict() + # Turn directory (pathlib.Path) into a primitive string + d["directory"] = str(d["directory"]) + return d + + class WebUi(BaseModel): host: str = "localhost" port: int = 4000 @@ -368,6 +401,7 @@ class CLPConfig(BaseModel): credentials_file_path: pathlib.Path = CLP_DEFAULT_CREDENTIALS_FILE_PATH archive_output: ArchiveOutput = ArchiveOutput() + ir_output: IrOutput = IrOutput() data_directory: pathlib.Path = pathlib.Path("var") / "data" logs_directory: pathlib.Path = pathlib.Path("var") / "log" @@ -377,6 +411,7 @@ def make_config_paths_absolute(self, clp_home: pathlib.Path): self.input_logs_directory = make_config_path_absolute(clp_home, self.input_logs_directory) self.credentials_file_path = make_config_path_absolute(clp_home, self.credentials_file_path) self.archive_output.make_config_paths_absolute(clp_home) + self.ir_output.make_config_paths_absolute(clp_home) self.data_directory = make_config_path_absolute(clp_home, self.data_directory) self.logs_directory = make_config_path_absolute(clp_home, self.logs_directory) self._os_release_file_path = make_config_path_absolute(clp_home, self._os_release_file_path) @@ -396,6 +431,12 @@ def validate_archive_output_dir(self): except ValueError as ex: raise ValueError(f"archive_output.directory is invalid: {ex}") + def validate_ir_output_dir(self): + try: + validate_path_could_be_dir(self.ir_output.directory) + except ValueError as ex: + raise ValueError(f"ir_output.directory is invalid: {ex}") + def validate_data_dir(self): try: validate_path_could_be_dir(self.data_directory) @@ -463,6 +504,7 @@ def load_redis_credentials_from_file(self): def dump_to_primitive_dict(self): d = self.dict() d["archive_output"] = self.archive_output.dump_to_primitive_dict() + d["ir_output"] = self.ir_output.dump_to_primitive_dict() # Turn paths into primitive strings d["input_logs_directory"] = str(self.input_logs_directory) d["credentials_file_path"] = str(self.credentials_file_path) diff --git a/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py b/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py index 4b9949091..994c0bbcf 100644 --- a/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py +++ b/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py @@ -2,10 +2,14 @@ from job_orchestration.scheduler.constants import QueueName -imports = "job_orchestration.executor.query.fs_search_task" +imports = ( + "job_orchestration.executor.query.fs_search_task", + "job_orchestration.executor.query.extract_ir_task", +) task_routes = { "job_orchestration.executor.query.fs_search_task.search": QueueName.QUERY, + "job_orchestration.executor.query.extract_ir_task.extract_ir": QueueName.QUERY, } task_create_missing_queues = True diff --git a/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py b/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py new file mode 100644 index 000000000..b04b809f3 --- /dev/null +++ b/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py @@ -0,0 +1,115 @@ +import datetime +import os +from pathlib import Path +from typing import Any, Dict, List, Optional + +from celery.app.task import Task +from celery.utils.log import get_task_logger +from clp_py_utils.clp_config import Database, StorageEngine +from clp_py_utils.clp_logging import set_logging_level +from clp_py_utils.sql_adapter import SQL_Adapter +from job_orchestration.executor.query.celery import app +from job_orchestration.executor.query.utils import ( + report_command_creation_failure, + run_query_task, +) +from job_orchestration.scheduler.job_config import ExtractIrJobConfig +from job_orchestration.scheduler.scheduler_data import QueryTaskStatus + +# Setup logging +logger = get_task_logger(__name__) + + +def make_command( + storage_engine: str, + clp_home: Path, + archives_dir: Path, + archive_id: str, + ir_output_dir: Path, + extract_ir_config: ExtractIrJobConfig, + results_cache_uri: str, + ir_collection: str, +) -> Optional[List[str]]: + if StorageEngine.CLP == storage_engine: + if not extract_ir_config.file_split_id: + logger.error("file_split_id not supplied") + return None + command = [ + str(clp_home / "bin" / "clo"), + "i", + str(archives_dir / archive_id), + extract_ir_config.file_split_id, + str(ir_output_dir), + results_cache_uri, + ir_collection, + ] + if extract_ir_config.target_uncompressed_size is not None: + command.append("--target-size") + command.append(extract_ir_config.target_uncompressed_size) + else: + logger.error(f"Unsupported storage engine {storage_engine}") + return None + + return command + + +@app.task(bind=True) +def extract_ir( + self: Task, + job_id: str, + task_id: int, + job_config_obj: dict, + archive_id: str, + clp_metadata_db_conn_params: dict, + results_cache_uri: str, +) -> Dict[str, Any]: + task_name = "IR extraction" + + # Setup logging to file + clp_logs_dir = Path(os.getenv("CLP_LOGS_DIR")) + clp_logging_level = os.getenv("CLP_LOGGING_LEVEL") + set_logging_level(logger, clp_logging_level) + + logger.info(f"Started {task_name} task for job {job_id}") + + start_time = datetime.datetime.now() + task_status: QueryTaskStatus + sql_adapter = SQL_Adapter(Database.parse_obj(clp_metadata_db_conn_params)) + + # Make task_command + clp_home = Path(os.getenv("CLP_HOME")) + archive_directory = Path(os.getenv("CLP_ARCHIVE_OUTPUT_DIR")) + clp_storage_engine = os.getenv("CLP_STORAGE_ENGINE") + ir_output_dir = Path(os.getenv("CLP_IR_OUTPUT_DIR")) + ir_collection = os.getenv("CLP_IR_COLLECTION") + extract_ir_config = ExtractIrJobConfig.parse_obj(job_config_obj) + + task_command = make_command( + storage_engine=clp_storage_engine, + clp_home=clp_home, + archives_dir=archive_directory, + archive_id=archive_id, + ir_output_dir=ir_output_dir, + extract_ir_config=extract_ir_config, + results_cache_uri=results_cache_uri, + ir_collection=ir_collection, + ) + if not task_command: + return report_command_creation_failure( + sql_adapter=sql_adapter, + logger=logger, + task_name=task_name, + task_id=task_id, + start_time=start_time, + ) + + return run_query_task( + sql_adapter=sql_adapter, + logger=logger, + clp_logs_dir=clp_logs_dir, + task_command=task_command, + task_name=task_name, + job_id=job_id, + task_id=task_id, + start_time=start_time, + ) diff --git a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py index 81ff757a2..baafca3e2 100644 --- a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py @@ -1,41 +1,25 @@ import datetime import os -import signal -import subprocess -import sys -from contextlib import closing from pathlib import Path -from typing import Any, Dict +from typing import Any, Dict, List, Optional from celery.app.task import Task from celery.utils.log import get_task_logger -from clp_py_utils.clp_config import Database, QUERY_TASKS_TABLE_NAME, StorageEngine +from clp_py_utils.clp_config import Database, StorageEngine from clp_py_utils.clp_logging import set_logging_level from clp_py_utils.sql_adapter import SQL_Adapter from job_orchestration.executor.query.celery import app +from job_orchestration.executor.query.utils import ( + report_command_creation_failure, + run_query_task, +) from job_orchestration.scheduler.job_config import SearchJobConfig -from job_orchestration.scheduler.scheduler_data import QueryTaskResult, QueryTaskStatus +from job_orchestration.scheduler.scheduler_data import QueryTaskStatus # Setup logging logger = get_task_logger(__name__) -def update_search_task_metadata( - db_cursor, - task_id: int, - kv_pairs: Dict[str, Any], -): - if not kv_pairs or len(kv_pairs) == 0: - raise ValueError("No key-value pairs provided to update search task metadata") - - query = f""" - UPDATE {QUERY_TASKS_TABLE_NAME} - SET {', '.join([f'{k}="{v}"' for k, v in kv_pairs.items()])} - WHERE id = {task_id} - """ - db_cursor.execute(query) - - def make_command( storage_engine: str, clp_home: Path, @@ -44,7 +28,7 @@ def make_command( search_config: SearchJobConfig, results_cache_uri: str, results_collection: str, -): +) -> Optional[List[str]]: if StorageEngine.CLP == storage_engine: command = [str(clp_home / "bin" / "clo"), "s", str(archives_dir / archive_id)] if search_config.path_filter is not None: @@ -59,7 +43,8 @@ def make_command( archive_id, ] else: - raise ValueError(f"Unsupported storage engine {storage_engine}") + logger.error(f"Unsupported storage engine {storage_engine}") + return None command.append(search_config.query_string) if search_config.begin_timestamp is not None: @@ -118,119 +103,50 @@ def search( clp_metadata_db_conn_params: dict, results_cache_uri: str, ) -> Dict[str, Any]: - clp_home = Path(os.getenv("CLP_HOME")) - archive_directory = Path(os.getenv("CLP_ARCHIVE_OUTPUT_DIR")) - clp_logs_dir = Path(os.getenv("CLP_LOGS_DIR")) - clp_logging_level = str(os.getenv("CLP_LOGGING_LEVEL")) - clp_storage_engine = str(os.getenv("CLP_STORAGE_ENGINE")) + task_name = "search" # Setup logging to file - worker_logs_dir = clp_logs_dir / job_id - worker_logs_dir.mkdir(exist_ok=True, parents=True) + clp_logs_dir = Path(os.getenv("CLP_LOGS_DIR")) + clp_logging_level = os.getenv("CLP_LOGGING_LEVEL") set_logging_level(logger, clp_logging_level) - clo_log_path = worker_logs_dir / f"{task_id}-clo.log" - clo_log_file = open(clo_log_path, "w") - logger.info(f"Started task for job {job_id}") + logger.info(f"Started {task_name} task for job {job_id}") - search_config = SearchJobConfig.parse_obj(job_config_obj) + start_time = datetime.datetime.now() + task_status: QueryTaskStatus sql_adapter = SQL_Adapter(Database.parse_obj(clp_metadata_db_conn_params)) - start_time = datetime.datetime.now() - search_status = QueryTaskStatus.RUNNING - with closing(sql_adapter.create_connection(True)) as db_conn, closing( - db_conn.cursor(dictionary=True) - ) as db_cursor: - try: - search_command = make_command( - storage_engine=clp_storage_engine, - clp_home=clp_home, - archives_dir=archive_directory, - archive_id=archive_id, - search_config=search_config, - results_cache_uri=results_cache_uri, - results_collection=job_id, - ) - except ValueError as e: - error_message = f"Error creating search command: {e}" - logger.error(error_message) - - update_search_task_metadata( - db_cursor, - task_id, - dict(status=QueryTaskStatus.FAILED, duration=0, start_time=start_time), - ) - db_conn.commit() - clo_log_file.write(error_message) - clo_log_file.close() - - return QueryTaskResult( - task_id=task_id, - status=QueryTaskStatus.FAILED, - duration=0, - error_log_path=str(clo_log_path), - ).dict() - - update_search_task_metadata( - db_cursor, task_id, dict(status=search_status, start_time=start_time) - ) - db_conn.commit() - - logger.info(f'Running: {" ".join(search_command)}') - search_proc = subprocess.Popen( - search_command, - preexec_fn=os.setpgrp, - close_fds=True, - stdout=clo_log_file, - stderr=clo_log_file, - ) + # Make task_command + clp_home = Path(os.getenv("CLP_HOME")) + archive_directory = Path(os.getenv("CLP_ARCHIVE_OUTPUT_DIR")) + clp_storage_engine = os.getenv("CLP_STORAGE_ENGINE") + search_config = SearchJobConfig.parse_obj(job_config_obj) - def sigterm_handler(_signo, _stack_frame): - logger.debug("Entered sigterm handler") - if search_proc.poll() is None: - logger.debug("Trying to kill search process") - # Kill the process group in case the search process also forked - os.killpg(os.getpgid(search_proc.pid), signal.SIGTERM) - os.waitpid(search_proc.pid, 0) - logger.info(f"Cancelling search task.") - # Add 128 to follow convention for exit codes from signals - # https://tldp.org/LDP/abs/html/exitcodes.html#AEN23549 - sys.exit(_signo + 128) - - # Register the function to kill the child process at exit - signal.signal(signal.SIGTERM, sigterm_handler) - - logger.info("Waiting for search to finish") - # communicate is equivalent to wait in this case, but avoids deadlocks if we switch to piping - # stdout/stderr in the future. - search_proc.communicate() - return_code = search_proc.returncode - if 0 != return_code: - search_status = QueryTaskStatus.FAILED - logger.error(f"Failed search task for job {job_id} - return_code={return_code}") - else: - search_status = QueryTaskStatus.SUCCEEDED - logger.info(f"Search task completed for job {job_id}") - - # Close log files - clo_log_file.close() - duration = (datetime.datetime.now() - start_time).total_seconds() - - with closing(sql_adapter.create_connection(True)) as db_conn, closing( - db_conn.cursor(dictionary=True) - ) as db_cursor: - update_search_task_metadata( - db_cursor, task_id, dict(status=search_status, start_time=start_time, duration=duration) + task_command = make_command( + storage_engine=clp_storage_engine, + clp_home=clp_home, + archives_dir=archive_directory, + archive_id=archive_id, + search_config=search_config, + results_cache_uri=results_cache_uri, + results_collection=str(task_id), + ) + if not task_command: + return report_command_creation_failure( + sql_adapter=sql_adapter, + logger=logger, + task_name=task_name, + task_id=task_id, + start_time=start_time, ) - db_conn.commit() - search_task_result = QueryTaskResult( - status=search_status, + return run_query_task( + sql_adapter=sql_adapter, + logger=logger, + clp_logs_dir=clp_logs_dir, + task_command=task_command, + task_name=task_name, + job_id=job_id, task_id=task_id, - duration=duration, + start_time=start_time, ) - - if QueryTaskStatus.FAILED == search_status: - search_task_result.error_log_path = str(clo_log_path) - - return search_task_result.dict() diff --git a/components/job-orchestration/job_orchestration/executor/query/utils.py b/components/job-orchestration/job_orchestration/executor/query/utils.py new file mode 100644 index 000000000..69d22398e --- /dev/null +++ b/components/job-orchestration/job_orchestration/executor/query/utils.py @@ -0,0 +1,135 @@ +import datetime +import os +import signal +import subprocess +import sys +from contextlib import closing +from logging import Logger +from pathlib import Path +from typing import Any, Dict, List + +from clp_py_utils.clp_config import QUERY_TASKS_TABLE_NAME +from clp_py_utils.sql_adapter import SQL_Adapter +from job_orchestration.scheduler.scheduler_data import QueryTaskResult, QueryTaskStatus + + +def get_task_log_file_path(clp_logs_dir: Path, job_id: str, task_id: int) -> Path: + worker_logs_dir = clp_logs_dir / job_id + worker_logs_dir.mkdir(exist_ok=True, parents=True) + return worker_logs_dir / f"{task_id}-clo.log" + + +def report_command_creation_failure( + sql_adapter: SQL_Adapter, + logger: Logger, + task_name: str, + task_id: int, + start_time: datetime.datetime, +): + logger.error(f"Error creating {task_name} command") + task_status = QueryTaskStatus.FAILED + update_query_task_metadata( + sql_adapter, + task_id, + dict(status=task_status, duration=0, start_time=start_time), + ) + + return QueryTaskResult( + task_id=task_id, + status=task_status, + duration=0, + ).dict() + + +def run_query_task( + sql_adapter: SQL_Adapter, + logger: Logger, + clp_logs_dir: Path, + task_command: List[str], + task_name: str, + job_id: str, + task_id: int, + start_time: datetime.datetime, +): + clo_log_path = get_task_log_file_path(clp_logs_dir, job_id, task_id) + clo_log_file = open(clo_log_path, "w") + + task_status = QueryTaskStatus.RUNNING + update_query_task_metadata( + sql_adapter, task_id, dict(status=task_status, start_time=start_time) + ) + + logger.info(f'Running: {" ".join(task_command)}') + task_proc = subprocess.Popen( + task_command, + preexec_fn=os.setpgrp, + close_fds=True, + stdout=clo_log_file, + stderr=clo_log_file, + ) + + def sigterm_handler(_signo, _stack_frame): + logger.debug("Entered sigterm handler") + if task_proc.poll() is None: + logger.debug(f"Trying to kill {task_name} process") + # Kill the process group in case the task process also forked + os.killpg(os.getpgid(task_proc.pid), signal.SIGTERM) + os.waitpid(task_proc.pid, 0) + logger.info(f"Cancelling {task_name} task.") + # Add 128 to follow convention for exit codes from signals + # https://tldp.org/LDP/abs/html/exitcodes.html#AEN23549 + sys.exit(_signo + 128) + + # Register the function to kill the child process at exit + signal.signal(signal.SIGTERM, sigterm_handler) + + logger.info(f"Waiting for {task_name} to finish") + # `communicate` is equivalent to `wait` in this case, but avoids deadlocks if we switch to + # piping stdout/stderr in the future. + task_proc.communicate() + return_code = task_proc.returncode + if 0 != return_code: + task_status = QueryTaskStatus.FAILED + logger.error( + f"{task_name} task {task_id} failed for job {job_id} - return_code={return_code}" + ) + else: + task_status = QueryTaskStatus.SUCCEEDED + logger.info(f"{task_name} task {task_id} completed for job {job_id}") + + clo_log_file.close() + duration = (datetime.datetime.now() - start_time).total_seconds() + + update_query_task_metadata( + sql_adapter, task_id, dict(status=task_status, start_time=start_time, duration=duration) + ) + + task_result = QueryTaskResult( + status=task_status, + task_id=task_id, + duration=duration, + ) + + if QueryTaskStatus.FAILED == task_status: + task_result.error_log_path = str(clo_log_path) + + return task_result.dict() + + +def update_query_task_metadata( + sql_adapter: SQL_Adapter, + task_id: int, + kv_pairs: Dict[str, Any], +): + with closing(sql_adapter.create_connection(True)) as db_conn, closing( + db_conn.cursor(dictionary=True) + ) as db_cursor: + if not kv_pairs or len(kv_pairs) == 0: + raise ValueError("No key-value pairs provided to update query task metadata") + + query = f""" + UPDATE {QUERY_TASKS_TABLE_NAME} + SET {', '.join([f'{k}="{v}"' for k, v in kv_pairs.items()])} + WHERE id = {task_id} + """ + db_cursor.execute(query) diff --git a/components/job-orchestration/job_orchestration/scheduler/constants.py b/components/job-orchestration/job_orchestration/scheduler/constants.py index b640524d9..131719148 100644 --- a/components/job-orchestration/job_orchestration/scheduler/constants.py +++ b/components/job-orchestration/job_orchestration/scheduler/constants.py @@ -71,6 +71,7 @@ def to_str(self) -> str: class QueryJobType(IntEnum): SEARCH_OR_AGGREGATION = 0 + EXTRACT_IR = auto() def __str__(self) -> str: return str(self.value) diff --git a/components/job-orchestration/job_orchestration/scheduler/job_config.py b/components/job-orchestration/job_orchestration/scheduler/job_config.py index 528dce21a..e90e2ee7f 100644 --- a/components/job-orchestration/job_orchestration/scheduler/job_config.py +++ b/components/job-orchestration/job_orchestration/scheduler/job_config.py @@ -42,6 +42,13 @@ class AggregationConfig(BaseModel): class QueryJobConfig(BaseModel): ... +class ExtractIrJobConfig(QueryJobConfig): + orig_file_id: str + msg_ix: int + file_split_id: typing.Optional[str] = None + target_uncompressed_size: typing.Optional[int] = None + + class SearchJobConfig(QueryJobConfig): query_string: str max_num_results: int diff --git a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py index 5331051ae..015480662 100644 --- a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py +++ b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py @@ -24,7 +24,7 @@ import pathlib import sys from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Tuple import celery import msgpack @@ -39,9 +39,10 @@ from clp_py_utils.core import read_yaml_config_file from clp_py_utils.decorators import exception_default_value from clp_py_utils.sql_adapter import SQL_Adapter +from job_orchestration.executor.query.extract_ir_task import extract_ir from job_orchestration.executor.query.fs_search_task import search from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType, QueryTaskStatus -from job_orchestration.scheduler.job_config import SearchJobConfig +from job_orchestration.scheduler.job_config import ExtractIrJobConfig, SearchJobConfig from job_orchestration.scheduler.query.reducer_handler import ( handle_reducer_connection, ReducerHandlerMessage, @@ -49,6 +50,7 @@ ReducerHandlerMessageType, ) from job_orchestration.scheduler.scheduler_data import ( + ExtractIrJob, InternalJobState, QueryJob, QueryTaskResult, @@ -277,6 +279,57 @@ def get_archives_for_search( return archives_for_search +def get_archive_and_file_split_ids_for_extraction( + db_conn, + extract_ir_config: ExtractIrJobConfig, +) -> Tuple[Optional[str], Optional[str]]: + orig_file_id = extract_ir_config.orig_file_id + msg_ix = extract_ir_config.msg_ix + + results = get_archive_and_file_split_ids(db_conn, orig_file_id, msg_ix) + if len(results) == 0: + logger.error(f"No matching file splits for orig_file_id={orig_file_id}, msg_ix={msg_ix}") + return None, None + elif len(results) > 1: + logger.error(f"Multiple file splits found for orig_file_id={orig_file_id}, msg_ix={msg_ix}") + for result in results: + logger.error(f"{result['archive_id']}:{result['id']}") + return None, None + + return results[0]["archive_id"], results[0]["file_split_id"] + + +@exception_default_value(default=[]) +def get_archive_and_file_split_ids( + db_conn, + orig_file_id: str, + msg_ix: int, +): + """ + Fetches the IDs of the file split and the archive containing the file split based on the + following criteria: + 1. The file split's original file id = `orig_file_id` + 2. The file split includes the message with index = `msg_ix` + :param db_conn: + :param orig_file_id: Original file id of the split + :param msg_ix: Index of the message that the file split must include + :return: A list of (archive id, file split id) on success. An empty list if + an exception occurs while interacting with the database. + """ + + query = f"""SELECT archive_id, id as file_split_id + FROM {CLP_METADATA_TABLE_PREFIX}files WHERE + orig_file_id = '{orig_file_id}' AND + begin_message_ix <= {msg_ix} AND + (begin_message_ix + num_messages) > {msg_ix} + """ + + with contextlib.closing(db_conn.cursor(dictionary=True)) as cursor: + cursor.execute(query) + results = list(cursor.fetchall()) + return results + + def get_task_group_for_job( archive_ids: List[str], task_ids: List[int], @@ -285,17 +338,35 @@ def get_task_group_for_job( results_cache_uri: str, ): job_config_obj = job.get_config().dict() - return celery.group( - search.s( - job_id=job.id, - archive_id=archive_ids[i], - task_id=task_ids[i], - job_config_obj=job_config_obj, - clp_metadata_db_conn_params=clp_metadata_db_conn_params, - results_cache_uri=results_cache_uri, + job_type = job.get_type() + if QueryJobType.SEARCH_OR_AGGREGATION == job_type: + return celery.group( + search.s( + job_id=job.id, + archive_id=archive_ids[i], + task_id=task_ids[i], + job_config_obj=job_config_obj, + clp_metadata_db_conn_params=clp_metadata_db_conn_params, + results_cache_uri=results_cache_uri, + ) + for i in range(len(archive_ids)) ) - for i in range(len(archive_ids)) - ) + elif QueryJobType.EXTRACT_IR == job_type: + return celery.group( + extract_ir.s( + job_id=job.id, + archive_id=archive_ids[i], + task_id=task_ids[i], + job_config_obj=job_config_obj, + clp_metadata_db_conn_params=clp_metadata_db_conn_params, + results_cache_uri=results_cache_uri, + ) + for i in range(len(archive_ids)) + ) + else: + error_msg = f"Unexpected job type: {job_type}" + logger.error(error_msg) + raise NotImplementedError(error_msg) def dispatch_query_job( @@ -364,6 +435,30 @@ async def acquire_reducer_for_job(job: SearchJob): logger.info(f"Got reducer for job {job.id} at {reducer_host}:{reducer_port}") +def dispatch_job_and_update_db( + db_conn, + new_job: QueryJob, + target_archives: List[str], + clp_metadata_db_conn_params: Dict[str, any], + results_cache_uri: str, + num_tasks: int, +) -> None: + dispatch_query_job( + db_conn, new_job, target_archives, clp_metadata_db_conn_params, results_cache_uri + ) + start_time = datetime.datetime.now() + new_job.start_time = start_time + set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + new_job.id, + QueryJobStatus.RUNNING, + QueryJobStatus.PENDING, + start_time=start_time, + num_tasks=num_tasks, + ) + + def handle_pending_query_jobs( db_conn_pool, clp_metadata_db_conn_params: Dict[str, any], @@ -427,6 +522,46 @@ def handle_pending_query_jobs( else: pending_search_jobs.append(new_search_job) active_jobs[job_id] = new_search_job + + elif QueryJobType.EXTRACT_IR == job_type: + extract_ir_config = ExtractIrJobConfig.parse_obj(msgpack.unpackb(job_config)) + archive_id, file_split_id = get_archive_and_file_split_ids_for_extraction( + db_conn, extract_ir_config + ) + if not archive_id or not file_split_id: + if not set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + QueryJobStatus.FAILED, + QueryJobStatus.PENDING, + start_time=datetime.datetime.now(), + num_tasks=0, + duration=0, + ): + logger.error(f"Failed to set job {job_id} as failed") + continue + + extract_ir_config.file_split_id = file_split_id + new_extract_ir_job = ExtractIrJob( + id=job_id, + archive_id=archive_id, + extract_ir_config=extract_ir_config, + state=InternalJobState.WAITING_FOR_DISPATCH, + ) + target_archive = [new_extract_ir_job.archive_id] + + dispatch_job_and_update_db( + db_conn, + new_extract_ir_job, + target_archive, + clp_metadata_db_conn_params, + results_cache_uri, + 1, + ) + active_jobs[new_extract_ir_job.id] = new_extract_ir_job + logger.info(f"Dispatched IR extraction job {job_id} on archive: {archive_id}") + else: # NOTE: We're skipping the job for this iteration, but its status will remain # unchanged. So this log will print again in the next iteration unless the user @@ -452,23 +587,17 @@ def handle_pending_query_jobs( archive_ids_for_search = [archive["archive_id"] for archive in archives_for_search] - dispatch_query_job( - db_conn, job, archive_ids_for_search, clp_metadata_db_conn_params, results_cache_uri + dispatch_job_and_update_db( + db_conn, + job, + archive_ids_for_search, + clp_metadata_db_conn_params, + results_cache_uri, + job.num_archives_to_search, ) logger.info( f"Dispatched job {job_id} with {len(archive_ids_for_search)} archives to search." ) - start_time = datetime.datetime.now() - job.start_time = start_time - set_job_or_task_status( - db_conn, - QUERY_JOBS_TABLE_NAME, - job_id, - QueryJobStatus.RUNNING, - QueryJobStatus.PENDING, - start_time=start_time, - num_tasks=job.num_archives_to_search, - ) return reducer_acquisition_tasks @@ -590,6 +719,51 @@ async def handle_finished_search_job( del active_jobs[job_id] +async def handle_finished_extract_ir_job( + db_conn, job: ExtractIrJob, task_results: Optional[Any] +) -> None: + global active_jobs + + job_id = job.id + new_job_status = QueryJobStatus.SUCCEEDED + num_tasks = len(task_results) + if 1 != num_tasks: + logger.error( + f"Unexpected number of tasks for IR extraction job {job_id}. " + f"Expected 1, got {num_tasks}." + ) + new_job_status = QueryJobStatus.FAILED + else: + task_result = QueryTaskResult.parse_obj(task_results[0]) + task_id = task_result.task_id + if not QueryJobStatus.SUCCEEDED == task_result.status: + logger.error( + f"IR extraction task job-{job_id}-task-{task_id} failed. " + f"Check {task_result.error_log_path} for details." + ) + new_job_status = QueryJobStatus.FAILED + else: + logger.info( + f"IR extraction task job-{job_id}-task-{task_id} succeeded in " + f"{task_result.duration} second(s)." + ) + + if set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + new_job_status, + QueryJobStatus.RUNNING, + num_tasks_completed=num_tasks, + duration=(datetime.datetime.now() - job.start_time).total_seconds(), + ): + if new_job_status == QueryJobStatus.SUCCEEDED: + logger.info(f"Completed IR extraction job {job_id}.") + else: + logger.info(f"Completed IR extraction job {job_id} with failing tasks.") + del active_jobs[job_id] + + async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): global active_jobs @@ -627,6 +801,9 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): await handle_finished_search_job( db_conn, search_job, returned_results, results_cache_uri ) + elif QueryJobType.EXTRACT_IR == job_type: + extract_ir_job: ExtractIrJob = job + await handle_finished_extract_ir_job(db_conn, extract_ir_job, returned_results) else: logger.error(f"Unexpected job type: {job_type}, skipping job {job_id}") diff --git a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py index d337e0806..3d4c0d7a7 100644 --- a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py +++ b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py @@ -9,7 +9,11 @@ QueryJobType, QueryTaskStatus, ) -from job_orchestration.scheduler.job_config import QueryJobConfig, SearchJobConfig +from job_orchestration.scheduler.job_config import ( + ExtractIrJobConfig, + QueryJobConfig, + SearchJobConfig, +) from job_orchestration.scheduler.query.reducer_handler import ReducerHandlerMessageQueues from pydantic import BaseModel, validator @@ -53,6 +57,17 @@ def get_type(self) -> QueryJobType: ... def get_config(self) -> QueryJobConfig: ... +class ExtractIrJob(QueryJob): + extract_ir_config: ExtractIrJobConfig + archive_id: str + + def get_type(self) -> QueryJobType: + return QueryJobType.EXTRACT_IR + + def get_config(self) -> QueryJobConfig: + return self.extract_ir_config + + class SearchJob(QueryJob): search_config: SearchJobConfig num_archives_to_search: int diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index 740146ab9..3f658211e 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -46,7 +46,8 @@ #results_cache: # host: "localhost" # port: 27017 -# db_name: "clp-search" +# db_name: "clp-query-results" +# ir_collection_name: "ir-files" # #compression_worker: # logging_level: "INFO" @@ -77,6 +78,13 @@ # # How much data CLP should try to fit into each segment within an archive # target_segment_size: 268435456 # 256 MB # +## Where CLP IR files should be output +#ir_output: +# directory: "var/data/ir" +# +# # How large each IR file should be before being split into a new IR file +# target_uncompressed_size: 134217728 # 128 MB +# ## Location where other data (besides archives) are stored. It will be created if ## it doesn't exist. #data_directory: "var/data" diff --git a/components/webui/imports/api/search/constants.js b/components/webui/imports/api/search/constants.js index fbc0c3188..baedddb85 100644 --- a/components/webui/imports/api/search/constants.js +++ b/components/webui/imports/api/search/constants.js @@ -91,6 +91,7 @@ let enumQueryType; */ const QUERY_JOB_TYPE = Object.freeze({ SEARCH_OR_AGGREGATION: (enumQueryType = 0), + EXTRACT_IR: ++enumQueryType, }); /* eslint-enable sort-keys */ diff --git a/docs/src/dev-guide/components-webui.md b/docs/src/dev-guide/components-webui.md index bf2f76f6f..c5a482e12 100644 --- a/docs/src/dev-guide/components-webui.md +++ b/docs/src/dev-guide/components-webui.md @@ -41,7 +41,7 @@ package: ```shell # Please update `` accordingly. - MONGO_URL="mongodb://localhost:27017/clp-search" \ + MONGO_URL="mongodb://localhost:27017/clp-query-results" \ ROOT_URL="http://localhost:4000" \ CLP_DB_USER="clp-user" \ CLP_DB_PASS="" \ From 3c1f0ad1c44b53d6c17fd7c1d578ec61616b5661 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Wed, 3 Jul 2024 12:03:59 -0400 Subject: [PATCH 018/114] clp-s: Correctly report uncompressed size of archives during archive-splitting (fixes #469). (#463) --- components/core/src/clp_s/JsonFileIterator.cpp | 10 ++++++++++ components/core/src/clp_s/JsonFileIterator.hpp | 8 ++++++++ components/core/src/clp_s/JsonParser.cpp | 12 +++++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/components/core/src/clp_s/JsonFileIterator.cpp b/components/core/src/clp_s/JsonFileIterator.cpp index 5fffcc8f9..ad6d16cd0 100644 --- a/components/core/src/clp_s/JsonFileIterator.cpp +++ b/components/core/src/clp_s/JsonFileIterator.cpp @@ -156,4 +156,14 @@ bool JsonFileIterator::get_json(simdjson::ondemand::document_stream::iterator& i } while (read_new_json()); return false; } + +size_t JsonFileIterator::get_num_bytes_consumed() { + // If there are more documents left in the current buffer account for how much of the + // buffer has been consumed, otherwise report the total number of bytes read so that we + // capture trailing whitespace. + if (m_doc_it != m_stream.end()) { + return m_bytes_read - (m_buf_occupied - m_next_document_position); + } + return m_bytes_read; +} } // namespace clp_s diff --git a/components/core/src/clp_s/JsonFileIterator.hpp b/components/core/src/clp_s/JsonFileIterator.hpp index 51422963a..b8db3f4f2 100644 --- a/components/core/src/clp_s/JsonFileIterator.hpp +++ b/components/core/src/clp_s/JsonFileIterator.hpp @@ -51,6 +51,14 @@ class JsonFileIterator { */ [[nodiscard]] size_t get_num_bytes_read() const { return m_bytes_read; } + /** + * Note: this method can not be const because checking if a simdjson iterator is at the end + * of a document stream is non-const. + * + * @return total number of bytes consumed from the file via get_json + */ + [[nodiscard]] size_t get_num_bytes_consumed(); + /** * @return the last error code encountered when iterating over the json file */ diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index d73643a64..26ec3d7b4 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -439,7 +439,7 @@ bool JsonParser::parse() { simdjson::ondemand::document_stream::iterator json_it; m_num_messages = 0; - size_t last_num_bytes_read = 0; + size_t last_num_bytes_consumed = 0; while (json_file_iterator.get_json(json_it)) { m_current_schema.clear(); @@ -463,9 +463,11 @@ bool JsonParser::parse() { ->append_message(current_schema_id, m_current_schema, m_current_parsed_message); if (m_archive_writer->get_data_size() >= m_target_encoded_size) { - size_t num_bytes_read = json_file_iterator.get_num_bytes_read(); - m_archive_writer->increment_uncompressed_size(num_bytes_read - last_num_bytes_read); - last_num_bytes_read = num_bytes_read; + size_t num_bytes_read = json_file_iterator.get_num_bytes_consumed(); + m_archive_writer->increment_uncompressed_size( + num_bytes_read - last_num_bytes_consumed + ); + last_num_bytes_consumed = num_bytes_read; split_archive(); } @@ -473,7 +475,7 @@ bool JsonParser::parse() { } m_archive_writer->increment_uncompressed_size( - json_file_iterator.get_num_bytes_read() - last_num_bytes_read + json_file_iterator.get_num_bytes_read() - last_num_bytes_consumed ); if (simdjson::error_code::SUCCESS != json_file_iterator.get_error()) { From 9dabb926dfc6dd9f4274052634a4ece81f322f16 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Thu, 4 Jul 2024 15:41:14 -0400 Subject: [PATCH 019/114] clo: Use relative path for file metadata output by an IR extraction job. (#470) --- components/core/src/clp/clo/clo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/core/src/clp/clo/clo.cpp b/components/core/src/clp/clo/clo.cpp index ce351f160..4216a2c6e 100644 --- a/components/core/src/clp/clo/clo.cpp +++ b/components/core/src/clp/clo/clo.cpp @@ -192,7 +192,7 @@ bool extract_ir(CommandLineArguments const& command_line_args) { results.emplace_back(std::move(bsoncxx::builder::basic::make_document( bsoncxx::builder::basic::kvp( clp::clo::cResultsCacheKeys::IrOutput::Path, - dest_ir_path.string() + dest_ir_file_name ), bsoncxx::builder::basic::kvp( clp::clo::cResultsCacheKeys::OrigFileId, From 4bb223eff272c60e7cf863d127e7db9cee97822f Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Fri, 5 Jul 2024 01:02:31 -0400 Subject: [PATCH 020/114] log-viewer-webui: Add boilerplate React client. (#468) Co-authored-by: Junhao Liao --- components/log-viewer-webui/client/.gitignore | 9 + .../log-viewer-webui/client/package-lock.json | 10513 ++++++++++++++++ .../log-viewer-webui/client/package.json | 40 + .../log-viewer-webui/client/public/index.html | 12 + .../log-viewer-webui/client/src/App.jsx | 12 + .../log-viewer-webui/client/src/index.css | 15 + .../log-viewer-webui/client/src/index.jsx | 14 + .../log-viewer-webui/client/webpack.config.js | 81 + .../log-viewer-webui/server/package-lock.json | 2 +- .../log-viewer-webui/server/package.json | 6 +- .../dev-guide/components-log-viewer-webui.md | 21 +- 11 files changed, 10714 insertions(+), 11 deletions(-) create mode 100644 components/log-viewer-webui/client/.gitignore create mode 100644 components/log-viewer-webui/client/package-lock.json create mode 100644 components/log-viewer-webui/client/package.json create mode 100644 components/log-viewer-webui/client/public/index.html create mode 100644 components/log-viewer-webui/client/src/App.jsx create mode 100644 components/log-viewer-webui/client/src/index.css create mode 100644 components/log-viewer-webui/client/src/index.jsx create mode 100644 components/log-viewer-webui/client/webpack.config.js diff --git a/components/log-viewer-webui/client/.gitignore b/components/log-viewer-webui/client/.gitignore new file mode 100644 index 000000000..0fc763fdd --- /dev/null +++ b/components/log-viewer-webui/client/.gitignore @@ -0,0 +1,9 @@ +# Dependencies +/node_modules + +# Build +/dist + +# IDEs +/.idea +/.vscode diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json new file mode 100644 index 000000000..bf75b0710 --- /dev/null +++ b/components/log-viewer-webui/client/package-lock.json @@ -0,0 +1,10513 @@ +{ + "name": "log-viewer-webui-client", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "log-viewer-webui-client", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@babel/core": "^7.24.7", + "@babel/preset-env": "^7.24.7", + "@babel/preset-react": "^7.24.7", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", + "babel-loader": "^9.1.3", + "css-loader": "^7.1.2", + "eslint-config-yscope": "latest", + "html-webpack-plugin": "^5.6.0", + "mini-css-extract-plugin": "^2.9.0", + "react-refresh": "^0.14.2", + "style-loader": "^4.0.0", + "webpack": "^5.92.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", + "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", + "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", + "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", + "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", + "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", + "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", + "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", + "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", + "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", + "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", + "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", + "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", + "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", + "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", + "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", + "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", + "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", + "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", + "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.7", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.7", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.7", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", + "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", + "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "^8.56.5", + "@types/estree": "^1.0.5", + "@typescript-eslint/types": "^7.2.0", + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", + "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", + "dev": true, + "peer": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "peer": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", + "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz", + "integrity": "sha512-LFWllMA55pzB9D34w/wXUCf8+c+IYKuJDgxiZ3qMhl64KRMBHYM1I3VdGaD2BV5FNPV2/S2596bppxHbv2ZydQ==", + "dev": true, + "dependencies": { + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.8.1.tgz", + "integrity": "sha512-c5c2C8Mos5tTQd+NWpqwEu7VT6SSRooAguFPMj1cp2RkTYl1ynKoXo8MWy3k4rkbzoeYHrqC2UlUzsroAN7wtQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "acorn": "^8.11.3", + "escape-string-regexp": "^4.0.0", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.8.1.tgz", + "integrity": "sha512-k1Eb6rcjMP+mmjvj+vd9y5KUdWn1OBkkPLHXhsrHt5lCDFZxJEs0aVQzE5lpYrtVZVkpc5esTtss/cPJux0lfA==", + "dev": true, + "peer": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "^1.8.1", + "@types/eslint": "^8.56.10", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.8.1.tgz", + "integrity": "sha512-4+40H3lHYTN8OWz+US8CamVkO+2hxNLp9+CAjorI7top/lHqemhpJvKA1LD9Uh+WMY9DYWiWpL2+SZ2wAXY9fQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/eslint": "^8.56.10", + "@typescript-eslint/utils": "^6.21.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "peer": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "peer": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.16" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001640", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", + "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "peer": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.1.tgz", + "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "peer": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.816", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.816.tgz", + "integrity": "sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "peer": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "peer": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "peer": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "peer": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-yscope": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/eslint-config-yscope/-/eslint-config-yscope-0.0.31.tgz", + "integrity": "sha512-cA6sS3G4Ydoht/CvST7C7moqJO+NiKl0InQtkX5YKocXAQE6KZ/VW9/kORdNnpIGCLwkqvMOa7y4XNJZnTfubw==", + "dev": true, + "peerDependencies": { + "@stylistic/eslint-plugin-js": "^1.6.2", + "@stylistic/eslint-plugin-jsx": "^1.6.2", + "@stylistic/eslint-plugin-plus": "^1.6.2", + "eslint": "^8.57.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-import-newlines": "^1.4.0", + "eslint-plugin-jsdoc": "^48.2.3", + "eslint-plugin-no-autofix": "^1.2.3", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-simple-import-sort": "^12.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "peer": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import-newlines": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.4.0.tgz", + "integrity": "sha512-+Cz1x2xBLtI9gJbmuYEpvY7F8K75wskBmJ7rk4VRObIJo+jklUJaejFJgtnWeL0dCFWabGEkhausrikXaNbtoQ==", + "dev": true, + "peer": true, + "bin": { + "import-linter": "lib/index.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "48.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.0.tgz", + "integrity": "sha512-ukXPNpGby3KjCveCizIS8t1EbuJEHYEu/tBg8GCbn/YbHcXwphyvYCdvRZ/oMRfTscGSSzfsWoZ+ZkAP0/6YMQ==", + "dev": true, + "peer": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.43.1", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "parse-imports": "^2.1.0", + "semver": "^7.6.2", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-no-autofix": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", + "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", + "dev": true, + "peer": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0", + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "eslint": ">= 5.12.1" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", + "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "dev": true, + "peer": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.hasown": "^1.1.4", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "peer": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", + "dev": true, + "peer": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "peer": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "peer": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "peer": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "peer": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "peer": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "peer": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "peer": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "peer": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "peer": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "peer": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "peer": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "peer": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "peer": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/launch-editor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", + "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", + "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.1.2", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-imports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", + "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "dev": true, + "peer": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", + "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "peer": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "peer": true + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true, + "peer": true + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "peer": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "peer": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true, + "peer": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "dev": true, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", + "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", + "dev": true, + "peer": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", + "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "peer": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.92.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", + "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", + "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/glob": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-dev-server/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "peer": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "peer": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "peer": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "peer": true + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json new file mode 100644 index 000000000..47b2a7af3 --- /dev/null +++ b/components/log-viewer-webui/client/package.json @@ -0,0 +1,40 @@ +{ + "name": "log-viewer-webui-client", + "version": "0.1.0", + "description": "", + "main": "src/index.jsx", + "scripts": { + "build": "webpack --define-process-env-node-env production", + "lint:check": "npx eslint --no-eslintrc --config package.json src webpack.config.js", + "lint:fix": "npx eslint --fix --no-eslintrc --config package.json src webpack.config.js", + "start": "webpack serve" + }, + "author": "YScope Inc. ", + "license": "Apache-2.0", + "type": "module", + "devDependencies": { + "@babel/core": "^7.24.7", + "@babel/preset-env": "^7.24.7", + "@babel/preset-react": "^7.24.7", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", + "babel-loader": "^9.1.3", + "css-loader": "^7.1.2", + "eslint-config-yscope": "latest", + "html-webpack-plugin": "^5.6.0", + "mini-css-extract-plugin": "^2.9.0", + "react-refresh": "^0.14.2", + "style-loader": "^4.0.0", + "webpack": "^5.92.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4" + }, + "eslintConfig": { + "extends": [ + "yscope/react" + ] + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + } +} diff --git a/components/log-viewer-webui/client/public/index.html b/components/log-viewer-webui/client/public/index.html new file mode 100644 index 000000000..e0646892c --- /dev/null +++ b/components/log-viewer-webui/client/public/index.html @@ -0,0 +1,12 @@ + + + + Log Viewer + + + + + +
+ + diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx new file mode 100644 index 000000000..3a6f57fff --- /dev/null +++ b/components/log-viewer-webui/client/src/App.jsx @@ -0,0 +1,12 @@ +/** + * Renders the main application. + * + * @return {JSX.Element} + */ +const App = () => { + return ( +

Hello world!

+ ); +}; + +export default App; diff --git a/components/log-viewer-webui/client/src/index.css b/components/log-viewer-webui/client/src/index.css new file mode 100644 index 000000000..2e657d8e6 --- /dev/null +++ b/components/log-viewer-webui/client/src/index.css @@ -0,0 +1,15 @@ +html { + height: 100%; + width: 100%; +} + +body { + margin: 0; + height: 100%; + width: 100%; +} + +#root { + height: 100%; + width: 100%; +} diff --git a/components/log-viewer-webui/client/src/index.jsx b/components/log-viewer-webui/client/src/index.jsx new file mode 100644 index 000000000..5cb6dbd4e --- /dev/null +++ b/components/log-viewer-webui/client/src/index.jsx @@ -0,0 +1,14 @@ +import {StrictMode} from "react"; +import {createRoot} from "react-dom/client"; + +import App from "./App"; + +import "./index.css"; + + +const root = createRoot(document.getElementById("root")); +root.render( + + + +); diff --git a/components/log-viewer-webui/client/webpack.config.js b/components/log-viewer-webui/client/webpack.config.js new file mode 100644 index 000000000..e4bba7aaf --- /dev/null +++ b/components/log-viewer-webui/client/webpack.config.js @@ -0,0 +1,81 @@ +import HtmlWebpackPlugin from "html-webpack-plugin"; +import MiniCssExtractPlugin from "mini-css-extract-plugin"; +import * as path from "node:path"; +import {fileURLToPath} from "node:url"; +import ReactRefreshPlugin from "@pmmmwh/react-refresh-webpack-plugin"; + + +const filename = fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); + +const isProduction = "production" === process.env.NODE_ENV; + +const stylesHandler = isProduction ? + MiniCssExtractPlugin.loader : + "style-loader"; + +const plugins = [ + new HtmlWebpackPlugin({ + template: path.resolve(dirname, "public", "index.html"), + }), +]; + +const config = { + devtool: isProduction ? + "source-map" : + "eval-source-map", + entry: path.resolve(dirname, "src", "index.jsx"), + module: { + rules: [ + { + test: /\.(js|jsx)$/i, + exclude: /node_modules/, + use: { + loader: "babel-loader", + options: { + presets: [ + "@babel/preset-env", + [ + "@babel/preset-react", + { + runtime: "automatic", + }, + ], + ], + plugins: isProduction ? [] : ["react-refresh/babel"] + }, + }, + }, + { + test: /\.css$/i, + use: [ + stylesHandler, + "css-loader", + ], + }, + ], + }, + output: { + path: path.resolve(dirname, "dist"), + filename: isProduction ? + "[name].[contenthash].bundle.js" : + "[name].bundle.js", + clean: true, + publicPath: "auto", + }, + plugins: plugins.concat(isProduction ? + [new MiniCssExtractPlugin()] : + [new ReactRefreshPlugin()]), + resolve: { + extensions: [ + ".js", + ".jsx", + ".json", + ], + }, +}; + +export default () => { + config.mode = isProduction ? "production" : "development"; + return config; +}; diff --git a/components/log-viewer-webui/server/package-lock.json b/components/log-viewer-webui/server/package-lock.json index 435ccc040..518067de4 100644 --- a/components/log-viewer-webui/server/package-lock.json +++ b/components/log-viewer-webui/server/package-lock.json @@ -1,5 +1,5 @@ { - "name": "log-viewer-server", + "name": "log-viewer-webui-server", "version": "0.1.0", "lockfileVersion": 3, "requires": true, diff --git a/components/log-viewer-webui/server/package.json b/components/log-viewer-webui/server/package.json index 059a0eb22..01401a527 100644 --- a/components/log-viewer-webui/server/package.json +++ b/components/log-viewer-webui/server/package.json @@ -1,13 +1,13 @@ { - "name": "log-viewer-server", + "name": "log-viewer-webui-server", "version": "0.1.0", "description": "", "main": "src/main.js", "scripts": { - "dev": "NODE_ENV=development nodemon src/main.js", "lint:check": "npx eslint --no-eslintrc --config package.json src", "lint:fix": "npx eslint --fix --no-eslintrc --config package.json src", - "start": "NODE_ENV=production node src/main.js", + "prod": "NODE_ENV=production node src/main.js", + "start": "NODE_ENV=development nodemon src/main.js", "test": "tap" }, "author": "YScope Inc. ", diff --git a/docs/src/dev-guide/components-log-viewer-webui.md b/docs/src/dev-guide/components-log-viewer-webui.md index e77375b9d..e1facc232 100644 --- a/docs/src/dev-guide/components-log-viewer-webui.md +++ b/docs/src/dev-guide/components-log-viewer-webui.md @@ -1,7 +1,7 @@ # Log Viewer WebUI A webapp that allows us to serve the [log-viewer] and integrate it with CLP's [webui]. The webapp -currently consists of a [Fastify] server. In the future, we'll add a [React] frontend. +currently consists of a [React] client and a [Fastify] server. ## Requirements @@ -12,22 +12,29 @@ currently consists of a [Fastify] server. In the future, we'll add a [React] fro Install the app's dependencies: ```shell -cd components/log-viewer-webui/server -npm i +cd components/log-viewer-webui +(cd client && npm i) +(cd server && npm i) ``` ## Running +To run the client during development: + +```shell +npm run start +``` + To run the server during development: ```shell -npm run dev +npm run start ``` To run the server in production: ```shell -npm start +npm run prod ``` In both cases, if you want to customize what host and port the server binds to, you can use the @@ -35,7 +42,7 @@ environment variables in `components/log-viewer-webui/server/.env`. ## Testing -To run all unit tests: +To run the server's unit tests: ```shell npm test @@ -43,7 +50,7 @@ npm test ## Linting -To check for linting errors: +To check for linting errors in either the client or server: ```shell npm run lint:check From 986a957ef6c5aaabcf25202561cfcddfd6595e28 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:18:00 -0400 Subject: [PATCH 021/114] clp-package: Deduplicate and clean up code in CLI job-launcher scripts. (#473) --- .../clp_package_utils/general.py | 76 ++++++++++++- .../clp_package_utils/scripts/compress.py | 53 +++------ .../clp_package_utils/scripts/decompress.py | 56 +++------- .../scripts/native/compress.py | 6 +- .../scripts/native/decompress.py | 97 +++++++++------- .../scripts/native/search.py | 104 ++++-------------- .../clp_package_utils/scripts/native/utils.py | 98 +++++++++++++++++ .../clp_package_utils/scripts/search.py | 51 +++------ .../clp_package_utils/scripts/start_clp.py | 6 +- .../clp_package_utils/scripts/stop_clp.py | 6 +- 10 files changed, 310 insertions(+), 243 deletions(-) create mode 100644 components/clp-package-utils/clp_package_utils/scripts/native/utils.py diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index ce0f10309..b84bf298e 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -6,6 +6,9 @@ import socket import subprocess import typing +import uuid +from enum import auto +from typing import List, Tuple import yaml from clp_py_utils.clp_config import ( @@ -24,6 +27,7 @@ read_yaml_config_file, validate_path_could_be_dir, ) +from strenum import KebabCaseStrEnum # CONSTANTS # Paths @@ -38,6 +42,12 @@ class DockerMountType(enum.IntEnum): BIND = 0 +class JobType(KebabCaseStrEnum): + COMPRESSION = auto() + DECOMPRESSION = auto() + SEARCH = auto() + + class DockerMount: def __init__( self, @@ -91,6 +101,14 @@ def get_clp_home(): return clp_home.resolve() +def generate_container_name(job_type: JobType) -> str: + """ + :param job_type: + :return: A unique container name for the given job type. + """ + return f"clp-{job_type}-{str(uuid.uuid4())[-4:]}" + + def check_dependencies(): try: subprocess.run( @@ -177,12 +195,15 @@ def is_path_already_mounted( return host_path_relative_to_mounted_root == container_path_relative_to_mounted_root -def generate_container_config(clp_config: CLPConfig, clp_home: pathlib.Path): +def generate_container_config( + clp_config: CLPConfig, clp_home: pathlib.Path +) -> Tuple[CLPConfig, CLPDockerMounts]: """ Copies the given config and sets up mounts mapping the relevant host paths into the container :param clp_config: :param clp_home: + :return: The container config and the mounts. """ container_clp_config = clp_config.copy(deep=True) @@ -241,6 +262,57 @@ def generate_container_config(clp_config: CLPConfig, clp_home: pathlib.Path): return container_clp_config, docker_mounts +def dump_container_config( + container_clp_config: CLPConfig, clp_config: CLPConfig, container_name: str +) -> Tuple[pathlib.Path, pathlib.Path]: + """ + Writes the given config to the logs directory so that it's accessible in the container. + :param container_clp_config: The config to write. + :param clp_config: The corresponding config on the host (used to determine the logs directory). + :param container_name: + :return: The path to the config file in the container and on the host. + """ + container_config_filename = f".{container_name}-config.yml" + config_file_path_on_host = clp_config.logs_directory / container_config_filename + config_file_path_on_container = container_clp_config.logs_directory / container_config_filename + with open(config_file_path_on_host, "w") as f: + yaml.safe_dump(container_clp_config.dump_to_primitive_dict(), f) + + return config_file_path_on_container, config_file_path_on_host + + +def generate_container_start_cmd( + container_name: str, container_mounts: List[CLPDockerMounts], container_image: str +) -> List[str]: + """ + Generates the command to start a container with the given mounts and name. + :param container_name: + :param container_mounts: + :param container_image: + :return: The command. + """ + clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" + # fmt: off + container_start_cmd = [ + "docker", "run", + "-i", + "--rm", + "--network", "host", + "-w", str(CONTAINER_CLP_HOME), + "-e", f"PYTHONPATH={clp_site_packages_dir}", + "-u", f"{os.getuid()}:{os.getgid()}", + "--name", container_name, + "--log-driver", "local" + ] + for mount in container_mounts: + if mount: + container_start_cmd.append("--mount") + container_start_cmd.append(str(mount)) + container_start_cmd.append(container_image) + + return container_start_cmd + + def validate_config_key_existence(config, key): try: value = get_config_value(config, key) @@ -249,7 +321,7 @@ def validate_config_key_existence(config, key): return value -def validate_and_load_config_file( +def load_config_file( config_file_path: pathlib.Path, default_config_file_path: pathlib.Path, clp_home: pathlib.Path ): if config_file_path.exists(): diff --git a/components/clp-package-utils/clp_package_utils/scripts/compress.py b/components/clp-package-utils/clp_package_utils/scripts/compress.py index 61495a4cd..d0aa30913 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/compress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/compress.py @@ -1,20 +1,20 @@ import argparse import logging -import os import pathlib import subprocess import sys import uuid -import yaml - from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, - CONTAINER_CLP_HOME, CONTAINER_INPUT_LOGS_ROOT_DIR, + dump_container_config, generate_container_config, + generate_container_name, + generate_container_start_cmd, get_clp_home, - validate_and_load_config_file, + JobType, + load_config_file, validate_and_load_db_credentials_file, ) @@ -57,51 +57,32 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) clp_config.validate_logs_dir() + # Validate and load necessary credentials validate_and_load_db_credentials_file(clp_config, clp_home, False) except: logger.exception("Failed to load config.") return -1 - container_name = f"clp-compressor-{str(uuid.uuid4())[-4:]}" + container_name = generate_container_name(JobType.COMPRESSION) container_clp_config, mounts = generate_container_config(clp_config, clp_home) - container_config_filename = f".{container_name}-config.yml" - container_config_file_path_on_host = clp_config.logs_directory / container_config_filename - with open(container_config_file_path_on_host, "w") as f: - yaml.safe_dump(container_clp_config.dump_to_primitive_dict(), f) + generated_config_path_on_container, generated_config_path_on_host = dump_container_config( + container_clp_config, clp_config, container_name + ) - clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" - # fmt: off - container_start_cmd = [ - "docker", "run", - "-i", - "--rm", - "--network", "host", - "-w", str(CONTAINER_CLP_HOME), - "-e", f"PYTHONPATH={clp_site_packages_dir}", - "-u", f"{os.getuid()}:{os.getgid()}", - "--name", container_name, - "--log-driver", "local", - "--mount", str(mounts.clp_home), - ] - # fmt: on - necessary_mounts = [mounts.input_logs_dir, mounts.data_dir, mounts.logs_dir] - for mount in necessary_mounts: - if mount: - container_start_cmd.append("--mount") - container_start_cmd.append(str(mount)) - container_start_cmd.append(clp_config.execution_container) + necessary_mounts = [mounts.clp_home, mounts.input_logs_dir, mounts.data_dir, mounts.logs_dir] + container_start_cmd = generate_container_start_cmd( + container_name, necessary_mounts, clp_config.execution_container + ) # fmt: off compress_cmd = [ "python3", "-m", "clp_package_utils.scripts.native.compress", - "--config", str(container_clp_config.logs_directory / container_config_filename), + "--config", str(generated_config_path_on_container), "--remove-path-prefix", str(CONTAINER_INPUT_LOGS_ROOT_DIR), ] # fmt: on @@ -140,7 +121,7 @@ def main(argv): subprocess.run(cmd, check=True) # Remove generated files - container_config_file_path_on_host.unlink() + generated_config_path_on_host.unlink() return 0 diff --git a/components/clp-package-utils/clp_package_utils/scripts/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/decompress.py index f20291b50..f700d9721 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/decompress.py @@ -1,21 +1,22 @@ import argparse import logging -import os import pathlib import subprocess import sys -import uuid -import yaml +from clp_py_utils.clp_config import CLPConfig from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, - CONTAINER_CLP_HOME, DockerMount, DockerMountType, + dump_container_config, generate_container_config, + generate_container_name, + generate_container_start_cmd, get_clp_home, - validate_and_load_config_file, + JobType, + load_config_file, validate_and_load_db_credentials_file, validate_path_could_be_dir, ) @@ -53,11 +54,10 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) clp_config.validate_logs_dir() + # Validate and load necessary credentials validate_and_load_db_credentials_file(clp_config, clp_home, False) except: logger.exception("Failed to load config.") @@ -76,33 +76,16 @@ def main(argv): return -1 extraction_dir.mkdir(exist_ok=True) - container_name = f"clp-decompressor-{str(uuid.uuid4())[-4:]}" - + container_name = generate_container_name(JobType.DECOMPRESSION) container_clp_config, mounts = generate_container_config(clp_config, clp_home) - container_config_filename = f".{container_name}-config.yml" - container_config_file_path_on_host = clp_config.logs_directory / container_config_filename - with open(container_config_file_path_on_host, "w") as f: - yaml.safe_dump(container_clp_config.dump_to_primitive_dict(), f) - - clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" - # fmt: off - container_start_cmd = [ - "docker", "run", - "-i", - "--rm", - "--network", "host", - "-w", str(CONTAINER_CLP_HOME), - "-e", f"PYTHONPATH={clp_site_packages_dir}", - "-u", f"{os.getuid()}:{os.getgid()}", - "--name", container_name, - "--log-driver", "local", - "--mount", str(mounts.clp_home), - ] - # fmt: on + generated_config_path_on_container, generated_config_path_on_host = dump_container_config( + container_clp_config, clp_config, container_name + ) # Set up mounts container_extraction_dir = pathlib.Path("/") / "mnt" / "extraction-dir" necessary_mounts = [ + mounts.clp_home, mounts.data_dir, mounts.logs_dir, mounts.archives_output_dir, @@ -120,18 +103,15 @@ def main(argv): container_paths_to_decompress_file_path, ) ) - for mount in necessary_mounts: - if mount: - container_start_cmd.append("--mount") - container_start_cmd.append(str(mount)) - - container_start_cmd.append(clp_config.execution_container) + container_start_cmd = generate_container_start_cmd( + container_name, necessary_mounts, clp_config.execution_container + ) # fmt: off decompress_cmd = [ "python3", "-m", "clp_package_utils.scripts.native.decompress", - "--config", str(container_clp_config.logs_directory / container_config_filename), + "--config", str(generated_config_path_on_container), "-d", str(container_extraction_dir), ] # fmt: on @@ -145,7 +125,7 @@ def main(argv): subprocess.run(cmd, check=True) # Remove generated files - container_config_file_path_on_host.unlink() + generated_config_path_on_host.unlink() return 0 diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/compress.py b/components/clp-package-utils/clp_package_utils/scripts/native/compress.py index a08602007..cb495204f 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/compress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/compress.py @@ -20,7 +20,7 @@ from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, get_clp_home, - validate_and_load_config_file, + load_config_file, ) # Setup logging @@ -170,9 +170,7 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) clp_config.validate_input_logs_dir() clp_config.validate_logs_dir() except: diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py index 9ca3ab7b6..9331492b4 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py @@ -4,6 +4,7 @@ import subprocess import sys import uuid +from typing import Optional import yaml from clp_py_utils.clp_config import CLPConfig @@ -11,7 +12,7 @@ from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, get_clp_home, - validate_and_load_config_file, + load_config_file, ) # Setup logging @@ -25,15 +26,62 @@ logger.addHandler(logging_console_handler) -def decompress_paths( +def validate_and_load_config_file( clp_home: pathlib.Path, - paths, - list_path: pathlib.Path, - clp_config: CLPConfig, - archives_dir: pathlib.Path, - logs_dir: pathlib.Path, - extraction_dir: pathlib.Path, + config_file_path: pathlib.Path, + default_config_file_path: pathlib.Path, +) -> Optional[CLPConfig]: + """ + Validates and loads the config file. + :param clp_home: + :param config_file_path: + :param default_config_file_path: + :return: clp_config on success, None otherwise. + """ + try: + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) + clp_config.validate_archive_output_dir() + clp_config.validate_logs_dir() + return clp_config + except Exception: + logger.exception("Failed to load config.") + return None + + +def handle_decompression_command( + parsed_args: argparse.Namespace, clp_home: pathlib.Path, default_config_file_path: pathlib.Path ): + """ + Handles the decompression command. + :param parsed_args: + :param clp_home: + :param default_config_file_path: + :return: 0 on success, -1 otherwise. + """ + # Validate paths were specified using only one method + if len(parsed_args.paths) > 0 and parsed_args.files_from is not None: + logger.error("Paths cannot be specified both on the command line and through a file.") + return -1 + + # Validate extraction directory + extraction_dir = pathlib.Path(parsed_args.extraction_dir) + if not extraction_dir.is_dir(): + logger.error(f"extraction-dir ({extraction_dir}) is not a valid directory.") + return -1 + + # Validate and load config file + clp_config = validate_and_load_config_file( + clp_home, pathlib.Path(parsed_args.config), default_config_file_path + ) + if not clp_config: + return -1 + + paths = parsed_args.paths + list_path = parsed_args.files_from + + logs_dir = clp_config.logs_directory + archives_dir = clp_config.archive_output.directory + # Generate database config file for clp db_config_file_path = logs_dir / f".decompress-db-config-{uuid.uuid4()}.yml" with open(db_config_file_path, "w") as f: @@ -46,6 +94,7 @@ def decompress_paths( "--db-config-file", str(db_config_file_path), ] # fmt: on + files_to_decompress_list_path = None if list_path is not None: decompression_cmd.append("-f") @@ -93,37 +142,7 @@ def main(argv): ) parsed_args = args_parser.parse_args(argv[1:]) - # Validate paths were specified using only one method - if len(parsed_args.paths) > 0 and parsed_args.files_from is not None: - args_parser.error("Paths cannot be specified both on the command line and through a file.") - - # Validate extraction directory - extraction_dir = pathlib.Path(parsed_args.extraction_dir) - if not extraction_dir.is_dir(): - logger.error(f"extraction-dir ({extraction_dir}) is not a valid directory.") - return -1 - - # Validate and load config file - try: - config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) - clp_config.validate_archive_output_dir() - clp_config.validate_logs_dir() - except: - logger.exception("Failed to load config.") - return -1 - - return decompress_paths( - clp_home, - parsed_args.paths, - parsed_args.files_from, - clp_config, - clp_config.archive_output.directory, - clp_config.logs_directory, - extraction_dir, - ) + return handle_decompression_command(parsed_args, clp_home, default_config_file_path) if "__main__" == __name__: diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/search.py b/components/clp-package-utils/clp_package_utils/scripts/native/search.py index 9041b0006..7dd247fa5 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/search.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/search.py @@ -4,16 +4,13 @@ import asyncio import ipaddress import logging -import multiprocessing import pathlib import socket import sys -import time -from contextlib import closing import msgpack import pymongo -from clp_py_utils.clp_config import Database, QUERY_JOBS_TABLE_NAME, ResultsCache +from clp_py_utils.clp_config import Database, ResultsCache from clp_py_utils.sql_adapter import SQL_Adapter from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType from job_orchestration.scheduler.job_config import AggregationConfig, SearchJobConfig @@ -21,7 +18,12 @@ from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, get_clp_home, - validate_and_load_config_file, + load_config_file, +) +from clp_package_utils.scripts.native.utils import ( + run_function_in_process, + submit_query_job, + wait_for_query_job, ) # Setup logging @@ -35,41 +37,6 @@ logger.addHandler(logging_console_handler) -async def run_function_in_process(function, *args, initializer=None, init_args=None): - """ - Runs the given function in a separate process wrapped in a *cancellable* - asyncio task. This is necessary because asyncio's multiprocessing process - cannot be cancelled once it's started. - :param function: Method to run - :param args: Arguments for the method - :param initializer: Initializer for each process in the pool - :param init_args: Arguments for the initializer - :return: Return value of the method - """ - pool = multiprocessing.Pool(1, initializer, init_args) - - loop = asyncio.get_event_loop() - fut = loop.create_future() - - def process_done_callback(obj): - loop.call_soon_threadsafe(fut.set_result, obj) - - def process_error_callback(err): - loop.call_soon_threadsafe(fut.set_exception, err) - - pool.apply_async( - function, args, callback=process_done_callback, error_callback=process_error_callback - ) - - try: - return await fut - except asyncio.CancelledError: - pass - finally: - pool.terminate() - pool.close() - - def create_and_monitor_job_in_db( db_config: Database, results_cache: ResultsCache, @@ -106,47 +73,22 @@ def create_and_monitor_job_in_db( search_config.tags = tag_list sql_adapter = SQL_Adapter(db_config) - with closing(sql_adapter.create_connection(True)) as db_conn, closing( - db_conn.cursor(dictionary=True) - ) as db_cursor: - # Create job - db_cursor.execute( - f"INSERT INTO `{QUERY_JOBS_TABLE_NAME}` (`job_config`, `type`) VALUES (%s, %s)", - (msgpack.packb(search_config.dict()), QueryJobType.SEARCH_OR_AGGREGATION), - ) - db_conn.commit() - job_id = db_cursor.lastrowid + job_id = submit_query_job(sql_adapter, search_config, QueryJobType.SEARCH_OR_AGGREGATION) + job_status = wait_for_query_job(sql_adapter, job_id) - # Wait for the job to be marked complete - while True: - db_cursor.execute( - f"SELECT `status` FROM `{QUERY_JOBS_TABLE_NAME}` WHERE `id` = {job_id}" - ) - # There will only ever be one row since it's impossible to have more than one job with - # the same ID - new_status = db_cursor.fetchall()[0]["status"] - db_conn.commit() - if new_status in ( - QueryJobStatus.SUCCEEDED, - QueryJobStatus.FAILED, - QueryJobStatus.CANCELLED, - ): - break - - time.sleep(0.5) + if do_count_aggregation is None and count_by_time_bucket_size is None: + return + with pymongo.MongoClient(results_cache.get_uri()) as client: + search_results_collection = client[results_cache.db_name][str(job_id)] + if do_count_aggregation is not None: + for document in search_results_collection.find(): + print(f"tags: {document['group_tags']} count: {document['records'][0]['count']}") + elif count_by_time_bucket_size is not None: + for document in search_results_collection.find(): + print(f"timestamp: {document['timestamp']} count: {document['count']}") - if do_count_aggregation is None and count_by_time_bucket_size is None: - return - with pymongo.MongoClient(results_cache.get_uri()) as client: - search_results_collection = client[results_cache.db_name][str(job_id)] - if do_count_aggregation is not None: - for document in search_results_collection.find(): - print( - f"tags: {document['group_tags']} count: {document['records'][0]['count']}" - ) - elif count_by_time_bucket_size is not None: - for document in search_results_collection.find(): - print(f"timestamp: {document['timestamp']} count: {document['count']}") + if job_status != QueryJobStatus.SUCCEEDED: + logger.error(f"job {job_id} finished with unexpected status: {job_status}") async def worker_connection_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): @@ -328,9 +270,7 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) clp_config.validate_logs_dir() except: logger.exception("Failed to load config.") diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/utils.py b/components/clp-package-utils/clp_package_utils/scripts/native/utils.py new file mode 100644 index 000000000..6b94e4676 --- /dev/null +++ b/components/clp-package-utils/clp_package_utils/scripts/native/utils.py @@ -0,0 +1,98 @@ +import asyncio +import multiprocessing +import time +from contextlib import closing + +import msgpack +from clp_py_utils.clp_config import ( + QUERY_JOBS_TABLE_NAME, +) +from clp_py_utils.sql_adapter import SQL_Adapter +from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType +from job_orchestration.scheduler.scheduler_data import QueryJobConfig + + +async def run_function_in_process(function, *args, initializer=None, init_args=None): + """ + Runs the given function in a separate process wrapped in a *cancellable* + asyncio task. This is necessary because asyncio's multiprocessing process + cannot be cancelled once it's started. + :param function: Method to run + :param args: Arguments for the method + :param initializer: Initializer for each process in the pool + :param init_args: Arguments for the initializer + :return: Return value of the method + """ + pool = multiprocessing.Pool(1, initializer, init_args) + + loop = asyncio.get_event_loop() + fut = loop.create_future() + + def process_done_callback(obj): + loop.call_soon_threadsafe(fut.set_result, obj) + + def process_error_callback(err): + loop.call_soon_threadsafe(fut.set_exception, err) + + pool.apply_async( + function, args, callback=process_done_callback, error_callback=process_error_callback + ) + + try: + return await fut + except asyncio.CancelledError: + pass + finally: + pool.terminate() + pool.close() + + +def submit_query_job( + sql_adapter: SQL_Adapter, job_config: QueryJobConfig, job_type: QueryJobType +) -> int: + """ + Submits a query job. + :param sql_adapter: + :param job_config: + :param job_type: + :return: The job's ID. + """ + with closing(sql_adapter.create_connection(True)) as db_conn, closing( + db_conn.cursor(dictionary=True) + ) as db_cursor: + # Create job + db_cursor.execute( + f"INSERT INTO `{QUERY_JOBS_TABLE_NAME}` (`job_config`, `type`) VALUES (%s, %s)", + (msgpack.packb(job_config.dict()), job_type), + ) + db_conn.commit() + return db_cursor.lastrowid + + +def wait_for_query_job(sql_adapter: SQL_Adapter, job_id: int) -> QueryJobStatus: + """ + Waits for the query job with the given ID to complete. + :param sql_adapter: + :param job_id: + :return: The job's status on completion. + """ + with closing(sql_adapter.create_connection(True)) as db_conn, closing( + db_conn.cursor(dictionary=True) + ) as db_cursor: + # Wait for the job to be marked complete + while True: + db_cursor.execute( + f"SELECT `status` FROM `{QUERY_JOBS_TABLE_NAME}` WHERE `id` = {job_id}" + ) + # There will only ever be one row since it's impossible to have more than one job with + # the same ID + new_status = db_cursor.fetchall()[0]["status"] + db_conn.commit() + if new_status in ( + QueryJobStatus.SUCCEEDED, + QueryJobStatus.FAILED, + QueryJobStatus.CANCELLED, + ): + return new_status + + time.sleep(0.5) diff --git a/components/clp-package-utils/clp_package_utils/scripts/search.py b/components/clp-package-utils/clp_package_utils/scripts/search.py index 2f2450430..f3f02046d 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/search.py +++ b/components/clp-package-utils/clp_package_utils/scripts/search.py @@ -10,10 +10,13 @@ from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, - CONTAINER_CLP_HOME, + dump_container_config, generate_container_config, + generate_container_name, + generate_container_start_cmd, get_clp_home, - validate_and_load_config_file, + JobType, + load_config_file, validate_and_load_db_credentials_file, ) @@ -70,52 +73,32 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) clp_config.validate_logs_dir() # Validate and load necessary credentials - validate_and_load_db_credentials_file(clp_config, clp_home, True) + validate_and_load_db_credentials_file(clp_config, clp_home, False) except: logger.exception("Failed to load config.") return -1 - container_name = f"clp-search-{str(uuid.uuid4())[-4:]}" + container_name = generate_container_name(JobType.SEARCH) container_clp_config, mounts = generate_container_config(clp_config, clp_home) - container_config_filename = f".{container_name}-config.yml" - container_config_file_path_on_host = clp_config.logs_directory / container_config_filename - with open(container_config_file_path_on_host, "w") as f: - yaml.safe_dump(container_clp_config.dump_to_primitive_dict(), f) + generated_config_path_on_container, generated_config_path_on_host = dump_container_config( + container_clp_config, clp_config, container_name + ) - clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" - # fmt: off - container_start_cmd = [ - "docker", "run", - "-i", - "--rm", - "--network", "host", - "-w", str(CONTAINER_CLP_HOME), - "-e", f"PYTHONPATH={clp_site_packages_dir}", - "-u", f"{os.getuid()}:{os.getgid()}", - "--name", container_name, - "--log-driver", "local", - "--mount", str(mounts.clp_home), - ] - # fmt: on - necessary_mounts = [mounts.logs_dir] - for mount in necessary_mounts: - if mount: - container_start_cmd.append("--mount") - container_start_cmd.append(str(mount)) - container_start_cmd.append(clp_config.execution_container) + necessary_mounts = [mounts.clp_home, mounts.logs_dir] + container_start_cmd = generate_container_start_cmd( + container_name, necessary_mounts, clp_config.execution_container + ) # fmt: off search_cmd = [ "python3", "-m", "clp_package_utils.scripts.native.search", - "--config", str(container_clp_config.logs_directory / container_config_filename), + "--config", str(generated_config_path_on_container), parsed_args.wildcard_query, ] # fmt: on @@ -142,7 +125,7 @@ def main(argv): subprocess.run(cmd, check=True) # Remove generated files - container_config_file_path_on_host.unlink() + generated_config_path_on_host.unlink() return 0 diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 5ba5bbe15..9dba79886 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -44,7 +44,7 @@ get_clp_home, is_container_exited, is_container_running, - validate_and_load_config_file, + load_config_file, validate_and_load_db_credentials_file, validate_and_load_queue_credentials_file, validate_and_load_redis_credentials_file, @@ -887,9 +887,7 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) # Validate and load necessary credentials if target in ( diff --git a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py index 00e3f7b6b..7971dd7d8 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py @@ -25,7 +25,7 @@ get_clp_home, is_container_exited, is_container_running, - validate_and_load_config_file, + load_config_file, validate_and_load_db_credentials_file, validate_and_load_queue_credentials_file, ) @@ -103,9 +103,7 @@ def main(argv): # Validate and load config file try: config_file_path = pathlib.Path(parsed_args.config) - clp_config = validate_and_load_config_file( - config_file_path, default_config_file_path, clp_home - ) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) # Validate and load necessary credentials if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME): From 02fbea4a0395f4c497ec61323937088f9cf1b5a6 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Sun, 7 Jul 2024 06:17:47 -0400 Subject: [PATCH 022/114] log-viewer-webui: Serve client using server in production; Add npm scripts to setup, lint, and start client and server together during development. (#474) --- .../log-viewer-webui/client/webpack.config.js | 10 +- components/log-viewer-webui/package-lock.json | 351 ++++++ components/log-viewer-webui/package.json | 22 + components/log-viewer-webui/server/.env | 1 + .../log-viewer-webui/server/package-lock.json | 1018 +++++++---------- .../log-viewer-webui/server/package.json | 1 + components/log-viewer-webui/server/src/app.js | 21 +- .../log-viewer-webui/server/src/main.js | 12 +- 8 files changed, 855 insertions(+), 581 deletions(-) create mode 100644 components/log-viewer-webui/package-lock.json create mode 100644 components/log-viewer-webui/package.json diff --git a/components/log-viewer-webui/client/webpack.config.js b/components/log-viewer-webui/client/webpack.config.js index e4bba7aaf..2829b3c10 100644 --- a/components/log-viewer-webui/client/webpack.config.js +++ b/components/log-viewer-webui/client/webpack.config.js @@ -2,6 +2,7 @@ import HtmlWebpackPlugin from "html-webpack-plugin"; import MiniCssExtractPlugin from "mini-css-extract-plugin"; import * as path from "node:path"; import {fileURLToPath} from "node:url"; + import ReactRefreshPlugin from "@pmmmwh/react-refresh-webpack-plugin"; @@ -42,7 +43,9 @@ const config = { }, ], ], - plugins: isProduction ? [] : ["react-refresh/babel"] + plugins: isProduction ? + [] : + ["react-refresh/babel"], }, }, }, @@ -76,6 +79,9 @@ const config = { }; export default () => { - config.mode = isProduction ? "production" : "development"; + config.mode = isProduction ? + "production" : + "development"; + return config; }; diff --git a/components/log-viewer-webui/package-lock.json b/components/log-viewer-webui/package-lock.json new file mode 100644 index 000000000..4ca32e8ff --- /dev/null +++ b/components/log-viewer-webui/package-lock.json @@ -0,0 +1,351 @@ +{ + "name": "log-viewer-webui", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "log-viewer-webui", + "version": "0.1.0", + "license": "Apache-2.0", + "devDependencies": { + "concurrently": "^8.2.2" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concurrently": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "date-fns": "^2.30.0", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + } + } +} diff --git a/components/log-viewer-webui/package.json b/components/log-viewer-webui/package.json new file mode 100644 index 000000000..d019ba21b --- /dev/null +++ b/components/log-viewer-webui/package.json @@ -0,0 +1,22 @@ +{ + "name": "log-viewer-webui", + "version": "0.1.0", + "description": "", + "scripts": { + "client:lint:check": "cd client && npm run lint:check", + "client:lint:fix": "cd client && npm run lint:fix", + "client:start": "cd client && npm start", + "init": "npm i && (cd client && npm i) && (cd server && npm i)", + "lint:check": "npm run client:lint:check && npm run server:lint:check", + "lint:fix": "npm run client:lint:fix && npm run server:lint:fix", + "server:lint:check": "cd server && npm run lint:check", + "server:lint:fix": "cd server && npm run lint:fix", + "server:start": "cd server && npm start", + "start": "concurrently \"npm run client:start\" \"npm run server:start\"" + }, + "author": "YScope Inc. ", + "license": "Apache-2.0", + "devDependencies": { + "concurrently": "^8.2.2" + } +} diff --git a/components/log-viewer-webui/server/.env b/components/log-viewer-webui/server/.env index 3fd917426..699f2cb90 100644 --- a/components/log-viewer-webui/server/.env +++ b/components/log-viewer-webui/server/.env @@ -1,2 +1,3 @@ +CLIENT_DIR=../client/dist HOST=localhost PORT=3000 diff --git a/components/log-viewer-webui/server/package-lock.json b/components/log-viewer-webui/server/package-lock.json index 518067de4..1066e05ef 100644 --- a/components/log-viewer-webui/server/package-lock.json +++ b/components/log-viewer-webui/server/package-lock.json @@ -5,10 +5,11 @@ "requires": true, "packages": { "": { - "name": "log-viewer-server", + "name": "log-viewer-webui-server", "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "@fastify/static": "^7.0.4", "dotenv": "^16.4.5", "fastify": "^4.28.0", "http-status-codes": "^2.3.0", @@ -45,6 +46,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@alcalzone/ansi-tokenize/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@base2/pretty-print-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", @@ -88,9 +101,9 @@ } }, "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", + "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", "dev": true, "peer": true, "engines": { @@ -118,9 +131,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "peer": true, "engines": { @@ -185,10 +198,18 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fastify/accept-negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", + "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", + "engines": { + "node": ">=14" + } + }, "node_modules/@fastify/ajv-compiler": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz", - "integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz", + "integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==", "dependencies": { "ajv": "^8.11.0", "ajv-formats": "^2.1.1", @@ -236,6 +257,31 @@ "fast-deep-equal": "^3.1.3" } }, + "node_modules/@fastify/send": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", + "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "2.0.0", + "mime": "^3.0.0" + } + }, + "node_modules/@fastify/static": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz", + "integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==", + "dependencies": { + "@fastify/accept-negotiator": "^1.0.0", + "@fastify/send": "^2.0.0", + "content-disposition": "^0.5.3", + "fastify-plugin": "^4.0.0", + "fastq": "^1.17.0", + "glob": "^10.3.4" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -302,7 +348,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -319,7 +364,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -331,7 +375,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -425,6 +468,14 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@lukeed/ms": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", + "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", + "engines": { + "node": ">=8" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -577,43 +628,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@npmcli/package-json/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@npmcli/promise-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", @@ -703,12 +717,24 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@sigstore/bundle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", @@ -1038,47 +1064,10 @@ "@tapjs/core": "2.1.6" } }, - "node_modules/@tapjs/fixture/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@tapjs/fixture/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tapjs/fixture/node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", + "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1087,7 +1076,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1271,28 +1260,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@tapjs/run/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tapjs/run/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -1302,25 +1269,10 @@ "node": ">=16" } }, - "node_modules/@tapjs/run/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tapjs/run/node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", + "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1329,7 +1281,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1451,59 +1403,35 @@ "@tapjs/core": "2.1.6" } }, - "node_modules/@tapjs/test/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "node_modules/@tapjs/test/node_modules/rimraf": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", + "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", "dev": true, "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" + "glob": "^10.3.7" }, "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@tapjs/test/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" + "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@tapjs/test/node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "node_modules/@tapjs/test/node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, "bin": { - "rimraf": "dist/esm/bin.mjs" + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=14.17" } }, "node_modules/@tapjs/typescript": { @@ -1580,9 +1508,9 @@ } }, "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -1633,9 +1561,9 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", - "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", "dev": true, "peer": true, "dependencies": { @@ -1787,9 +1715,9 @@ "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1923,7 +1851,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1932,7 +1859,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2229,8 +2155,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2267,7 +2192,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -2355,43 +2279,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/cacache/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2563,6 +2450,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-truncate/node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -2599,15 +2498,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2655,7 +2545,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2666,8 +2555,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/colorette": { "version": "2.0.20", @@ -2690,6 +2578,17 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2717,7 +2616,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2849,6 +2747,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -2898,14 +2804,12 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/encoding": { "version": "0.1.13", @@ -3050,6 +2954,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "peer": true + }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", @@ -3115,6 +3026,11 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3185,9 +3101,9 @@ } }, "node_modules/eslint-config-yscope": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/eslint-config-yscope/-/eslint-config-yscope-0.0.29.tgz", - "integrity": "sha512-k+jHGltXmGGdBtuacUME7b3M9k0TOXbr/kWxkxVhbFPMX4Eg33WqCDYEiHV/jWlXLfag18YBH3r7RI+ysMIbeg==", + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/eslint-config-yscope/-/eslint-config-yscope-0.0.31.tgz", + "integrity": "sha512-cA6sS3G4Ydoht/CvST7C7moqJO+NiKl0InQtkX5YKocXAQE6KZ/VW9/kORdNnpIGCLwkqvMOa7y4XNJZnTfubw==", "dev": true, "peerDependencies": { "@stylistic/eslint-plugin-js": "^1.6.2", @@ -3359,20 +3275,22 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.2.12", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.12.tgz", - "integrity": "sha512-sO9sKkJx5ovWoRk9hV0YiNzXQ4Z6j27CqE/po2E3wddZVuy9wvKPSTiIhpxMTrP/qURvKayJIDB2+o9kyCW1Fw==", + "version": "48.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.2.tgz", + "integrity": "sha512-VXBJFviQz30rynlOEQ+dNWLmeopjoAgutUVrWOZwm6Ki4EVDm4XkyIqAV/Zhf7FcDr0AG0aGmRn5FxxCtAF0tA==", "dev": true, "peer": true, "dependencies": { "@es-joy/jsdoccomment": "~0.43.1", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.4", + "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", "esquery": "^1.5.0", + "parse-imports": "^2.1.0", "semver": "^7.6.2", - "spdx-expression-parse": "^4.0.0" + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.0" }, "engines": { "node": ">=18" @@ -3399,9 +3317,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.2.tgz", - "integrity": "sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==", + "version": "7.34.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", + "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", "dev": true, "peer": true, "dependencies": { @@ -3409,7 +3327,7 @@ "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.3", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", @@ -3510,9 +3428,9 @@ } }, "node_modules/eslint-plugin-simple-import-sort": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.0.tgz", - "integrity": "sha512-Y2fqAfC11TcG/WP3TrI1Gi3p3nc8XJyEOJYHyEPEGI/UAgNx6akxxlX74p7SbAQdLcgASKhj8M0GKvH3vq/+ig==", + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", "dev": true, "peer": true, "peerDependencies": { @@ -3736,9 +3654,9 @@ "peer": true }, "node_modules/fast-json-stringify": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.0.tgz", - "integrity": "sha512-A4bg6E15QrkuVO3f0SwIASgzMzR6XC4qTyTqhf3hYXy0iazbAdZKwkE+ox4WgzKyzM6ygvbdq3r134UjOaaAnA==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz", + "integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==", "dependencies": { "@fastify/merge-json-schemas": "^0.1.0", "ajv": "^8.10.0", @@ -3819,9 +3737,9 @@ "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==" }, "node_modules/fastify": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.28.0.tgz", - "integrity": "sha512-HhW7UHW07YlqH5qpS0af8d2Gl/o98DhJ8ZDQWHRNDnzeOhZvtreWsX8xanjGgXmkYerGbo8ax/n40Dpwqkot8Q==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.28.1.tgz", + "integrity": "sha512-kFWUtpNr4i7t5vY2EJPCN2KgMVpuqfU4NjnJNCgiNB900oiDeYqaNDRcAfeBbOF5hGixixxcKnOU4KN9z6QncQ==", "funding": [ { "type": "github", @@ -3851,6 +3769,11 @@ "toad-cache": "^3.3.0" } }, + "node_modules/fastify-plugin": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", + "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==" + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -3946,10 +3869,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", - "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", - "dev": true, + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4026,6 +3948,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4113,21 +4036,22 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", + "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4146,26 +4070,18 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/globals": { @@ -4327,6 +4243,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "peer": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -4363,6 +4280,21 @@ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -4382,9 +4314,9 @@ "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==" }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -4506,8 +4438,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ink": { "version": "4.4.1", @@ -4731,12 +4662,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "dev": true, + "peer": true, "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4797,15 +4732,11 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/is-generator-function": { @@ -5077,8 +5008,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", @@ -5131,15 +5061,14 @@ } }, "node_modules/jackspeak": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", - "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", - "dev": true, + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.1.tgz", + "integrity": "sha512-U23pQPDnmYybVkYjObcuYMk43VRlMLLqLI+RdZy8s8WV8WsxO9SnqSroKaluuvcNOdCAlauKszDwd+umbot5Mg==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5342,12 +5271,11 @@ } }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "dev": true, + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.1.tgz", + "integrity": "sha512-9/8QXrtbGeMB6LxwQd4x1tIMnsmUxMvIH/qWGsccz6bt9Uln3S+sgAaqfQNhbGA8ufzs2fHuP/yqapGgP9Hh2g==", "engines": { - "node": "14 || >=16.14" + "node": ">=18" } }, "node_modules/make-dir": { @@ -5431,6 +5359,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -5467,7 +5406,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -5681,28 +5619,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/node-gyp/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -5712,21 +5628,6 @@ "node": ">=16" } }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/proc-log": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", @@ -5752,9 +5653,9 @@ } }, "node_modules/nodemon": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.3.tgz", - "integrity": "sha512-m4Vqs+APdKzDFpuaL9F9EVOF85+h070FnkHVEoU4+rmT6Vw0bmNl7s61VEkY/cJkL7RCv1p4urnUDUMrS5rk2w==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", + "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -5838,13 +5739,12 @@ } }, "node_modules/normalize-package-data": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.1.tgz", - "integrity": "sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "dev": true, "dependencies": { "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" }, @@ -5966,11 +5866,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "peer": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6195,8 +6098,7 @@ "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" }, "node_modules/pacote": { "version": "17.0.7", @@ -6243,6 +6145,20 @@ "node": ">=6" } }, + "node_modules/parse-imports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", + "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "dev": true, + "peer": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/patch-console": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", @@ -6274,7 +6190,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -6290,7 +6205,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -6688,43 +6602,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/read-package-json/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -6874,43 +6751,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/resolve-import/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/resolve-import/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/restore-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", @@ -6981,6 +6821,52 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7148,11 +7034,15 @@ "node": ">= 0.4" } }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -7164,7 +7054,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -7192,7 +7081,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -7239,6 +7127,13 @@ "node": ">=8" } }, + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true, + "peer": true + }, "node_modules/slice-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-6.0.0.tgz", @@ -7267,6 +7162,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -7292,14 +7199,14 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", - "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" @@ -7403,6 +7310,14 @@ "node": ">=8" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -7457,7 +7372,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -7475,7 +7389,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7488,23 +7401,12 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -7516,7 +7418,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -7610,7 +7511,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7623,7 +7523,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7698,59 +7597,39 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sync-content/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "node_modules/sync-content/node_modules/rimraf": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", + "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", "dev": true, "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" + "glob": "^10.3.7" }, "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sync-content/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" + "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sync-content/node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "node_modules/synckit": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", + "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", "dev": true, + "peer": true, "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.18" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://opencollective.com/unts" } }, "node_modules/tap": { @@ -7918,6 +7797,27 @@ "concat-map": "0.0.1" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/test-exclude/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7965,6 +7865,14 @@ "node": ">=12" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -8010,9 +7918,9 @@ } }, "node_modules/tshy": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.15.1.tgz", - "integrity": "sha512-7p30vmXaNX7OL1yLy/MYUtO0SJOm9fQSnzk3DXaM+LmQosooCB4elVeHAGIIZdABhL2E8dx5t/5msR5lh0xnaQ==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.17.0.tgz", + "integrity": "sha512-95BrHQTZCrJ3LnoGQoDCv7PtyNKyIIY9A9FPgY04IpsmV0URmlI8OWjMkQWRONUAJqJeJCij9p8REXLuv+7MXg==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -8020,11 +7928,11 @@ "foreground-child": "^3.1.1", "minimatch": "^9.0.4", "mkdirp": "^3.0.1", - "polite-json": "^4.0.1", + "polite-json": "^5.0.0", "resolve-import": "^1.4.5", "rimraf": "^5.0.1", "sync-content": "^1.0.2", - "typescript": "^5.4.5", + "typescript": "5", "walk-up-path": "^3.0.1" }, "bin": { @@ -8046,47 +7954,37 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/tshy/node_modules/glob": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", - "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "node_modules/tshy/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/tshy/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/tshy/node_modules/polite-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/polite-json/-/polite-json-5.0.0.tgz", + "integrity": "sha512-OLS/0XeUAcE8a2fdwemNja+udKgXNnY6yKVIXqAD2zVRx1KvY6Ato/rZ2vdzbxqYwPW0u6SCNC/bAMPNzpzxbw==", "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tshy/node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", + "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -8095,7 +7993,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -8225,9 +8123,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -8314,9 +8212,9 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -8376,7 +8274,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -8499,7 +8396,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -8517,7 +8413,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -8533,23 +8428,12 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8563,7 +8447,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -8575,7 +8458,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -8587,7 +8469,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -8604,9 +8485,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "engines": { "node": ">=10.0.0" @@ -8697,15 +8578,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/components/log-viewer-webui/server/package.json b/components/log-viewer-webui/server/package.json index 01401a527..e7e52d521 100644 --- a/components/log-viewer-webui/server/package.json +++ b/components/log-viewer-webui/server/package.json @@ -14,6 +14,7 @@ "license": "Apache-2.0", "type": "module", "dependencies": { + "@fastify/static": "^7.0.4", "dotenv": "^16.4.5", "fastify": "^4.28.0", "http-status-codes": "^2.3.0", diff --git a/components/log-viewer-webui/server/src/app.js b/components/log-viewer-webui/server/src/app.js index 22982c352..d67b7136a 100644 --- a/components/log-viewer-webui/server/src/app.js +++ b/components/log-viewer-webui/server/src/app.js @@ -1,4 +1,8 @@ import fastify from "fastify"; +import * as path from "node:path"; +import process from "node:process"; + +import {fastifyStatic} from "@fastify/static"; import exampleRoutes from "./routes/examples.js"; @@ -6,11 +10,26 @@ import exampleRoutes from "./routes/examples.js"; /** * Creates the Fastify app with the given options. * + * @param {string} clientDir Absolute path to the client directory to serve when in running in a + * production environment. * @param {import("fastify").FastifyServerOptions} fastifyOptions * @return {Promise} */ -const app = async (fastifyOptions = {}) => { +const app = async (clientDir, fastifyOptions = {}) => { const server = fastify(fastifyOptions); + + if ("production" === process.env.NODE_ENV) { + // In the development environment, we expect the client to use a separate webserver that + // supports live reloading. + if (false === path.isAbsolute(clientDir)) { + throw new Error("`clientDir` must be an absolute path."); + } + + await server.register(fastifyStatic, { + prefix: "/", + root: clientDir, + }); + } await server.register(exampleRoutes); return server; diff --git a/components/log-viewer-webui/server/src/main.js b/components/log-viewer-webui/server/src/main.js index 706040dce..f1507d3ef 100644 --- a/components/log-viewer-webui/server/src/main.js +++ b/components/log-viewer-webui/server/src/main.js @@ -1,4 +1,5 @@ import dotenv from "dotenv"; +import * as path from "node:path"; import process from "node:process"; import app from "./app.js"; @@ -7,7 +8,7 @@ import app from "./app.js"; /** * Parses environment variables into config values for the application. * - * @return {{PORT: string, HOST: string}} + * @return {{CLIENT_DIR: string, HOST: string, PORT: string}} * @throws {Error} if any required environment variable is undefined. */ const parseEnvVars = () => { @@ -16,10 +17,10 @@ const parseEnvVars = () => { }); const { - HOST, PORT, + CLIENT_DIR, HOST, PORT, } = process.env; const envVars = { - HOST, PORT, + CLIENT_DIR, HOST, PORT, }; // Check for mandatory environment variables @@ -45,12 +46,13 @@ const main = async () => { production: true, test: false, }; - const server = await app({ + + const envVars = parseEnvVars(); + const server = await app(path.resolve(envVars.CLIENT_DIR), { logger: envToLogger[process.env.NODE_ENV] ?? true, }); try { - const envVars = parseEnvVars(); await server.listen({host: envVars.HOST, port: Number(envVars.PORT)}); } catch (e) { server.log.error(e); From 6e2166592869e70aa603acbfeab53df396f70e29 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Mon, 8 Jul 2024 01:21:43 -0400 Subject: [PATCH 023/114] linting: Add log-viewer-webui to js-lint tasks. (#475) Co-authored-by: Junhao Liao --- Taskfile.yml | 99 +++++++++++++++++++ .../dev-guide/components-log-viewer-webui.md | 22 ++++- lint-tasks.yml | 62 ++++++------ 3 files changed, 149 insertions(+), 34 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index edce5c074..2e3422168 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -10,6 +10,7 @@ vars: G_BUILD_DIR: "{{.ROOT_DIR}}/build" G_CORE_COMPONENT_BUILD_DIR: "{{.G_BUILD_DIR}}/core" G_METEOR_BUILD_DIR: "{{.G_BUILD_DIR}}/meteor" + G_NODEJS_22_DIR: "{{.G_BUILD_DIR}}/nodejs-22" G_PACKAGE_BUILD_DIR: "{{.G_BUILD_DIR}}/clp-package" G_PACKAGE_VENV_DIR: "{{.G_BUILD_DIR}}/package-venv" G_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/webui" @@ -26,6 +27,7 @@ tasks: clean: cmds: - "rm -rf '{{.G_BUILD_DIR}}'" + - task: "clean-log-viewer-webui" - task: "clean-python-component" vars: COMPONENT: "clp-package-utils" @@ -35,6 +37,18 @@ tasks: - task: "clean-python-component" vars: COMPONENT: "job-orchestration" + - task: "clean-webui" + + clean-log-viewer-webui: + cmds: + - "rm -rf 'components/log-viewer-webui/client/node_modules'" + - "rm -rf 'components/log-viewer-webui/node_modules'" + - "rm -rf 'components/log-viewer-webui/server/node_modules'" + + clean-webui: + cmds: + - "rm -rf 'components/webui/.meteor/local'" + - "rm -rf 'components/webui/node_modules'" clp-json-pkg-tar: cmds: @@ -204,6 +218,19 @@ tasks: - "tests/**/*" generates: ["{{.CHECKSUM_FILE}}"] + nodejs-22: + internal: true + vars: + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" + OUTPUT_DIR: "{{.G_NODEJS_22_DIR}}" + run: "once" + cmds: + - task: "nodejs" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + NODEJS_VERSION: "v22.4.0" + OUTPUT_DIR: "{{.OUTPUT_DIR}}" + webui-nodejs: internal: true vars: @@ -274,6 +301,78 @@ tasks: sources: ["{{.TASKFILE}}"] generates: ["{{.CHECKSUM_FILE}}"] + # NOTE: The log-viewer-webui has three different node_modules directories (client, server, and the + # top-level one we call "package"), meaning we have to create three different checksums. To allow + # tasks which depend on this task to only have to check one checksum file, we concatenate the + # three checksum files into one. + log-viewer-webui-node-modules: + internal: true + vars: + # Checksum files + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" + CLIENT_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-client-node-modules.md5" + PACKAGE_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-package-node-modules.md5" + SERVER_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-server-node-modules.md5" + + # Directories + SRC_DIR: "{{.TASKFILE_DIR}}/components/log-viewer-webui" + CLIENT_OUTPUT_DIR: "{{.SRC_DIR}}/client/node_modules" + PACKAGE_OUTPUT_DIR: "{{.SRC_DIR}}/node_modules" + SERVER_OUTPUT_DIR: "{{.SRC_DIR}}/server/node_modules" + dir: "{{.SRC_DIR}}" + deps: + - "nodejs-22" + - task: "utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CLIENT_CHECKSUM_FILE}}" + DATA_DIR: "{{.CLIENT_OUTPUT_DIR}}" + - task: "utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.SERVER_CHECKSUM_FILE}}" + DATA_DIR: "{{.SERVER_OUTPUT_DIR}}" + - task: "utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.PACKAGE_CHECKSUM_FILE}}" + DATA_DIR: "{{.PACKAGE_OUTPUT_DIR}}" + cmds: + - "rm -f {{.CHECKSUM_FILE}}" + - task: "clean-log-viewer-webui" + - "PATH='{{.G_NODEJS_22_DIR}}/bin':$PATH npm run init" + # These commands must be last + - task: "utils:compute-checksum" + vars: + DATA_DIR: "{{.CLIENT_OUTPUT_DIR}}" + OUTPUT_FILE: "{{.CLIENT_CHECKSUM_FILE}}" + - task: "utils:compute-checksum" + vars: + DATA_DIR: "{{.PACKAGE_OUTPUT_DIR}}" + OUTPUT_FILE: "{{.PACKAGE_CHECKSUM_FILE}}" + - task: "utils:compute-checksum" + vars: + DATA_DIR: "{{.SERVER_OUTPUT_DIR}}" + OUTPUT_FILE: "{{.SERVER_CHECKSUM_FILE}}" + # This command must be last + - >- + cat + "{{.CLIENT_CHECKSUM_FILE}}" + "{{.PACKAGE_CHECKSUM_FILE}}" + "{{.SERVER_CHECKSUM_FILE}}" + > "{{.CHECKSUM_FILE}}" + sources: + - "{{.G_BUILD_DIR}}/nodejs-22.md5" + - "{{.TASKFILE}}" + - "client/package.json" + - "client/package-lock.json" + - "package.json" + - "package-lock.json" + - "server/package.json" + - "server/package-lock.json" + generates: + - "{{.CHECKSUM_FILE}}" + - "{{.CLIENT_CHECKSUM_FILE}}" + - "{{.PACKAGE_CHECKSUM_FILE}}" + - "{{.SERVER_CHECKSUM_FILE}}" + meteor: run: "once" preconditions: diff --git a/docs/src/dev-guide/components-log-viewer-webui.md b/docs/src/dev-guide/components-log-viewer-webui.md index e1facc232..463d67c78 100644 --- a/docs/src/dev-guide/components-log-viewer-webui.md +++ b/docs/src/dev-guide/components-log-viewer-webui.md @@ -50,13 +50,31 @@ npm test ## Linting -To check for linting errors in either the client or server: +You can lint this component either as part of the entire project or as a standalone component. + +### Lint as part of the project + +To check for linting errors: + +```shell +task lint:js-check +``` + +To also fix linting errors (if applicable): + +```shell +task lint:js-fix +``` + +### Lint the component alone + +To check for linting errors: ```shell npm run lint:check ``` -To also fix linting errors (if possible): +To also fix linting errors (if applicable): ```shell npm run lint:fix diff --git a/lint-tasks.yml b/lint-tasks.yml index 996b49734..075ee2ec8 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -1,9 +1,10 @@ version: "3" vars: - G_LINTER_NODEJS_BUILD_DIR: "{{.G_BUILD_DIR}}/linter-nodejs" - G_LINTER_NODEJS_BIN_DIR: "{{.G_LINTER_NODEJS_BUILD_DIR}}/bin" G_LINT_VENV_DIR: "{{.G_BUILD_DIR}}/lint-venv" + G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" + G_NODEJS_22_BIN_DIR: "{{.G_NODEJS_22_DIR}}/bin" + G_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/webui" tasks: check: @@ -47,29 +48,34 @@ tasks: sources: *cpp_source_files js-check: - dir: "components/webui" cmds: - task: "js" vars: LINT_CMD: "check" sources: &js_source_files - "{{.G_BUILD_DIR}}/lint#linter-node-modules.md5" + - "{{.G_BUILD_DIR}}/log-viewer-webui-node-modules.md5" - "{{.G_BUILD_DIR}}/webui-node-modules.md5" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/**/*.css" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/**/*.jsx" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/package.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/webpack.config.js" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/*.js" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/package.json" + - "{{.G_WEBUI_SRC_DIR}}/client/**/*.js" + - "{{.G_WEBUI_SRC_DIR}}/client/**/*.jsx" + - "{{.G_WEBUI_SRC_DIR}}/imports/**/*.js" + - "{{.G_WEBUI_SRC_DIR}}/imports/**/*.jsx" + - "{{.G_WEBUI_SRC_DIR}}/launcher.js" + - "{{.G_WEBUI_SRC_DIR}}/package.json" + - "{{.G_WEBUI_SRC_DIR}}/server/**/*.js" + - "{{.G_WEBUI_SRC_DIR}}/server/**/*.jsx" + - "{{.G_WEBUI_SRC_DIR}}/tests/**/*.js" + - "{{.G_WEBUI_SRC_DIR}}/tests/**/*.jsx" - "{{.ROOT_DIR}}/Taskfile.yml" - "{{.TASKFILE}}" - - "client/**/*.js" - - "client/**/*.jsx" - - "imports/**/*.js" - - "imports/**/*.jsx" - - "launcher.js" - - "package.json" - - "server/**/*.js" - - "server/**/*.jsx" - - "tests/**/*.js" - - "tests/**/*.jsx" js-fix: - dir: "components/webui" cmds: - task: "js" vars: @@ -127,10 +133,14 @@ tasks: internal: true requires: vars: ["LINT_CMD"] - deps: ["linter-node-modules"] - dir: "components/webui" + deps: [":log-viewer-webui-node-modules", "linter-node-modules"] cmds: - - "PATH='{{.G_LINTER_NODEJS_BIN_DIR}}':$PATH npm run 'lint:{{.LINT_CMD}}'" + - for: + - "components/log-viewer-webui" + - "components/webui" + cmd: |- + cd "{{.ITEM}}" + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run "lint:{{.LINT_CMD}}" py: internal: true @@ -149,18 +159,6 @@ tasks: black --color --line-length 100 {{.BLACK_FLAGS}} . ruff check {{.RUFF_FLAGS}} . - linter-nodejs: - internal: true - vars: - CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK | replace \":\" \"#\"}}.md5" - OUTPUT_DIR: "{{.G_LINTER_NODEJS_BUILD_DIR}}" - cmds: - - task: ":nodejs" - vars: - CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" - NODEJS_VERSION: "latest" - OUTPUT_DIR: "{{.OUTPUT_DIR}}" - linter-node-modules: internal: true deps: @@ -170,7 +168,7 @@ tasks: vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" - - "linter-nodejs" + - ":nodejs-22" dir: "{{.WEBUI_LINTER_DIR}}" vars: WEBUI_LINTER_DIR: "{{.ROOT_DIR}}/components/webui/linter" @@ -178,14 +176,14 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK | replace \":\" \"#\"}}.md5" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - - "PATH='{{.G_LINTER_NODEJS_BIN_DIR}}':$PATH npm update" + - "PATH='{{.G_NODEJS_22_BIN_DIR}}':$PATH npm update" # This command must be last - task: ":utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" sources: - - "{{.G_BUILD_DIR}}/lint#linter-nodejs.md5" + - "{{.G_BUILD_DIR}}/nodejs-22.md5" - "{{.G_BUILD_DIR}}/webui-node-modules.md5" - "{{.ROOT_DIR}}/Taskfile.yml" - "{{.TASKFILE}}" From 437607a5ccc11c4bd5d2bae9f2699a8120f46dfc Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:47:49 -0400 Subject: [PATCH 024/114] clp-core: Replace calls to incomplete UTF-8 validation function with new and complete implementation. (#477) --- components/core/src/clp/clp/CMakeLists.txt | 2 ++ .../core/src/clp/clp/FileCompressor.cpp | 9 ++--- components/core/src/clp/clp/utils.cpp | 34 ------------------- components/core/src/clp/clp/utils.hpp | 8 ----- 4 files changed, 7 insertions(+), 46 deletions(-) diff --git a/components/core/src/clp/clp/CMakeLists.txt b/components/core/src/clp/clp/CMakeLists.txt index b8e073dd1..0f18777d9 100644 --- a/components/core/src/clp/clp/CMakeLists.txt +++ b/components/core/src/clp/clp/CMakeLists.txt @@ -133,6 +133,8 @@ set( ../TimestampPattern.hpp ../TraceableException.hpp ../type_utils.hpp + ../utf8_utils.cpp + ../utf8_utils.hpp ../Utils.cpp ../Utils.hpp ../VariableDictionaryEntry.cpp diff --git a/components/core/src/clp/clp/FileCompressor.cpp b/components/core/src/clp/clp/FileCompressor.cpp index 4100816f5..9898602cc 100644 --- a/components/core/src/clp/clp/FileCompressor.cpp +++ b/components/core/src/clp/clp/FileCompressor.cpp @@ -16,6 +16,7 @@ #include "../LogSurgeonReader.hpp" #include "../Profiler.hpp" #include "../streaming_archive/writer/utils.hpp" +#include "../utf8_utils.hpp" #include "utils.hpp" using clp::ir::eight_byte_encoded_variable_t; @@ -145,8 +146,8 @@ bool FileCompressor::compress_file( size_t peek_size{0}; m_file_reader.peek_buffered_data(utf8_validation_buf, peek_size); bool succeeded = true; - auto utf8_validation_buf_len = std::min(peek_size, cUtfMaxValidationLen); - if (is_utf8_sequence(utf8_validation_buf_len, utf8_validation_buf)) { + auto const utf8_validation_buf_len = std::min(peek_size, cUtfMaxValidationLen); + if (is_utf8_encoded({utf8_validation_buf, utf8_validation_buf_len})) { if (use_heuristic) { parse_and_encode_with_heuristic( target_data_size_of_dicts, @@ -359,8 +360,8 @@ bool FileCompressor::try_compressing_as_archive( size_t peek_size{0}; m_libarchive_file_reader.peek_buffered_data(utf8_validation_buf, peek_size); string file_path{m_libarchive_reader.get_path()}; - auto utf8_validation_buf_len = std::min(peek_size, cUtfMaxValidationLen); - if (is_utf8_sequence(utf8_validation_buf_len, utf8_validation_buf)) { + auto const utf8_validation_buf_len = std::min(peek_size, cUtfMaxValidationLen); + if (is_utf8_encoded({utf8_validation_buf, utf8_validation_buf_len})) { auto boost_path_for_compression = parent_boost_path / file_path; if (use_heuristic) { parse_and_encode_with_heuristic( diff --git a/components/core/src/clp/clp/utils.cpp b/components/core/src/clp/clp/utils.cpp index 5ba59e0d7..0f05d75ac 100644 --- a/components/core/src/clp/clp/utils.cpp +++ b/components/core/src/clp/clp/utils.cpp @@ -86,40 +86,6 @@ bool find_all_files_and_empty_directories( return true; } -bool is_utf8_sequence(size_t sequence_length, char const* sequence) { - size_t num_utf8_bytes_to_read = 0; - for (size_t i = 0; i < sequence_length; ++i) { - auto byte = sequence[i]; - - if (num_utf8_bytes_to_read > 0) { - // Validate that byte matches 0b10xx_xxxx - if ((byte & 0xC0) != 0x80) { - return false; - } - --num_utf8_bytes_to_read; - } else { - if (byte & 0x80) { - // Check if byte is valid UTF-8 length-indicator - if ((byte & 0xF8) == 0xF0) { - // Matches 0b1111_0xxx - num_utf8_bytes_to_read = 3; - } else if ((byte & 0xF0) == 0xE0) { - // Matches 0b1110_xxxx - num_utf8_bytes_to_read = 2; - } else if ((byte & 0xE0) == 0xC0) { - // Matches 0b110x_xxxx - num_utf8_bytes_to_read = 1; - } else { - // Invalid UTF-8 length-indicator - return false; - } - } // else byte is ASCII - } - } - - return true; -} - bool read_input_paths(string const& list_path, vector& paths) { ErrorCode error_code = read_list_of_paths(list_path, paths); if (ErrorCode_Success != error_code) { diff --git a/components/core/src/clp/clp/utils.hpp b/components/core/src/clp/clp/utils.hpp index 41e7a3694..0a6918445 100644 --- a/components/core/src/clp/clp/utils.hpp +++ b/components/core/src/clp/clp/utils.hpp @@ -41,14 +41,6 @@ bool find_all_files_and_empty_directories( std::vector& empty_directory_paths ); -/** - * Checks if the given sequence is valid UTF-8 - * @param sequence_length - * @param sequence - * @return true if valid, false otherwise - */ -bool is_utf8_sequence(size_t sequence_length, char const* sequence); - /** * Reads a list of input paths * @param list_path From 94d96d3e09b193d1a4658c79ffad257cbe3cd11d Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Fri, 12 Jul 2024 17:11:51 -0400 Subject: [PATCH 025/114] clp-package: Add log-viewer-webui as a component. (#476) --- Taskfile.yml | 82 ++++++++++++++++--- .../clp_package_utils/general.py | 14 ++++ .../clp_package_utils/scripts/start_clp.py | 77 +++++++++++++++-- .../clp_package_utils/scripts/stop_clp.py | 12 ++- .../clp-py-utils/clp_py_utils/clp_config.py | 43 ++++++++-- .../package-template/src/etc/clp-config.yml | 4 + lint-tasks.yml | 1 - 7 files changed, 203 insertions(+), 30 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 2e3422168..9763307a7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -9,13 +9,15 @@ vars: # Paths G_BUILD_DIR: "{{.ROOT_DIR}}/build" G_CORE_COMPONENT_BUILD_DIR: "{{.G_BUILD_DIR}}/core" + G_LOG_VIEWER_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/log-viewer-webui" G_METEOR_BUILD_DIR: "{{.G_BUILD_DIR}}/meteor" - G_NODEJS_22_DIR: "{{.G_BUILD_DIR}}/nodejs-22" + G_NODEJS_14_BUILD_DIR: "{{.G_BUILD_DIR}}/nodejs-14" + G_NODEJS_14_BIN_DIR: "{{.G_NODEJS_14_BUILD_DIR}}/bin" + G_NODEJS_22_BUILD_DIR: "{{.G_BUILD_DIR}}/nodejs-22" + G_NODEJS_22_BIN_DIR: "{{.G_NODEJS_22_BUILD_DIR}}/bin" G_PACKAGE_BUILD_DIR: "{{.G_BUILD_DIR}}/clp-package" G_PACKAGE_VENV_DIR: "{{.G_BUILD_DIR}}/package-venv" G_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/webui" - G_WEBUI_NODEJS_BUILD_DIR: "{{.G_BUILD_DIR}}/webui-nodejs" - G_WEBUI_NODEJS_BIN_DIR: "{{.G_WEBUI_NODEJS_BUILD_DIR}}/bin" # Versions G_PACKAGE_VERSION: "0.2.0-dev" @@ -65,6 +67,8 @@ tasks: STORAGE_ENGINE: "clp" package: + env: + NODE_ENV: "production" vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_PACKAGE_BUILD_DIR}}" @@ -74,13 +78,14 @@ tasks: - "clp-py-utils" - "init" - "job-orchestration" + - "log-viewer-webui" + - "nodejs-14" - "package-venv" - task: "utils:validate-checksum" vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" - "webui" - - "webui-nodejs" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - "rsync -a components/package-template/src/ '{{.OUTPUT_DIR}}'" @@ -101,16 +106,32 @@ tasks: "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" - "{{.G_WEBUI_NODEJS_BIN_DIR}}/node" "{{.OUTPUT_DIR}}/bin/" + - >- + rsync -a + "{{.G_NODEJS_14_BIN_DIR}}/node" + "{{.OUTPUT_DIR}}/bin/node-14" + - >- + rsync -a + "{{.G_NODEJS_22_BIN_DIR}}/node" + "{{.OUTPUT_DIR}}/bin/node-22" - "mkdir -p '{{.OUTPUT_DIR}}/var/www/'" - >- rsync -a "{{.G_WEBUI_BUILD_DIR}}/" - "{{.OUTPUT_DIR}}/var/www/" + "{{.OUTPUT_DIR}}/var/www/webui/" + # Avoid using `npm clean-install` because Meteor does not generate a `package-lock.json` file, + # which `clean-install` depends on. + - |- + cd "{{.OUTPUT_DIR}}/var/www/webui/programs/server" + PATH="{{.G_NODEJS_14_BIN_DIR}}":$PATH npm install + - >- + rsync -a + "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/" + "{{.OUTPUT_DIR}}/var/www/log_viewer/" - |- - cd "{{.OUTPUT_DIR}}/var/www/programs/server" - PATH="{{.G_WEBUI_NODEJS_BIN_DIR}}":$PATH npm install + cd "{{.OUTPUT_DIR}}/var/www/log_viewer/server" + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm clean-install # This command must be last - task: "utils:compute-checksum" vars: @@ -174,6 +195,43 @@ tasks: vars: COMPONENT: "{{.TASK}}" + log-viewer-webui: + deps: + - "init" + - "log-viewer-webui-node-modules" + - task: "utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.OUTPUT_DIR}}" + dir: "components/log-viewer-webui" + vars: + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" + OUTPUT_DIR: "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}" + cmds: + - "rm -rf '{{.OUTPUT_DIR}}'" + - "rsync -a client {{.OUTPUT_DIR}}/" + - |- + cd "{{.OUTPUT_DIR}}/client" + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build + - "mkdir {{.OUTPUT_DIR}}/server" + - |- + cd server + rsync -a src package-lock.json package.json {{.OUTPUT_DIR}}/server/ + - task: "utils:compute-checksum" + vars: + DATA_DIR: "{{.OUTPUT_DIR}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + sources: + - "{{.G_BUILD_DIR}}/log-viewer-modules.md5" + - "{{.TASKFILE}}" + - "client/src/**/*.css" + - "client/src/**/*.jsx" + - "client/src/package.json" + - "client/src/webpack.config.js" + - "server/src/**/*.js" + - "server/src/**/package.json" + generates: ["{{.CHECKSUM_FILE}}"] + webui: deps: - "init" @@ -222,7 +280,7 @@ tasks: internal: true vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" - OUTPUT_DIR: "{{.G_NODEJS_22_DIR}}" + OUTPUT_DIR: "{{.G_NODEJS_22_BUILD_DIR}}" run: "once" cmds: - task: "nodejs" @@ -231,11 +289,11 @@ tasks: NODEJS_VERSION: "v22.4.0" OUTPUT_DIR: "{{.OUTPUT_DIR}}" - webui-nodejs: + nodejs-14: internal: true vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" - OUTPUT_DIR: "{{.G_WEBUI_NODEJS_BUILD_DIR}}" + OUTPUT_DIR: "{{.G_NODEJS_14_BUILD_DIR}}" cmds: - task: "nodejs" vars: @@ -337,7 +395,7 @@ tasks: cmds: - "rm -f {{.CHECKSUM_FILE}}" - task: "clean-log-viewer-webui" - - "PATH='{{.G_NODEJS_22_DIR}}/bin':$PATH npm run init" + - "PATH='{{.G_NODEJS_22_BIN_DIR}}':$PATH npm run init" # These commands must be last - task: "utils:compute-checksum" vars: diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index b84bf298e..a2e6e344f 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -15,6 +15,7 @@ CLP_DEFAULT_CREDENTIALS_FILE_PATH, CLPConfig, DB_COMPONENT_NAME, + LOG_VIEWER_WEBUI_COMPONENT_NAME, QUEUE_COMPONENT_NAME, REDIS_COMPONENT_NAME, REDUCER_COMPONENT_NAME, @@ -494,3 +495,16 @@ def validate_webui_config( raise ValueError(f"{WEBUI_COMPONENT_NAME} logs directory is invalid: {ex}") validate_port(f"{WEBUI_COMPONENT_NAME}.port", clp_config.webui.host, clp_config.webui.port) + + +def validate_log_viewer_config(clp_config: CLPConfig, logs_dir: pathlib.Path): + try: + validate_path_could_be_dir(logs_dir) + except ValueError as ex: + raise ValueError(f"{LOG_VIEWER_WEBUI_COMPONENT_NAME} logs directory is invalid: {ex}") + + validate_port( + f"{LOG_VIEWER_WEBUI_COMPONENT_NAME}.port", + clp_config.log_viewer_webui.host, + clp_config.log_viewer_webui.port, + ) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 9dba79886..4c072752e 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -21,6 +21,7 @@ COMPRESSION_WORKER_COMPONENT_NAME, CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME, + LOG_VIEWER_WEBUI_COMPONENT_NAME, QUERY_JOBS_TABLE_NAME, QUERY_SCHEDULER_COMPONENT_NAME, QUERY_WORKER_COMPONENT_NAME, @@ -49,6 +50,7 @@ validate_and_load_queue_credentials_file, validate_and_load_redis_credentials_file, validate_db_config, + validate_log_viewer_config, validate_queue_config, validate_redis_config, validate_reducer_config, @@ -698,10 +700,9 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts return webui_logs_dir = clp_config.logs_directory / component_name - node_path = str( - CONTAINER_CLP_HOME / "var" / "www" / "programs" / "server" / "npm" / "node_modules" - ) - settings_json_path = get_clp_home() / "var" / "www" / "settings.json" + container_webui_dir = CONTAINER_CLP_HOME / "var" / "www" / "webui" + node_path = str(container_webui_dir / "programs" / "server" / "npm" / "node_modules") + settings_json_path = get_clp_home() / "var" / "www" / "webui" / "settings.json" validate_webui_config(clp_config, webui_logs_dir, settings_json_path) @@ -758,9 +759,67 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts container_cmd.append(clp_config.execution_container) node_cmd = [ - str(CONTAINER_CLP_HOME / "bin" / "node"), - str(CONTAINER_CLP_HOME / "var" / "www" / "launcher.js"), - str(CONTAINER_CLP_HOME / "var" / "www" / "main.js"), + str(CONTAINER_CLP_HOME / "bin" / "node-14"), + str(container_webui_dir / "launcher.js"), + str(container_webui_dir / "main.js"), + ] + cmd = container_cmd + node_cmd + subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) + + logger.info(f"Started {component_name}.") + + +def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts): + component_name = LOG_VIEWER_WEBUI_COMPONENT_NAME + logger.info(f"Starting {component_name}...") + + container_name = f"clp-{component_name}-{instance_id}" + if container_exists(container_name): + return + + log_viewer_webui_logs_dir = clp_config.logs_directory / component_name + container_log_viewer_dir = CONTAINER_CLP_HOME / "var" / "www" / "log_viewer" + node_path = str(container_log_viewer_dir / "server" / "node_modules") + + validate_log_viewer_config(clp_config, log_viewer_webui_logs_dir) + + # Create directories + log_viewer_webui_logs_dir.mkdir(exist_ok=True, parents=True) + + container_log_viewer_webui_logs_dir = pathlib.Path("/") / "var" / "log" / component_name + + # Start container + # fmt: off + container_cmd = [ + "docker", "run", + "-d", + "--network", "host", + "--name", container_name, + "--log-driver", "local", + "-e", f"NODE_PATH={node_path}", + "-e", f"CLIENT_DIR={container_log_viewer_dir}/client/dist", + "-e", f"PORT={clp_config.log_viewer_webui.port}", + "-e", f"HOST={clp_config.log_viewer_webui.host}", + "-e", f"NODE_ENV=production", + "-u", f"{os.getuid()}:{os.getgid()}", + ] + # fmt: on + necessary_mounts = [ + mounts.clp_home, + mounts.ir_output_dir, + DockerMount( + DockerMountType.BIND, log_viewer_webui_logs_dir, container_log_viewer_webui_logs_dir + ), + ] + for mount in necessary_mounts: + if mount: + container_cmd.append("--mount") + container_cmd.append(str(mount)) + container_cmd.append(clp_config.execution_container) + + node_cmd = [ + str(CONTAINER_CLP_HOME / "bin" / "node-22"), + str(container_log_viewer_dir / "server" / "src" / "main.js"), ] cmd = container_cmd + node_cmd subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) @@ -870,6 +929,7 @@ def main(argv): reducer_server_parser = component_args_parser.add_parser(REDUCER_COMPONENT_NAME) add_num_workers_argument(reducer_server_parser) component_args_parser.add_parser(WEBUI_COMPONENT_NAME) + component_args_parser.add_parser(LOG_VIEWER_WEBUI_COMPONENT_NAME) parsed_args = args_parser.parse_args(argv[1:]) @@ -897,6 +957,7 @@ def main(argv): COMPRESSION_SCHEDULER_COMPONENT_NAME, QUERY_SCHEDULER_COMPONENT_NAME, WEBUI_COMPONENT_NAME, + LOG_VIEWER_WEBUI_COMPONENT_NAME, ): validate_and_load_db_credentials_file(clp_config, clp_home, True) if target in ( @@ -984,6 +1045,8 @@ def main(argv): start_reducer(instance_id, clp_config, container_clp_config, num_workers, mounts) if target in (ALL_TARGET_NAME, WEBUI_COMPONENT_NAME): start_webui(instance_id, clp_config, mounts) + if target in (ALL_TARGET_NAME, LOG_VIEWER_WEBUI_COMPONENT_NAME): + start_log_viewer_webui(instance_id, clp_config, mounts) except Exception as ex: if type(ex) == ValueError: diff --git a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py index 7971dd7d8..f100a098a 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py @@ -11,6 +11,7 @@ COMPRESSION_WORKER_COMPONENT_NAME, CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME, + LOG_VIEWER_WEBUI_COMPONENT_NAME, QUERY_SCHEDULER_COMPONENT_NAME, QUERY_WORKER_COMPONENT_NAME, QUEUE_COMPONENT_NAME, @@ -92,6 +93,7 @@ def main(argv): component_args_parser.add_parser(COMPRESSION_WORKER_COMPONENT_NAME) component_args_parser.add_parser(QUERY_WORKER_COMPONENT_NAME) component_args_parser.add_parser(WEBUI_COMPONENT_NAME) + component_args_parser.add_parser(LOG_VIEWER_WEBUI_COMPONENT_NAME) parsed_args = args_parser.parse_args(argv[1:]) @@ -106,7 +108,12 @@ def main(argv): clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) # Validate and load necessary credentials - if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, DB_COMPONENT_NAME): + if target in ( + ALL_TARGET_NAME, + CONTROLLER_TARGET_NAME, + DB_COMPONENT_NAME, + LOG_VIEWER_WEBUI_COMPONENT_NAME, + ): validate_and_load_db_credentials_file(clp_config, clp_home, False) if target in ( ALL_TARGET_NAME, @@ -134,6 +141,9 @@ def main(argv): already_exited_containers = [] force = parsed_args.force + if target in (ALL_TARGET_NAME, LOG_VIEWER_WEBUI_COMPONENT_NAME): + container_name = f"clp-{LOG_VIEWER_WEBUI_COMPONENT_NAME}-{instance_id}" + stop_running_container(container_name, already_exited_containers, force) if target in (ALL_TARGET_NAME, WEBUI_COMPONENT_NAME): container_name = f"clp-{WEBUI_COMPONENT_NAME}-{instance_id}" stop_running_container(container_name, already_exited_containers, force) diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index 0c0ce6893..9485b43c2 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -26,6 +26,7 @@ COMPRESSION_WORKER_COMPONENT_NAME = "compression_worker" QUERY_WORKER_COMPONENT_NAME = "query_worker" WEBUI_COMPONENT_NAME = "webui" +LOG_VIEWER_WEBUI_COMPONENT_NAME = "log_viewer_webui" # Target names ALL_TARGET_NAME = "" @@ -153,6 +154,20 @@ def _validate_logging_level(cls, field): ) +def _validate_host(cls, field): + if "" == field: + raise ValueError(f"{cls.__name__}.host cannot be empty.") + + +def _validate_port(cls, field): + min_valid_port = 0 + max_valid_port = 2**16 - 1 + if min_valid_port > field or max_valid_port < field: + raise ValueError( + f"{cls.__name__}.port is not within valid range " f"{min_valid_port}-{max_valid_port}." + ) + + class CompressionScheduler(BaseModel): jobs_poll_delay: float = 0.1 # seconds logging_level: str = "INFO" @@ -361,19 +376,12 @@ class WebUi(BaseModel): @validator("host") def validate_host(cls, field): - if "" == field: - raise ValueError(f"{WEBUI_COMPONENT_NAME}.host cannot be empty.") + _validate_host(cls, field) return field @validator("port") def validate_port(cls, field): - min_valid_port = 0 - max_valid_port = 2**16 - 1 - if min_valid_port > field or max_valid_port < field: - raise ValueError( - f"{WEBUI_COMPONENT_NAME}.port is not within valid range " - f"{min_valid_port}-{max_valid_port}." - ) + _validate_port(cls, field) return field @validator("logging_level") @@ -382,6 +390,22 @@ def validate_logging_level(cls, field): return field +class LogViewerWebUi(BaseModel): + host: str = "localhost" + port: int = 3000 + logging_level: str = "INFO" + + @validator("host") + def validate_host(cls, field): + _validate_host(cls, field) + return field + + @validator("port") + def validate_port(cls, field): + _validate_port(cls, field) + return field + + class CLPConfig(BaseModel): execution_container: typing.Optional[str] @@ -398,6 +422,7 @@ class CLPConfig(BaseModel): compression_worker: CompressionWorker = CompressionWorker() query_worker: QueryWorker = QueryWorker() webui: WebUi = WebUi() + log_viewer_webui: LogViewerWebUi = LogViewerWebUi() credentials_file_path: pathlib.Path = CLP_DEFAULT_CREDENTIALS_FILE_PATH archive_output: ArchiveOutput = ArchiveOutput() diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index 3f658211e..ce626afa3 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -60,6 +60,10 @@ # port: 4000 # logging_level: "INFO" # +#log_viewer_webui +# host: "localhost" +# port: 3000 +# ## Where archives should be output to #archive_output: # directory: "var/data/archives" diff --git a/lint-tasks.yml b/lint-tasks.yml index 075ee2ec8..9cd3f1435 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -3,7 +3,6 @@ version: "3" vars: G_LINT_VENV_DIR: "{{.G_BUILD_DIR}}/lint-venv" G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" - G_NODEJS_22_BIN_DIR: "{{.G_NODEJS_22_DIR}}/bin" G_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/webui" tasks: From d9607af320547a6258fa9c35cc004a6eb4772d97 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:51:14 -0400 Subject: [PATCH 026/114] Taskfiles: Rearrange task attributes to match latest style guide. (#478) --- Taskfile.yml | 261 ++++++++++++++++++++++++------------------------- lint-tasks.yml | 58 +++++------ 2 files changed, 159 insertions(+), 160 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 9763307a7..e01bda896 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -72,6 +72,22 @@ tasks: vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_PACKAGE_BUILD_DIR}}" + sources: + - "{{.G_BUILD_DIR}}/package-venv.md5" + - "{{.G_BUILD_DIR}}/webui.md5" + - "{{.G_BUILD_DIR}}/webui-nodejs.md5" + - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clg" + - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clo" + - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" + - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" + - "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" + - "{{.TASKFILE}}" + - "/etc/os-release" + - "components/clp-package-utils/dist/*.whl" + - "components/clp-py-utils/dist/*.whl" + - "components/job-orchestration/dist/*.whl" + - "components/package-template/src/**/*" + generates: ["{{.CHECKSUM_FILE}}"] deps: - "core" - "clp-package-utils" @@ -137,35 +153,10 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.G_BUILD_DIR}}/package-venv.md5" - - "{{.G_BUILD_DIR}}/webui.md5" - - "{{.G_BUILD_DIR}}/webui-nodejs.md5" - - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clg" - - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clo" - - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" - - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" - - "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" - - "{{.TASKFILE}}" - - "/etc/os-release" - - "components/clp-package-utils/dist/*.whl" - - "components/clp-py-utils/dist/*.whl" - - "components/job-orchestration/dist/*.whl" - - "components/package-template/src/**/*" - generates: ["{{.CHECKSUM_FILE}}"] core: - deps: ["core-submodules", "init"] vars: SRC_DIR: "components/core" - cmds: - - "mkdir -p '{{.G_CORE_COMPONENT_BUILD_DIR}}'" - - "cmake -S '{{.SRC_DIR}}' -B '{{.G_CORE_COMPONENT_BUILD_DIR}}'" - - >- - cmake - --build "{{.G_CORE_COMPONENT_BUILD_DIR}}" - --parallel - --target clg clo clp clp-s reducer-server sources: - "{{.G_BUILD_DIR}}/core-submodules.md5" - "{{.SRC_DIR}}/cmake/**/*" @@ -179,6 +170,15 @@ tasks: - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" + deps: ["core-submodules", "init"] + cmds: + - "mkdir -p '{{.G_CORE_COMPONENT_BUILD_DIR}}'" + - "cmake -S '{{.SRC_DIR}}' -B '{{.G_CORE_COMPONENT_BUILD_DIR}}'" + - >- + cmake + --build "{{.G_CORE_COMPONENT_BUILD_DIR}}" + --parallel + --target clg clo clp clp-s reducer-server clp-package-utils: - task: "python-component" @@ -196,6 +196,20 @@ tasks: COMPONENT: "{{.TASK}}" log-viewer-webui: + vars: + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" + OUTPUT_DIR: "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}" + sources: + - "{{.G_BUILD_DIR}}/log-viewer-modules.md5" + - "{{.TASKFILE}}" + - "client/src/**/*.css" + - "client/src/**/*.jsx" + - "client/src/package.json" + - "client/src/webpack.config.js" + - "server/src/**/*.js" + - "server/src/**/package.json" + dir: "components/log-viewer-webui" + generates: ["{{.CHECKSUM_FILE}}"] deps: - "init" - "log-viewer-webui-node-modules" @@ -203,10 +217,6 @@ tasks: vars: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" - dir: "components/log-viewer-webui" - vars: - CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" - OUTPUT_DIR: "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - "rsync -a client {{.OUTPUT_DIR}}/" @@ -221,18 +231,24 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + webui: + vars: + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" + OUTPUT_DIR: "{{.G_WEBUI_BUILD_DIR}}" sources: - - "{{.G_BUILD_DIR}}/log-viewer-modules.md5" + - "{{.G_BUILD_DIR}}/meteor.md5" + - "{{.G_BUILD_DIR}}/webui-node-modules.md5" - "{{.TASKFILE}}" - - "client/src/**/*.css" - - "client/src/**/*.jsx" - - "client/src/package.json" - - "client/src/webpack.config.js" - - "server/src/**/*.js" - - "server/src/**/package.json" + - "*" + - ".meteor/*" + - "client/**/*" + - "imports/**/*" + - "server/**/*" + - "tests/**/*" + dir: "components/webui" + platforms: ["386", "amd64"] generates: ["{{.CHECKSUM_FILE}}"] - - webui: deps: - "init" - "meteor" @@ -241,11 +257,6 @@ tasks: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" - "webui-node-modules" - dir: "components/webui" - platforms: ["386", "amd64"] - vars: - CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" - OUTPUT_DIR: "{{.G_WEBUI_BUILD_DIR}}" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - "mkdir -p '{{.OUTPUT_DIR}}'" @@ -264,17 +275,6 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.G_BUILD_DIR}}/meteor.md5" - - "{{.G_BUILD_DIR}}/webui-node-modules.md5" - - "{{.TASKFILE}}" - - "*" - - ".meteor/*" - - "client/**/*" - - "imports/**/*" - - "server/**/*" - - "tests/**/*" - generates: ["{{.CHECKSUM_FILE}}"] nodejs-22: internal: true @@ -303,10 +303,15 @@ tasks: core-submodules: internal: true - dir: "components/core" vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "submodules" + sources: + - "{{.TASKFILE}}" + - ".gitmodules" + - "tools/scripts/deps-download/**/*" + dir: "components/core" + generates: ["{{.CHECKSUM_FILE}}"] deps: - "init" - task: "utils:validate-checksum" @@ -320,21 +325,18 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.TASKFILE}}" - - ".gitmodules" - - "tools/scripts/deps-download/**/*" - generates: ["{{.CHECKSUM_FILE}}"] download-and-extract-tar: internal: true - requires: - vars: ["CHECKSUM_FILE", "EXTRACTED_DIR_NAME", "TAR_NAME", "OUTPUT_DIR", "URL_PREFIX"] label: "{{.TASK}}-{{.TAR_NAME}}" vars: OUTPUT_TMP_DIR: "{{.OUTPUT_DIR}}-tmp" EXTRACTED_DIR: "{{.OUTPUT_TMP_DIR}}/{{.EXTRACTED_DIR_NAME}}" TAR_PATH: "{{.OUTPUT_TMP_DIR}}/{{.TAR_NAME}}" + requires: + vars: ["CHECKSUM_FILE", "EXTRACTED_DIR_NAME", "TAR_NAME", "OUTPUT_DIR", "URL_PREFIX"] + sources: ["{{.TASKFILE}}"] + generates: ["{{.CHECKSUM_FILE}}"] deps: - "init" - task: "utils:validate-checksum" @@ -356,8 +358,6 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: ["{{.TASKFILE}}"] - generates: ["{{.CHECKSUM_FILE}}"] # NOTE: The log-viewer-webui has three different node_modules directories (client, server, and the # top-level one we call "package"), meaning we have to create three different checksums. To allow @@ -377,7 +377,21 @@ tasks: CLIENT_OUTPUT_DIR: "{{.SRC_DIR}}/client/node_modules" PACKAGE_OUTPUT_DIR: "{{.SRC_DIR}}/node_modules" SERVER_OUTPUT_DIR: "{{.SRC_DIR}}/server/node_modules" + sources: + - "{{.G_BUILD_DIR}}/nodejs-22.md5" + - "{{.TASKFILE}}" + - "client/package.json" + - "client/package-lock.json" + - "package.json" + - "package-lock.json" + - "server/package.json" + - "server/package-lock.json" dir: "{{.SRC_DIR}}" + generates: + - "{{.CHECKSUM_FILE}}" + - "{{.CLIENT_CHECKSUM_FILE}}" + - "{{.PACKAGE_CHECKSUM_FILE}}" + - "{{.SERVER_CHECKSUM_FILE}}" deps: - "nodejs-22" - task: "utils:validate-checksum" @@ -416,32 +430,18 @@ tasks: "{{.PACKAGE_CHECKSUM_FILE}}" "{{.SERVER_CHECKSUM_FILE}}" > "{{.CHECKSUM_FILE}}" - sources: - - "{{.G_BUILD_DIR}}/nodejs-22.md5" - - "{{.TASKFILE}}" - - "client/package.json" - - "client/package-lock.json" - - "package.json" - - "package-lock.json" - - "server/package.json" - - "server/package-lock.json" - generates: - - "{{.CHECKSUM_FILE}}" - - "{{.CLIENT_CHECKSUM_FILE}}" - - "{{.PACKAGE_CHECKSUM_FILE}}" - - "{{.SERVER_CHECKSUM_FILE}}" meteor: - run: "once" - preconditions: - - sh: >- - (test "$(uname -m)" != "aarch64") || (test "$(uname -s)" != "Linux") - msg: "Meteor 2.x does not support aarch64 on Linux" vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" METEOR_ARCH: "{{ if eq ARCH \"arm64\" }}arm64{{ else }}x86_64{{ end }}" METEOR_PLATFORM: "{{ if eq OS \"darwin\" }}osx{{ else }}linux{{ end }}" METEOR_RELEASE: "2.15" + run: "once" + preconditions: + - sh: >- + (test "$(uname -m)" != "aarch64") || (test "$(uname -s)" != "Linux") + msg: "Meteor 2.x does not support aarch64 on Linux" cmds: - task: "download-and-extract-tar" vars: @@ -453,9 +453,6 @@ tasks: nodejs: internal: true - deps: ["init"] - requires: - vars: ["CHECKSUM_FILE", "NODEJS_VERSION", "OUTPUT_DIR"] vars: NODEJS_ARCH: "{{ if eq ARCH \"arm64\" }}arm64{{ else }}x64{{ end }}" NODEJS_VERSION_BASE_URL: "https://nodejs.org/dist/{{.NODEJS_VERSION}}/" @@ -467,6 +464,9 @@ tasks: --max-count 1 "node-v[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+-{{OS}}-{{.NODEJS_ARCH}}" | head --lines 1 + requires: + vars: ["CHECKSUM_FILE", "NODEJS_VERSION", "OUTPUT_DIR"] + deps: ["init"] cmds: - task: "download-and-extract-tar" vars: @@ -478,8 +478,6 @@ tasks: package-tar: internal: true - requires: - vars: ["FLAVOUR", "STORAGE_ENGINE"] vars: VERSIONED_PACKAGE_NAME: sh: | @@ -487,7 +485,14 @@ tasks: echo "clp-{{.FLAVOUR}}-${ID}-${VERSION_CODENAME}-$(arch)-v{{.G_PACKAGE_VERSION}}" OUTPUT_DIR: "{{.G_BUILD_DIR}}/{{.VERSIONED_PACKAGE_NAME}}" OUTPUT_FILE: "{{.OUTPUT_DIR}}.tar.gz" + requires: + vars: ["FLAVOUR", "STORAGE_ENGINE"] + sources: + - "{{.G_BUILD_DIR}}/package.md5" + - "{{.TASKFILE}}" dir: "{{.G_BUILD_DIR}}" + generates: + - "{{.VERSIONED_PACKAGE_NAME}}.tar.gz" deps: ["package"] cmds: - "rm -rf '{{.OUTPUT_DIR}}' '{{.OUTPUT_FILE}}'" @@ -509,17 +514,17 @@ tasks: tar czf '{{.OUTPUT_FILE}}' --directory '{{.G_BUILD_DIR}}' --dereference '{{.VERSIONED_PACKAGE_NAME}}' - sources: - - "{{.G_BUILD_DIR}}/package.md5" - - "{{.TASKFILE}}" - generates: - - "{{.VERSIONED_PACKAGE_NAME}}.tar.gz" package-venv: internal: true vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_PACKAGE_VENV_DIR}}" + sources: + - "{{.ROOT_DIR}}/requirements.txt" + - "{{.TASKFILE}}" + - "/etc/os-release" + generates: ["{{.CHECKSUM_FILE}}"] deps: - "init" - task: "utils:validate-checksum" @@ -537,34 +542,16 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.ROOT_DIR}}/requirements.txt" - - "{{.TASKFILE}}" - - "/etc/os-release" - generates: ["{{.CHECKSUM_FILE}}"] python-component: internal: true - requires: - vars: ["COMPONENT"] label: "{{.COMPONENT}}" - deps: - - task: "component-venv" - vars: - COMPONENT: "{{.COMPONENT}}" - OUTPUT_DIR: "{{.VENV_DIR}}" vars: PACKAGE: sh: "echo {{.COMPONENT}} | tr - _" VENV_DIR: "{{.G_BUILD_DIR}}/{{.COMPONENT}}/venv" - dir: "components/{{.COMPONENT}}" - cmds: - - task: "clean-python-component" - vars: - COMPONENT: "{{.COMPONENT}}" - - |- - . "{{.VENV_DIR}}/bin/activate" - poetry build --format wheel + requires: + vars: ["COMPONENT"] sources: - "{{.G_BUILD_DIR}}/{{.COMPONENT}}_venv.md5" - "{{.PACKAGE}}/**/*" @@ -572,8 +559,21 @@ tasks: - "{{.TASKFILE}}" - "/etc/os-release" - "pyproject.toml" + dir: "components/{{.COMPONENT}}" generates: - "dist/*.whl" + deps: + - task: "component-venv" + vars: + COMPONENT: "{{.COMPONENT}}" + OUTPUT_DIR: "{{.VENV_DIR}}" + cmds: + - task: "clean-python-component" + vars: + COMPONENT: "{{.COMPONENT}}" + - |- + . "{{.VENV_DIR}}/bin/activate" + poetry build --format wheel webui-node-modules: internal: true @@ -581,7 +581,13 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/webui" OUTPUT_DIR: "{{.WEBUI_SRC_DIR}}/node_modules" + sources: + - "{{.G_BUILD_DIR}}/meteor.md5" + - "{{.TASKFILE}}" + - ".meteor/packages" + - "package.json" dir: "{{.WEBUI_SRC_DIR}}" + generates: ["{{.CHECKSUM_FILE}}"] deps: - "init" - "meteor" @@ -597,21 +603,21 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.G_BUILD_DIR}}/meteor.md5" - - "{{.TASKFILE}}" - - ".meteor/packages" - - "package.json" - generates: ["{{.CHECKSUM_FILE}}"] component-venv: internal: true - requires: - vars: ["COMPONENT", "OUTPUT_DIR"] label: "{{.COMPONENT}}-venv" - dir: "components/{{.COMPONENT}}" vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.COMPONENT}}-venv.md5" + requires: + vars: ["COMPONENT", "OUTPUT_DIR"] + sources: + - "{{.ROOT_DIR}}/requirements.txt" + - "{{.TASKFILE}}" + - "/etc/os-release" + - "pyproject.toml" + dir: "components/{{.COMPONENT}}" + generates: ["{{.CHECKSUM_FILE}}"] deps: - "init" - task: "utils:validate-checksum" @@ -629,24 +635,17 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.ROOT_DIR}}/requirements.txt" - - "{{.TASKFILE}}" - - "/etc/os-release" - - "pyproject.toml" - generates: ["{{.CHECKSUM_FILE}}"] - clean-python-component: internal: true + label: "clean-{{.COMPONENT}}" requires: vars: ["COMPONENT"] - label: "clean-{{.COMPONENT}}" dir: "components/{{.COMPONENT}}" cmds: - "rm -rf dist" init: internal: true - run: "once" silent: true + run: "once" cmd: "mkdir -p '{{.G_BUILD_DIR}}'" diff --git a/lint-tasks.yml b/lint-tasks.yml index 9cd3f1435..a7de6e49e 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -21,11 +21,6 @@ tasks: - task: "yml-fix" cpp-check: - dir: "components/core" - cmds: - - task: "cpp" - vars: - FLAGS: "--dry-run" sources: &cpp_source_files - "{{.TASKFILE}}" - ".clang-format" @@ -37,20 +32,21 @@ tasks: - "tests/**/*.h" - "tests/**/*.hpp" - "tests/**/*.inc" + dir: "components/core" + cmds: + - task: "cpp" + vars: + FLAGS: "--dry-run" cpp-fix: + sources: *cpp_source_files dir: "components/core" cmds: - task: "cpp" vars: FLAGS: "-i" - sources: *cpp_source_files js-check: - cmds: - - task: "js" - vars: - LINT_CMD: "check" sources: &js_source_files - "{{.G_BUILD_DIR}}/lint#linter-node-modules.md5" - "{{.G_BUILD_DIR}}/log-viewer-webui-node-modules.md5" @@ -73,13 +69,17 @@ tasks: - "{{.G_WEBUI_SRC_DIR}}/tests/**/*.jsx" - "{{.ROOT_DIR}}/Taskfile.yml" - "{{.TASKFILE}}" + cmds: + - task: "js" + vars: + LINT_CMD: "check" js-fix: + sources: *js_source_files cmds: - task: "js" vars: LINT_CMD: "fix" - sources: *js_source_files py-check: cmds: @@ -117,8 +117,8 @@ tasks: internal: true requires: vars: ["FLAGS"] - deps: ["venv"] dir: "components/core" + deps: ["venv"] cmds: - |- . "{{.G_LINT_VENV_DIR}}/bin/activate" @@ -160,6 +160,18 @@ tasks: linter-node-modules: internal: true + vars: + WEBUI_LINTER_DIR: "{{.ROOT_DIR}}/components/webui/linter" + OUTPUT_DIR: "{{.WEBUI_LINTER_DIR}}/node_modules" + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK | replace \":\" \"#\"}}.md5" + sources: + - "{{.G_BUILD_DIR}}/nodejs-22.md5" + - "{{.G_BUILD_DIR}}/webui-node-modules.md5" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + - "../package.json" + dir: "{{.WEBUI_LINTER_DIR}}" + generates: ["{{.CHECKSUM_FILE}}"] deps: - ":init" - ":webui-node-modules" @@ -168,11 +180,6 @@ tasks: CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" DATA_DIR: "{{.OUTPUT_DIR}}" - ":nodejs-22" - dir: "{{.WEBUI_LINTER_DIR}}" - vars: - WEBUI_LINTER_DIR: "{{.ROOT_DIR}}/components/webui/linter" - OUTPUT_DIR: "{{.WEBUI_LINTER_DIR}}/node_modules" - CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK | replace \":\" \"#\"}}.md5" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - "PATH='{{.G_NODEJS_22_BIN_DIR}}':$PATH npm update" @@ -181,19 +188,17 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.G_BUILD_DIR}}/nodejs-22.md5" - - "{{.G_BUILD_DIR}}/webui-node-modules.md5" - - "{{.ROOT_DIR}}/Taskfile.yml" - - "{{.TASKFILE}}" - - "../package.json" - generates: ["{{.CHECKSUM_FILE}}"] venv: internal: true vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK | replace \":\" \"#\"}}.md5" OUTPUT_DIR: "{{.G_LINT_VENV_DIR}}" + sources: + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + - "lint-requirements.txt" + generates: ["{{.CHECKSUM_FILE}}"] deps: - ":init" - task: ":utils:validate-checksum" @@ -211,8 +216,3 @@ tasks: vars: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - sources: - - "{{.ROOT_DIR}}/Taskfile.yml" - - "{{.TASKFILE}}" - - "lint-requirements.txt" - generates: ["{{.CHECKSUM_FILE}}"] From 862fccf63424e3a5a677abce1ee1245ac2099cee Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:05:03 -0400 Subject: [PATCH 027/114] clp-package: Fix bugs introduced in #460: (#481) - Write search results to collection named job_id rather than task_id. - Convert int to str in IR extraction command generation. --- .../job_orchestration/executor/query/extract_ir_task.py | 2 +- .../job_orchestration/executor/query/fs_search_task.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py b/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py index b04b809f3..61fcbf549 100644 --- a/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py @@ -45,7 +45,7 @@ def make_command( ] if extract_ir_config.target_uncompressed_size is not None: command.append("--target-size") - command.append(extract_ir_config.target_uncompressed_size) + command.append(str(extract_ir_config.target_uncompressed_size)) else: logger.error(f"Unsupported storage engine {storage_engine}") return None diff --git a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py index baafca3e2..162056220 100644 --- a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py @@ -129,7 +129,7 @@ def search( archive_id=archive_id, search_config=search_config, results_cache_uri=results_cache_uri, - results_collection=str(task_id), + results_collection=job_id, ) if not task_command: return report_command_creation_failure( From eebbf1ea5ed3488e69c5081e765c769875089224 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:02:54 -0400 Subject: [PATCH 028/114] ffi: Add support for serializing msgpack map into KV-pair IR format. (#467) --- .../core/src/clp/ffi/ir_stream/Serializer.cpp | 460 ++++++++++++++++++ .../core/src/clp/ffi/ir_stream/Serializer.hpp | 36 ++ .../clp/ffi/ir_stream/encoding_methods.cpp | 26 +- .../clp/ffi/ir_stream/encoding_methods.hpp | 9 + .../clp/ffi/ir_stream/protocol_constants.hpp | 29 ++ .../core/src/clp/ffi/ir_stream/utils.cpp | 34 +- .../core/src/clp/ffi/ir_stream/utils.hpp | 61 ++- .../core/tests/test-ir_encoding_methods.cpp | 114 +++++ 8 files changed, 747 insertions(+), 22 deletions(-) diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp index 6a7128d9f..770a6a78c 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -1,22 +1,238 @@ #include "Serializer.hpp" +#include #include +#include +#include +#include +#include +#include #include +#include #include #include +#include #include "../../ir/types.hpp" #include "../../time_types.hpp" +#include "../../type_utils.hpp" #include "../encoding_methods.hpp" +#include "../SchemaTree.hpp" +#include "../SchemaTreeNode.hpp" #include "encoding_methods.hpp" #include "protocol_constants.hpp" #include "utils.hpp" +using std::optional; +using std::span; +using std::string; +using std::string_view; +using std::vector; + using clp::ir::eight_byte_encoded_variable_t; using clp::ir::four_byte_encoded_variable_t; namespace clp::ffi::ir_stream { +namespace { +/** + * Class for iterating the kv-pairs of a MessagePack map. + */ +class MsgpackMapIterator { +public: + // Types + using Child = msgpack::object_kv; + + // Constructors + MsgpackMapIterator(SchemaTreeNode::id_t schema_tree_node_id, span children) + : m_schema_tree_node_id{schema_tree_node_id}, + m_children{children}, + m_curr_child_it{m_children.begin()} {} + + // Methods + /** + * @return This map's ID in the schema tree. + */ + [[nodiscard]] auto get_schema_tree_node_id() const -> SchemaTreeNode::id_t { + return m_schema_tree_node_id; + } + + /** + * @return Whether there are more children to traverse. + */ + [[nodiscard]] auto has_next_child() const -> bool { + return m_curr_child_it != m_children.end(); + } + + /** + * Gets the next child and advances the underlying child idx. + * @return The next child to traverse. + */ + [[nodiscard]] auto get_next_child() -> Child const& { return *(m_curr_child_it++); } + +private: + SchemaTreeNode::id_t m_schema_tree_node_id; + span m_children; + span::iterator m_curr_child_it; +}; + +/** + * Gets the schema-tree node type that corresponds with a given MessagePack value. + * @param val + * @return The corresponding schema-tree node type. + * @return std::nullopt if the value doesn't match any of the supported schema-tree node types. + */ +[[nodiscard]] auto get_schema_tree_node_type_from_msgpack_val(msgpack::object const& val +) -> optional; + +/** + * Serializes an empty object. + * @param output_buf + */ +auto serialize_value_empty_object(vector& output_buf) -> void; + +/** + * Serializes an integer. + * @param val + * @param output_buf + * @return Whether serialization succeeded. + */ +auto serialize_value_int(int64_t val, vector& output_buf) -> void; + +/** + * Serializes a float. + * @param val + * @param output_buf + */ +auto serialize_value_float(double val, vector& output_buf) -> void; + +/** + * Serializes a boolean. + * @param val + * @param output_buf + */ +auto serialize_value_bool(bool val, vector& output_buf) -> void; + +/** + * Serializes a null. + * @param output_buf + */ +auto serialize_value_null(vector& output_buf) -> void; + +/** + * Serializes a string. + * @tparam encoded_variable_t + * @param val + * @param logtype_buf + * @param output_buf + * @return Whether serialization succeeded. + */ +template +[[nodiscard]] auto +serialize_value_string(string_view val, string& logtype_buf, vector& output_buf) -> bool; + +/** + * Serializes a MessagePack array as a JSON string, using CLP's encoding for unstructured text. + * @tparam encoded_variable_t + * @param val + * @param logtype_buf + * @param output_buf + * @return Whether serialization succeeded. + */ +template +[[nodiscard]] auto serialize_value_array( + msgpack::object const& val, + string& logtype_buf, + vector& output_buf +) -> bool; + +auto get_schema_tree_node_type_from_msgpack_val(msgpack::object const& val +) -> optional { + optional ret_val; + switch (val.type) { + case msgpack::type::POSITIVE_INTEGER: + case msgpack::type::NEGATIVE_INTEGER: + ret_val.emplace(SchemaTreeNode::Type::Int); + break; + case msgpack::type::FLOAT32: + case msgpack::type::FLOAT64: + ret_val.emplace(SchemaTreeNode::Type::Float); + break; + case msgpack::type::STR: + ret_val.emplace(SchemaTreeNode::Type::Str); + break; + case msgpack::type::BOOLEAN: + ret_val.emplace(SchemaTreeNode::Type::Bool); + break; + case msgpack::type::NIL: + case msgpack::type::MAP: + ret_val.emplace(SchemaTreeNode::Type::Obj); + break; + case msgpack::type::ARRAY: + ret_val.emplace(SchemaTreeNode::Type::UnstructuredArray); + break; + default: + return std::nullopt; + } + return ret_val; +} + +auto serialize_value_empty_object(vector& output_buf) -> void { + output_buf.push_back(cProtocol::Payload::ValueEmpty); +} + +auto serialize_value_int(int64_t val, vector& output_buf) -> void { + if (INT8_MIN <= val && val <= INT8_MAX) { + output_buf.push_back(cProtocol::Payload::ValueInt8); + output_buf.push_back(static_cast(val)); + } else if (INT16_MIN <= val && val <= INT16_MAX) { + output_buf.push_back(cProtocol::Payload::ValueInt16); + serialize_int(static_cast(val), output_buf); + } else if (INT32_MIN <= val && val <= INT32_MAX) { + output_buf.push_back(cProtocol::Payload::ValueInt32); + serialize_int(static_cast(val), output_buf); + } else { // (INT64_MIN <= val && val <= INT64_MAX) + output_buf.push_back(cProtocol::Payload::ValueInt64); + serialize_int(val, output_buf); + } +} + +auto serialize_value_float(double val, vector& output_buf) -> void { + output_buf.push_back(cProtocol::Payload::ValueFloat); + serialize_int(bit_cast(val), output_buf); +} + +auto serialize_value_bool(bool val, vector& output_buf) -> void { + output_buf.push_back(val ? cProtocol::Payload::ValueTrue : cProtocol::Payload::ValueFalse); +} + +auto serialize_value_null(vector& output_buf) -> void { + output_buf.push_back(cProtocol::Payload::ValueNull); +} + +template +auto serialize_value_string(string_view val, string& logtype_buf, vector& output_buf) + -> bool { + if (string_view::npos == val.find(' ')) { + return serialize_string(val, output_buf); + } + logtype_buf.clear(); + return serialize_clp_string(val, logtype_buf, output_buf); +} + +template +auto serialize_value_array( + msgpack::object const& val, + string& logtype_buf, + vector& output_buf +) -> bool { + std::ostringstream oss; + oss << val; + logtype_buf.clear(); + return serialize_clp_string(oss.str(), logtype_buf, output_buf); +} +} // namespace + template auto Serializer::create( ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { @@ -59,14 +275,258 @@ auto Serializer::change_utc_offset(UtcOffset utc_offset) -> serialize_utc_offset_change(m_curr_utc_offset, m_ir_buf); } +template +auto Serializer::serialize_msgpack_map(msgpack::object_map const& msgpack_map +) -> bool { + if (0 == msgpack_map.size) { + serialize_value_empty_object(m_ir_buf); + return true; + } + + m_schema_tree.take_snapshot(); + m_schema_tree_node_buf.clear(); + m_key_group_buf.clear(); + m_value_group_buf.clear(); + + // Traverse the map using DFS iteratively + bool failure{false}; + vector dfs_stack; + dfs_stack.emplace_back( + SchemaTree::cRootId, + span{msgpack_map.ptr, msgpack_map.size} + ); + while (false == dfs_stack.empty()) { + auto& curr{dfs_stack.back()}; + if (false == curr.has_next_child()) { + // Visited all children, so pop node + dfs_stack.pop_back(); + continue; + } + + // Convert the current value's type to its corresponding schema-tree node type + auto const& [key, val]{curr.get_next_child()}; + auto const opt_schema_tree_node_type{get_schema_tree_node_type_from_msgpack_val(val)}; + if (false == opt_schema_tree_node_type.has_value()) { + failure = true; + break; + } + auto const schema_tree_node_type{opt_schema_tree_node_type.value()}; + + SchemaTree::NodeLocator const locator{ + curr.get_schema_tree_node_id(), + key.as(), + schema_tree_node_type + }; + + // Get the schema-tree node that corresponds with the current kv-pair, or add it if it + // doesn't exist. + auto opt_schema_tree_node_id{m_schema_tree.try_get_node_id(locator)}; + if (false == opt_schema_tree_node_id.has_value()) { + opt_schema_tree_node_id.emplace(m_schema_tree.insert_node(locator)); + if (false == serialize_schema_tree_node(locator)) { + failure = true; + break; + } + } + auto const schema_tree_node_id{opt_schema_tree_node_id.value()}; + + if (msgpack::type::MAP == val.type) { + // Serialize map + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + auto const& inner_map{val.via.map}; + auto const inner_map_size(inner_map.size); + if (0 == inner_map_size) { + // Value is an empty map, so we can serialize it immediately + if (false == serialize_key(schema_tree_node_id)) { + failure = true; + break; + } + serialize_value_empty_object(m_value_group_buf); + } else { + // Add map for DFS iteration + dfs_stack.emplace_back( + schema_tree_node_id, + span{inner_map.ptr, inner_map_size} + ); + } + } else { + // Serialize primitive + if (false + == (serialize_key(schema_tree_node_id) && serialize_val(val, schema_tree_node_type) + )) + { + failure = true; + break; + } + } + } + + if (failure) { + m_schema_tree.revert(); + return false; + } + + m_ir_buf.insert( + m_ir_buf.cend(), + m_schema_tree_node_buf.cbegin(), + m_schema_tree_node_buf.cend() + ); + m_ir_buf.insert(m_ir_buf.cend(), m_key_group_buf.cbegin(), m_key_group_buf.cend()); + m_ir_buf.insert(m_ir_buf.cend(), m_value_group_buf.cbegin(), m_value_group_buf.cend()); + return true; +} + +template +auto Serializer::serialize_schema_tree_node( + SchemaTree::NodeLocator const& locator +) -> bool { + switch (locator.get_type()) { + case SchemaTreeNode::Type::Int: + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeInt); + break; + case SchemaTreeNode::Type::Float: + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeFloat); + break; + case SchemaTreeNode::Type::Bool: + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeBool); + break; + case SchemaTreeNode::Type::Str: + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeStr); + break; + case SchemaTreeNode::Type::UnstructuredArray: + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeUnstructuredArray); + break; + case SchemaTreeNode::Type::Obj: + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeObj); + break; + default: + // Unknown type + return false; + } + + auto const parent_id{locator.get_parent_id()}; + if (parent_id <= UINT8_MAX) { + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeParentIdUByte); + m_schema_tree_node_buf.push_back(bit_cast(static_cast(parent_id))); + } else if (parent_id <= UINT16_MAX) { + m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeParentIdUShort); + serialize_int(static_cast(parent_id), m_schema_tree_node_buf); + } else { + // Out of range + return false; + } + + return serialize_string(locator.get_key_name(), m_schema_tree_node_buf); +} + +template +auto Serializer::serialize_key(SchemaTreeNode::id_t id) -> bool { + if (id <= UINT8_MAX) { + m_key_group_buf.push_back(cProtocol::Payload::KeyIdUByte); + m_key_group_buf.push_back(bit_cast(static_cast(id))); + } else if (id <= UINT16_MAX) { + m_key_group_buf.push_back(cProtocol::Payload::KeyIdUShort); + serialize_int(static_cast(id), m_key_group_buf); + } else { + return false; + } + return true; +} + +template +auto Serializer::serialize_val( + msgpack::object const& val, + SchemaTreeNode::Type schema_tree_node_type +) -> bool { + switch (schema_tree_node_type) { + case SchemaTreeNode::Type::Int: + if (msgpack::type::POSITIVE_INTEGER == val.type + && static_cast(INT64_MAX) < val.as()) + { + return false; + } + serialize_value_int(val.as(), m_value_group_buf); + break; + + case SchemaTreeNode::Type::Float: + serialize_value_float(val.as(), m_value_group_buf); + break; + + case SchemaTreeNode::Type::Bool: + serialize_value_bool(val.as(), m_value_group_buf); + break; + + case SchemaTreeNode::Type::Str: + if (false + == serialize_value_string( + val.as(), + m_logtype_buf, + m_value_group_buf + )) + { + return false; + } + break; + + case SchemaTreeNode::Type::Obj: + if (msgpack::type::NIL != val.type) { + return false; + } + serialize_value_null(m_value_group_buf); + break; + + case SchemaTreeNode::Type::UnstructuredArray: + if (false + == serialize_value_array(val, m_logtype_buf, m_value_group_buf)) + { + return false; + } + break; + + default: + // Unknown schema tree node type + return false; + } + return true; +} + // Explicitly declare template specializations so that we can define the template methods in this // file template auto Serializer::create( ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; template auto Serializer::create( ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + template auto Serializer::change_utc_offset(UtcOffset utc_offset ) -> void; template auto Serializer::change_utc_offset(UtcOffset utc_offset ) -> void; + +template auto Serializer::serialize_msgpack_map( + msgpack::object_map const& msgpack_map +) -> bool; +template auto Serializer::serialize_msgpack_map( + msgpack::object_map const& msgpack_map +) -> bool; + +template auto Serializer::serialize_schema_tree_node( + SchemaTree::NodeLocator const& locator +) -> bool; +template auto Serializer::serialize_schema_tree_node( + SchemaTree::NodeLocator const& locator +) -> bool; + +template auto Serializer::serialize_key(SchemaTreeNode::id_t id +) -> bool; +template auto Serializer::serialize_key(SchemaTreeNode::id_t id +) -> bool; + +template auto Serializer::serialize_val( + msgpack::object const& val, + SchemaTreeNode::Type schema_tree_node_type +) -> bool; +template auto Serializer::serialize_val( + msgpack::object const& val, + SchemaTreeNode::Type schema_tree_node_type +) -> bool; } // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp index 4c8d48fc6..82863bc7e 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -3,12 +3,15 @@ #include #include +#include #include #include +#include #include "../../time_types.hpp" #include "../SchemaTree.hpp" +#include "../SchemaTreeNode.hpp" namespace clp::ffi::ir_stream { /** @@ -79,14 +82,47 @@ class Serializer { */ auto change_utc_offset(UtcOffset utc_offset) -> void; + /** + * Serializes the given msgpack map as a key-value pair log event. + * @param msgpack_map + * @return Whether serialization succeeded. + */ + [[nodiscard]] auto serialize_msgpack_map(msgpack::object_map const& msgpack_map) -> bool; + private: // Constructors Serializer() = default; + // Methods + /** + * Serializes a schema tree node identified by the given locator into `m_schema_tree_node_buf`. + * @param locator + * @return Whether serialization succeeded. + */ + [[nodiscard]] auto serialize_schema_tree_node(SchemaTree::NodeLocator const& locator) -> bool; + + /** + * Serializes the given key ID into `m_key_group_buf`. + * @param id + * @return true on success. + * @return false if the ID exceeds the representable range. + */ + [[nodiscard]] auto serialize_key(SchemaTreeNode::id_t id) -> bool; + + /** + * Serializes the given MessagePack value into `m_value_group_buf`. + * @param val + * @param schema_tree_node_type The type of the schema tree node that corresponds to `val`. + * @return Whether serialization succeeded. + */ + [[nodiscard]] auto + serialize_val(msgpack::object const& val, SchemaTreeNode::Type schema_tree_node_type) -> bool; + UtcOffset m_curr_utc_offset{0}; Buffer m_ir_buf; SchemaTree m_schema_tree; + std::string m_logtype_buf; Buffer m_schema_tree_node_buf; Buffer m_key_group_buf; Buffer m_value_group_buf; diff --git a/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp b/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp index 35363e2d3..128d659c1 100644 --- a/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp @@ -135,6 +135,22 @@ bool serialize_log_event( string_view message, string& logtype, vector& ir_buf +) { + if (false == serialize_message(message, logtype, ir_buf)) { + return false; + } + + // Encode timestamp + ir_buf.push_back(cProtocol::Payload::TimestampVal); + serialize_int(timestamp, ir_buf); + + return true; +} + +bool serialize_message( + std::string_view message, + std::string& logtype, + std::vector& ir_buf ) { auto encoded_var_handler = [&ir_buf](eight_byte_encoded_variable_t encoded_var) { ir_buf.push_back(cProtocol::Payload::VarEightByteEncoding); @@ -153,15 +169,7 @@ bool serialize_log_event( return false; } - if (false == serialize_logtype(logtype, ir_buf)) { - return false; - } - - // Encode timestamp - ir_buf.push_back(cProtocol::Payload::TimestampVal); - serialize_int(timestamp, ir_buf); - - return true; + return serialize_logtype(logtype, ir_buf); } } // namespace eight_byte_encoding diff --git a/components/core/src/clp/ffi/ir_stream/encoding_methods.hpp b/components/core/src/clp/ffi/ir_stream/encoding_methods.hpp index 0129e7550..be042e870 100644 --- a/components/core/src/clp/ffi/ir_stream/encoding_methods.hpp +++ b/components/core/src/clp/ffi/ir_stream/encoding_methods.hpp @@ -39,6 +39,15 @@ bool serialize_log_event( std::string& logtype, std::vector& ir_buf ); + +/** + * Serializes the given message into the eight-byte encoding IR stream. + * @param message + * @param logtype Returns the message's logtype. + * @param ir_buf + * @return Whether the message was serialized successfully. + */ +bool serialize_message(std::string_view message, std::string& logtype, std::vector& ir_buf); } // namespace eight_byte_encoding namespace four_byte_encoding { diff --git a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp index f9fd7ed78..9f84cc4e1 100644 --- a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp +++ b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp @@ -50,6 +50,35 @@ constexpr int8_t TimestampDeltaInt = 0x33; constexpr int8_t TimestampDeltaLong = 0x34; constexpr int8_t UtcOffsetChange = 0x3F; + +constexpr int8_t StrLenUByte = 0x41; +constexpr int8_t StrLenUShort = 0x42; +constexpr int8_t StrLenUInt = 0x43; + +constexpr int8_t ValueInt8 = 0x51; +constexpr int8_t ValueInt16 = 0x52; +constexpr int8_t ValueInt32 = 0x53; +constexpr int8_t ValueInt64 = 0x54; +constexpr int8_t ValueFloat = 0x56; +constexpr int8_t ValueTrue = 0x57; +constexpr int8_t ValueFalse = 0x58; +constexpr int8_t ValueFourByteEncodingClpStr = 0x59; +constexpr int8_t ValueEightByteEncodingClpStr = 0x5A; +constexpr int8_t ValueEmpty = 0x5E; +constexpr int8_t ValueNull = 0x5F; + +constexpr int8_t SchemaTreeNodeParentIdUByte = 0x60; +constexpr int8_t SchemaTreeNodeParentIdUShort = 0x61; + +constexpr int8_t KeyIdUByte = 0x65; +constexpr int8_t KeyIdUShort = 0x66; + +constexpr int8_t SchemaTreeNodeInt = 0x71; +constexpr int8_t SchemaTreeNodeFloat = 0x72; +constexpr int8_t SchemaTreeNodeBool = 0x73; +constexpr int8_t SchemaTreeNodeStr = 0x74; +constexpr int8_t SchemaTreeNodeUnstructuredArray = 0x75; +constexpr int8_t SchemaTreeNodeObj = 0x76; } // namespace Payload constexpr int8_t FourByteEncodingMagicNumber[] diff --git a/components/core/src/clp/ffi/ir_stream/utils.cpp b/components/core/src/clp/ffi/ir_stream/utils.cpp index 0a22536b6..66277720c 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.cpp +++ b/components/core/src/clp/ffi/ir_stream/utils.cpp @@ -1,6 +1,7 @@ #include "utils.hpp" #include +#include #include #include @@ -9,24 +10,43 @@ #include "protocol_constants.hpp" namespace clp::ffi::ir_stream { -auto serialize_metadata(nlohmann::json& metadata, std::vector& ir_buf) -> bool { - ir_buf.push_back(cProtocol::Metadata::EncodingJson); +auto serialize_metadata(nlohmann::json& metadata, std::vector& output_buf) -> bool { + output_buf.push_back(cProtocol::Metadata::EncodingJson); auto const metadata_serialized = metadata.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore); auto const metadata_serialized_length = metadata_serialized.length(); if (metadata_serialized_length <= UINT8_MAX) { - ir_buf.push_back(cProtocol::Metadata::LengthUByte); - ir_buf.push_back(bit_cast(static_cast(metadata_serialized_length))); + output_buf.push_back(cProtocol::Metadata::LengthUByte); + output_buf.push_back(bit_cast(static_cast(metadata_serialized_length))); } else if (metadata_serialized_length <= UINT16_MAX) { - ir_buf.push_back(cProtocol::Metadata::LengthUShort); - serialize_int(static_cast(metadata_serialized_length), ir_buf); + output_buf.push_back(cProtocol::Metadata::LengthUShort); + serialize_int(static_cast(metadata_serialized_length), output_buf); } else { // Can't encode metadata longer than 64 KiB return false; } - ir_buf.insert(ir_buf.cend(), metadata_serialized.cbegin(), metadata_serialized.cend()); + output_buf.insert(output_buf.cend(), metadata_serialized.cbegin(), metadata_serialized.cend()); return true; } + +auto serialize_string(std::string_view str, std::vector& output_buf) -> bool { + auto const length{str.length()}; + if (length <= UINT8_MAX) { + output_buf.push_back(cProtocol::Payload::StrLenUByte); + output_buf.push_back(bit_cast(static_cast(length))); + } else if (length <= UINT16_MAX) { + output_buf.push_back(cProtocol::Payload::StrLenUShort); + serialize_int(static_cast(length), output_buf); + } else if (length <= UINT32_MAX) { + output_buf.push_back(cProtocol::Payload::StrLenUInt); + serialize_int(static_cast(length), output_buf); + } else { + // Out of range + return false; + } + output_buf.insert(output_buf.cend(), str.cbegin(), str.cend()); + return true; +} } // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/utils.hpp b/components/core/src/clp/ffi/ir_stream/utils.hpp index 5e1fb293a..7879c3f74 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.hpp +++ b/components/core/src/clp/ffi/ir_stream/utils.hpp @@ -3,33 +3,61 @@ #include #include +#include +#include #include #include +#include "../../ir/types.hpp" #include "byteswap.hpp" +#include "encoding_methods.hpp" +#include "protocol_constants.hpp" namespace clp::ffi::ir_stream { /** * Serializes the given metadata into the IR stream. * @param metadata - * @param ir_buf + * @param output_buf * @return Whether serialization succeeded. */ [[nodiscard]] auto -serialize_metadata(nlohmann::json& metadata, std::vector& ir_buf) -> bool; +serialize_metadata(nlohmann::json& metadata, std::vector& output_buf) -> bool; /** * Serializes the given integer into the IR stream. * @tparam integer_t * @param value - * @param ir_buf + * @param output_buf */ template -auto serialize_int(integer_t value, std::vector& ir_buf) -> void; +auto serialize_int(integer_t value, std::vector& output_buf) -> void; + +/** + * Serializes a string using CLP's encoding for unstructured text. + * @tparam encoded_variable_t + * @param str + * @param logtype Returns the corresponding logtype. + * @param output_buf + * @return Whether serialization succeeded. + */ +template +[[nodiscard]] auto serialize_clp_string( + std::string_view str, + std::string& logtype, + std::vector& output_buf +) -> bool; + +/** + * Serializes a string. + * @param str + * @param output_buf + * @return Whether serialization succeeded. + */ +[[nodiscard]] auto serialize_string(std::string_view str, std::vector& output_buf) -> bool; template -auto serialize_int(integer_t value, std::vector& ir_buf) -> void { +auto serialize_int(integer_t value, std::vector& output_buf) -> void { integer_t value_big_endian{}; static_assert(sizeof(integer_t) == 2 || sizeof(integer_t) == 4 || sizeof(integer_t) == 8); if constexpr (sizeof(value) == 2) { @@ -41,7 +69,28 @@ auto serialize_int(integer_t value, std::vector& ir_buf) -> void { } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) std::span const data_view{reinterpret_cast(&value_big_endian), sizeof(value)}; - ir_buf.insert(ir_buf.end(), data_view.begin(), data_view.end()); + output_buf.insert(output_buf.end(), data_view.begin(), data_view.end()); +} + +template +[[nodiscard]] auto serialize_clp_string( + std::string_view str, + std::string& logtype, + std::vector& output_buf +) -> bool { + static_assert( + (std::is_same_v + || std::is_same_v) + ); + bool succeeded{}; + if constexpr (std::is_same_v) { + output_buf.push_back(cProtocol::Payload::ValueFourByteEncodingClpStr); + succeeded = four_byte_encoding::serialize_message(str, logtype, output_buf); + } else { + output_buf.push_back(cProtocol::Payload::ValueEightByteEncodingClpStr); + succeeded = eight_byte_encoding::serialize_message(str, logtype, output_buf); + } + return succeeded; } } // namespace clp::ffi::ir_stream #endif diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index 167803e58..4199428ff 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -1,9 +1,14 @@ +#include +#include #include +#include +#include #include #include #include #include +#include #include "../src/clp/BufferReader.hpp" #include "../src/clp/ErrorCode.hpp" @@ -132,6 +137,19 @@ auto flush_and_clear_serializer_buffer( std::vector& byte_buf ) -> void; +/** + * Unpacks and serializes the given msgpack bytes using kv serializer. + * @tparam encoded_variable_t + * @param msgpack_bytes + * @param serializer + * @return Whether serialization succeeded. + */ +template +[[nodiscard]] auto unpack_and_serialize_msgpack_bytes( + vector const& msgpack_bytes, + Serializer& serializer +) -> bool; + template [[nodiscard]] auto serialize_log_events( vector const& log_events, @@ -241,6 +259,22 @@ auto flush_and_clear_serializer_buffer( byte_buf.insert(byte_buf.cend(), view.begin(), view.end()); serializer.clear_ir_buf(); } + +template +auto unpack_and_serialize_msgpack_bytes( + vector const& msgpack_bytes, + Serializer& serializer +) -> bool { + auto const msgpack_obj_handle{msgpack::unpack( + clp::size_checked_pointer_cast(msgpack_bytes.data()), + msgpack_bytes.size() + )}; + auto const msgpack_obj{msgpack_obj_handle.get()}; + if (msgpack::type::MAP != msgpack_obj.type) { + return false; + } + return serializer.serialize_msgpack_map(msgpack_obj.via.map); +} } // namespace /** @@ -971,3 +1005,83 @@ TEMPLATE_TEST_CASE( && 0 == num_bytes_read) ); } + +TEMPLATE_TEST_CASE( + "ffi_ir_stream_Serializer_serialize_msgpack", + "[clp][ffi][ir_stream][Serializer]", + four_byte_encoded_variable_t, + eight_byte_encoded_variable_t +) { + // TODO: Test deserializing the serialized bytes once a KV-pair IR deserializer is implemented. + + vector ir_buf; + + auto result{Serializer::create()}; + REQUIRE((false == result.has_error())); + + auto& serializer{result.value()}; + flush_and_clear_serializer_buffer(serializer, ir_buf); + + auto const empty_obj = nlohmann::json::parse("{}"); + REQUIRE(unpack_and_serialize_msgpack_bytes(nlohmann::json::to_msgpack(empty_obj), serializer)); + + // Test encoding basic object + constexpr string_view cShortString{"short_string"}; + constexpr string_view cClpString{"uid=0, CPU usage: 99.99%, \"user_name\"=YScope"}; + auto const empty_array = nlohmann::json::parse("[]"); + nlohmann::json const basic_obj + = {{"int8_max", INT8_MAX}, + {"int8_min", INT8_MIN}, + {"int16_max", INT16_MAX}, + {"int16_min", INT16_MIN}, + {"int32_max", INT32_MAX}, + {"int32_min", INT32_MIN}, + {"int64_max", INT64_MAX}, + {"int64_min", INT64_MIN}, + {"float_zero", 0.0}, + {"float_pos", 1.01}, + {"float_neg", -1.01}, + {"true", true}, + {"false", false}, + {"string", cShortString}, + {"clp_string", cClpString}, + {"null", nullptr}, + {"empty_object", empty_obj}, + {"empty_array", empty_array}}; + + REQUIRE(unpack_and_serialize_msgpack_bytes(nlohmann::json::to_msgpack(basic_obj), serializer)); + + auto basic_array = empty_array; + basic_array.emplace_back(1); + basic_array.emplace_back(1.0); + basic_array.emplace_back(true); + basic_array.emplace_back(cShortString); + basic_array.emplace_back(cClpString); + basic_array.emplace_back(nullptr); + basic_array.emplace_back(empty_array); + for (auto const& element : basic_array) { + // Non-map objects should not be serializable + REQUIRE( + (false + == unpack_and_serialize_msgpack_bytes( + nlohmann::json::to_msgpack(element), + serializer + )) + ); + } + basic_array.emplace_back(empty_obj); + + // Recursively construct an object containing inner maps and inner arrays. + auto recursive_obj = basic_obj; + auto recursive_array = basic_array; + constexpr size_t cRecursiveDepth{6}; + for (size_t i{0}; i < cRecursiveDepth; ++i) { + recursive_array.emplace_back(recursive_obj); + recursive_obj.emplace("obj_" + std::to_string(i), recursive_obj); + recursive_obj.emplace("array_" + std::to_string(i), recursive_array); + REQUIRE(unpack_and_serialize_msgpack_bytes( + nlohmann::json::to_msgpack(recursive_obj), + serializer + )); + } +} From 24e46901d6681e9bb4f28cd36277c3743b3fd07f Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:49:14 -0400 Subject: [PATCH 029/114] core: Replace `boost-outcome` with `outcome`. (#484) --- .gitmodules | 6 +++--- components/core/.clang-format | 2 +- .../core/src/clp/ffi/ir_stream/Serializer.cpp | 8 ++++---- .../core/src/clp/ffi/ir_stream/Serializer.hpp | 4 ++-- components/core/src/clp/ir/LogEventDeserializer.cpp | 13 +++++++------ components/core/src/clp/ir/LogEventDeserializer.hpp | 6 +++--- components/core/src/glt/ir/LogEventDeserializer.cpp | 13 +++++++------ components/core/src/glt/ir/LogEventDeserializer.hpp | 6 +++--- components/core/submodules/boost-outcome | 1 - components/core/submodules/outcome | 1 + .../tools/scripts/deps-download/boost-outcome.json | 10 ---------- .../tools/scripts/deps-download/download-all.sh | 2 +- .../core/tools/scripts/deps-download/outcome.json | 10 ++++++++++ 13 files changed, 42 insertions(+), 40 deletions(-) delete mode 160000 components/core/submodules/boost-outcome create mode 160000 components/core/submodules/outcome delete mode 100644 components/core/tools/scripts/deps-download/boost-outcome.json create mode 100644 components/core/tools/scripts/deps-download/outcome.json diff --git a/.gitmodules b/.gitmodules index f433a706e..5eb798197 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,9 +14,6 @@ [submodule "components/core/submodules/log-surgeon"] path = components/core/submodules/log-surgeon url = https://github.com/y-scope/log-surgeon.git -[submodule "components/core/submodules/boost-outcome"] - path = components/core/submodules/boost-outcome - url = https://github.com/boostorg/outcome.git [submodule "components/core/submodules/simdjson"] path = components/core/submodules/simdjson url = https://github.com/simdjson/simdjson.git @@ -26,3 +23,6 @@ [submodule "tools/yscope-dev-utils"] path = tools/yscope-dev-utils url = https://github.com/y-scope/yscope-dev-utils.git +[submodule "components/core/submodules/outcome"] + path = components/core/submodules/outcome + url = https://github.com/ned14/outcome.git diff --git a/components/core/.clang-format b/components/core/.clang-format index 18195cc31..c8e66579c 100644 --- a/components/core/.clang-format +++ b/components/core/.clang-format @@ -75,7 +75,7 @@ IncludeCategories: # Library headers. Update when adding new libraries. # NOTE: clang-format retains leading white-space on a line in violation of the YAML spec. - Regex: "<(absl|antlr4|archive|boost|bsoncxx|catch2|curl|date|fmt|json|log_surgeon|mariadb\ -|mongocxx|msgpack|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" +|mongocxx|msgpack|outcome|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" Priority: 3 # C system headers - Regex: "^<.+\\.h>" diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp index 770a6a78c..5a9325553 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -10,9 +10,9 @@ #include #include -#include #include #include +#include #include "../../ir/types.hpp" #include "../../time_types.hpp" @@ -235,7 +235,7 @@ auto serialize_value_array( template auto Serializer::create( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { +) -> OUTCOME_V2_NAMESPACE::std_result> { static_assert( (std::is_same_v || std::is_same_v) @@ -493,9 +493,9 @@ auto Serializer::serialize_val( // Explicitly declare template specializations so that we can define the template methods in this // file template auto Serializer::create( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto Serializer::create( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto Serializer::change_utc_offset(UtcOffset utc_offset ) -> void; diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp index 82863bc7e..950d8481f 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -6,8 +6,8 @@ #include #include -#include #include +#include #include "../../time_types.hpp" #include "../SchemaTree.hpp" @@ -44,7 +44,7 @@ class Serializer { * - std::errc::protocol_error on failure to serialize the preamble. */ [[nodiscard]] static auto create( - ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + ) -> OUTCOME_V2_NAMESPACE::std_result>; // Disable copy constructor/assignment operator Serializer(Serializer const&) = delete; diff --git a/components/core/src/clp/ir/LogEventDeserializer.cpp b/components/core/src/clp/ir/LogEventDeserializer.cpp index b158a2712..9e0bf1723 100644 --- a/components/core/src/clp/ir/LogEventDeserializer.cpp +++ b/components/core/src/clp/ir/LogEventDeserializer.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "../ffi/ir_stream/decoding_methods.hpp" @@ -12,7 +13,7 @@ namespace clp::ir { template auto LogEventDeserializer::create(ReaderInterface& reader -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { +) -> OUTCOME_V2_NAMESPACE::std_result> { ffi::ir_stream::encoded_tag_t metadata_type{0}; std::vector metadata; auto ir_error_code = ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata); @@ -68,7 +69,7 @@ auto LogEventDeserializer::create(ReaderInterface& reader template auto LogEventDeserializer::deserialize_log_event( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { +) -> OUTCOME_V2_NAMESPACE::std_result> { // Process any packets before the log event ffi::ir_stream::encoded_tag_t tag{}; while (true) { @@ -129,11 +130,11 @@ auto LogEventDeserializer::deserialize_log_event( // Explicitly declare template specializations so that we can define the template methods in this // file template auto LogEventDeserializer::create(ReaderInterface& reader -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto LogEventDeserializer::create(ReaderInterface& reader -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto LogEventDeserializer::deserialize_log_event( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto LogEventDeserializer::deserialize_log_event( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; } // namespace clp::ir diff --git a/components/core/src/clp/ir/LogEventDeserializer.hpp b/components/core/src/clp/ir/LogEventDeserializer.hpp index 5fb72579d..a8bb4dc20 100644 --- a/components/core/src/clp/ir/LogEventDeserializer.hpp +++ b/components/core/src/clp/ir/LogEventDeserializer.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include "../ReaderInterface.hpp" #include "../time_types.hpp" @@ -35,7 +35,7 @@ class LogEventDeserializer { * or uses an unsupported version */ static auto create(ReaderInterface& reader - ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + ) -> OUTCOME_V2_NAMESPACE::std_result>; // Delete copy constructor and assignment LogEventDeserializer(LogEventDeserializer const&) = delete; @@ -62,7 +62,7 @@ class LogEventDeserializer { * - std::errc::protocol_error if the IR stream is corrupted */ [[nodiscard]] auto deserialize_log_event( - ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + ) -> OUTCOME_V2_NAMESPACE::std_result>; private: // Constructors diff --git a/components/core/src/glt/ir/LogEventDeserializer.cpp b/components/core/src/glt/ir/LogEventDeserializer.cpp index 00cd880e9..c22f22bb7 100644 --- a/components/core/src/glt/ir/LogEventDeserializer.cpp +++ b/components/core/src/glt/ir/LogEventDeserializer.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "../ffi/ir_stream/decoding_methods.hpp" @@ -11,7 +12,7 @@ namespace glt::ir { template auto LogEventDeserializer::create(ReaderInterface& reader -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { +) -> OUTCOME_V2_NAMESPACE::std_result> { ffi::ir_stream::encoded_tag_t metadata_type{0}; std::vector metadata; auto ir_error_code = ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata); @@ -67,7 +68,7 @@ auto LogEventDeserializer::create(ReaderInterface& reader template auto LogEventDeserializer::deserialize_log_event( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result> { +) -> OUTCOME_V2_NAMESPACE::std_result> { epoch_time_ms_t timestamp_or_timestamp_delta{}; std::string logtype; std::vector dict_vars; @@ -106,11 +107,11 @@ auto LogEventDeserializer::deserialize_log_event( // Explicitly declare template specializations so that we can define the template methods in this // file template auto LogEventDeserializer::create(ReaderInterface& reader -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto LogEventDeserializer::create(ReaderInterface& reader -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto LogEventDeserializer::deserialize_log_event( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; template auto LogEventDeserializer::deserialize_log_event( -) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; +) -> OUTCOME_V2_NAMESPACE::std_result>; } // namespace glt::ir diff --git a/components/core/src/glt/ir/LogEventDeserializer.hpp b/components/core/src/glt/ir/LogEventDeserializer.hpp index 9667f889a..4fbfb3c53 100644 --- a/components/core/src/glt/ir/LogEventDeserializer.hpp +++ b/components/core/src/glt/ir/LogEventDeserializer.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include "../ReaderInterface.hpp" #include "../TimestampPattern.hpp" @@ -34,7 +34,7 @@ class LogEventDeserializer { * or uses an unsupported version */ static auto create(ReaderInterface& reader - ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + ) -> OUTCOME_V2_NAMESPACE::std_result>; // Delete copy constructor and assignment LogEventDeserializer(LogEventDeserializer const&) = delete; @@ -59,7 +59,7 @@ class LogEventDeserializer { * - std::errc::result_out_of_range if the IR stream is corrupted */ [[nodiscard]] auto deserialize_log_event( - ) -> BOOST_OUTCOME_V2_NAMESPACE::std_result>; + ) -> OUTCOME_V2_NAMESPACE::std_result>; private: // Constructors diff --git a/components/core/submodules/boost-outcome b/components/core/submodules/boost-outcome deleted file mode 160000 index 39500a331..000000000 --- a/components/core/submodules/boost-outcome +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 39500a33117c23596673c1925479c7ff01b602f6 diff --git a/components/core/submodules/outcome b/components/core/submodules/outcome new file mode 160000 index 000000000..571f9c930 --- /dev/null +++ b/components/core/submodules/outcome @@ -0,0 +1 @@ +Subproject commit 571f9c930e672950e99d5d30f743603aaaf8014c diff --git a/components/core/tools/scripts/deps-download/boost-outcome.json b/components/core/tools/scripts/deps-download/boost-outcome.json deleted file mode 100644 index 01e89b394..000000000 --- a/components/core/tools/scripts/deps-download/boost-outcome.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/boostorg/outcome/archive/refs/tags/boost-1.83.0.zip", - "unzip": true, - "targets": [ - { - "source": "outcome-boost-1.83.0", - "destination": "submodules/boost-outcome" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/download-all.sh b/components/core/tools/scripts/deps-download/download-all.sh index ded2b2612..b552f1247 100755 --- a/components/core/tools/scripts/deps-download/download-all.sh +++ b/components/core/tools/scripts/deps-download/download-all.sh @@ -19,11 +19,11 @@ if [ -e "$project_root_dir/.git" ] ; then git submodule update --init --recursive else python3 "${script_dir}/download-dep.py" "${script_dir}/abseil-cpp.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/boost-outcome.json" python3 "${script_dir}/download-dep.py" "${script_dir}/Catch2.json" python3 "${script_dir}/download-dep.py" "${script_dir}/date.json" python3 "${script_dir}/download-dep.py" "${script_dir}/json.json" python3 "${script_dir}/download-dep.py" "${script_dir}/log-surgeon.json" + python3 "${script_dir}/download-dep.py" "${script_dir}/outcome.json" python3 "${script_dir}/download-dep.py" "${script_dir}/simdjson.json" python3 "${script_dir}/download-dep.py" "${script_dir}/yaml-cpp.json" fi diff --git a/components/core/tools/scripts/deps-download/outcome.json b/components/core/tools/scripts/deps-download/outcome.json new file mode 100644 index 000000000..1a0725f4b --- /dev/null +++ b/components/core/tools/scripts/deps-download/outcome.json @@ -0,0 +1,10 @@ +{ + "url": "https://github.com/ned14/outcome/archive/refs/tags/v2.2.9.zip", + "unzip": true, + "targets": [ + { + "source": "outcome-2.2.9", + "destination": "submodules/outcome" + } + ] +} From 44aaff907eb20225cd9785e756ed20e192997594 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Fri, 19 Jul 2024 04:07:17 -0400 Subject: [PATCH 030/114] Add initial implementation of regex_utils library containing a regex to wildcard string translator and a corresponding std::error_code enum and category. (#482) Co-authored-by: Bingran Hu Co-authored-by: davidlion Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Co-authored-by: Kirk Rodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 7 +- .../core/src/clp/regex_utils/CMakeLists.txt | 20 ++ .../core/src/clp/regex_utils/ErrorCode.cpp | 82 ++++++ .../core/src/clp/regex_utils/ErrorCode.hpp | 39 +++ .../RegexToWildcardTranslatorConfig.hpp | 46 ++++ .../core/src/clp/regex_utils/constants.hpp | 19 ++ .../regex_utils/regex_translation_utils.cpp | 248 ++++++++++++++++++ .../regex_utils/regex_translation_utils.hpp | 36 +++ components/core/tests/test-regex_utils.cpp | 38 +++ docs/src/dev-guide/components-core/index.md | 1 + .../dev-guide/components-core/regex-utils.md | 77 ++++++ 11 files changed, 611 insertions(+), 2 deletions(-) create mode 100644 components/core/src/clp/regex_utils/CMakeLists.txt create mode 100644 components/core/src/clp/regex_utils/ErrorCode.cpp create mode 100644 components/core/src/clp/regex_utils/ErrorCode.hpp create mode 100644 components/core/src/clp/regex_utils/RegexToWildcardTranslatorConfig.hpp create mode 100644 components/core/src/clp/regex_utils/constants.hpp create mode 100644 components/core/src/clp/regex_utils/regex_translation_utils.cpp create mode 100644 components/core/src/clp/regex_utils/regex_translation_utils.hpp create mode 100644 components/core/tests/test-regex_utils.cpp create mode 100644 docs/src/dev-guide/components-core/regex-utils.md diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 7cba49acb..57ae8cda1 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -209,6 +209,7 @@ set(sqlite_DYNAMIC_LIBS "dl;m;pthread") include(cmake/Modules/FindLibraryDependencies.cmake) FindDynamicLibraryDependencies(sqlite "${sqlite_DYNAMIC_LIBS}") +add_subdirectory(src/clp/regex_utils) add_subdirectory(src/clp/string_utils) add_subdirectory(src/clp/clg) @@ -304,11 +305,11 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/decoding_methods.inc src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp + src/clp/ffi/ir_stream/protocol_constants.hpp src/clp/ffi/ir_stream/Serializer.cpp src/clp/ffi/ir_stream/Serializer.hpp src/clp/ffi/ir_stream/utils.cpp src/clp/ffi/ir_stream/utils.hpp - src/clp/ffi/ir_stream/protocol_constants.hpp src/clp/ffi/SchemaTree.cpp src/clp/ffi/SchemaTree.hpp src/clp/ffi/SchemaTreeNode.hpp @@ -435,10 +436,10 @@ set(SOURCE_FILES_unitTest src/clp/StringReader.hpp src/clp/Thread.cpp src/clp/Thread.hpp + src/clp/time_types.hpp src/clp/TimestampPattern.cpp src/clp/TimestampPattern.hpp src/clp/TraceableException.hpp - src/clp/time_types.hpp src/clp/type_utils.hpp src/clp/utf8_utils.cpp src/clp/utf8_utils.hpp @@ -470,6 +471,7 @@ set(SOURCE_FILES_unitTest tests/test-NetworkReader.cpp tests/test-ParserWithUserSchema.cpp tests/test-query_methods.cpp + tests/test-regex_utils.cpp tests/test-Segment.cpp tests/test-SQLiteDB.cpp tests/test-Stopwatch.cpp @@ -497,6 +499,7 @@ target_link_libraries(unitTest spdlog::spdlog ${sqlite_LIBRARY_DEPENDENCIES} ${STD_FS_LIBS} + clp::regex_utils clp::string_utils yaml-cpp::yaml-cpp ZStd::ZStd diff --git a/components/core/src/clp/regex_utils/CMakeLists.txt b/components/core/src/clp/regex_utils/CMakeLists.txt new file mode 100644 index 000000000..c5d54dde0 --- /dev/null +++ b/components/core/src/clp/regex_utils/CMakeLists.txt @@ -0,0 +1,20 @@ +set( + REGEX_UTILS_HEADER_LIST + "constants.hpp" + "ErrorCode.hpp" + "regex_translation_utils.hpp" + "RegexToWildcardTranslatorConfig.hpp" +) +add_library( + regex_utils + ErrorCode.cpp + regex_translation_utils.cpp + ${REGEX_UTILS_HEADER_LIST} +) +add_library(clp::regex_utils ALIAS regex_utils) +target_include_directories(regex_utils + PRIVATE + ../ + "${PROJECT_SOURCE_DIR}/submodules" +) +target_compile_features(regex_utils PRIVATE cxx_std_20) diff --git a/components/core/src/clp/regex_utils/ErrorCode.cpp b/components/core/src/clp/regex_utils/ErrorCode.cpp new file mode 100644 index 000000000..5779263e8 --- /dev/null +++ b/components/core/src/clp/regex_utils/ErrorCode.cpp @@ -0,0 +1,82 @@ +#include "regex_utils/ErrorCode.hpp" + +#include +#include +#include + +namespace clp::regex_utils { +using std::error_code; + +namespace { +using std::error_category; +using std::string; +using std::string_view; + +/** + * Class for giving the error codes more detailed string descriptions. + */ +class ErrorCodeCategory : public error_category { +public: + /** + * @return The class of errors. + */ + [[nodiscard]] auto name() const noexcept -> char const* override; + + /** + * @param The error code encoded in int. + * @return The descriptive message for the error. + */ + [[nodiscard]] auto message(int ev) const -> string override; +}; + +auto ErrorCodeCategory::name() const noexcept -> char const* { + return "regex utility"; +} + +auto ErrorCodeCategory::message(int ev) const -> string { + switch (static_cast(ev)) { + case ErrorCode::Success: + return "Success."; + + case ErrorCode::IllegalState: + return "Unrecognized state."; + + case ErrorCode::UntranslatableStar: + return "Unable to express regex quantifier `*` in wildcard, which repeats a token for " + "zero or more occurences, unless it is combined with a wildcard `.`"; + + case ErrorCode::UntranslatablePlus: + return "Unable to express regex quantifier `+` in wildcard, which repeats a token for " + "one or more occurences, unless it is combined with a wildcard `.`"; + + case ErrorCode::UnsupportedQuestionMark: + return "Unable to express regex quantifier `?` in wildcard, which makes the preceding " + "token optional, unless the translator supports returning a list of possible " + "wildcard translations."; + + case ErrorCode::UnsupportedPipe: + return "Unable to express regex OR `|` in wildcard, which allows the query string to " + "match a single token out of a series of options, unless the translator " + "supports returning a list of possible wildcard translations."; + + case ErrorCode::IllegalCaret: + return "Failed to translate due to start anchor `^` in the middle of the string."; + + case ErrorCode::IllegalDollarSign: + return "Failed to translate due to end anchor `$` in the middle of the string."; + + case ErrorCode::UnmatchedParenthesis: + return "Unmatched opening `(` or closing `)`."; + + default: + return "(unrecognized error)"; + } +} + +ErrorCodeCategory const cErrorCodeCategoryInstance; +} // namespace + +auto make_error_code(ErrorCode e) -> error_code { + return {static_cast(e), cErrorCodeCategoryInstance}; +} +} // namespace clp::regex_utils diff --git a/components/core/src/clp/regex_utils/ErrorCode.hpp b/components/core/src/clp/regex_utils/ErrorCode.hpp new file mode 100644 index 000000000..1babb2fec --- /dev/null +++ b/components/core/src/clp/regex_utils/ErrorCode.hpp @@ -0,0 +1,39 @@ +#ifndef CLP_REGEX_UTILS_ERRORCODE_HPP +#define CLP_REGEX_UTILS_ERRORCODE_HPP + +#include +#include +#include + +namespace clp::regex_utils { +/** + * Enum class for propagating and handling various regex utility errors. + * More detailed descriptions can be found in ErrorCode.cpp. + */ +enum class ErrorCode : uint8_t { + Success = 0, + IllegalState, + UntranslatableStar, + UntranslatablePlus, + UnsupportedQuestionMark, + UnsupportedPipe, + IllegalCaret, + IllegalDollarSign, + UnmatchedParenthesis, +}; + +/** + * Wrapper function to turn a regular enum class into an std::error_code. + * + * @param An error code enum. + * @return The corresponding std::error_code type variable. + */ +[[nodiscard]] auto make_error_code(ErrorCode ec) -> std::error_code; +} // namespace clp::regex_utils + +namespace std { +template <> +struct is_error_code_enum : true_type {}; +} // namespace std + +#endif // CLP_REGEX_UTILS_ERRORCODE_HPP diff --git a/components/core/src/clp/regex_utils/RegexToWildcardTranslatorConfig.hpp b/components/core/src/clp/regex_utils/RegexToWildcardTranslatorConfig.hpp new file mode 100644 index 000000000..e53963c2e --- /dev/null +++ b/components/core/src/clp/regex_utils/RegexToWildcardTranslatorConfig.hpp @@ -0,0 +1,46 @@ +#ifndef CLP_REGEX_UTILS_REGEXTOWILDCARDTRANSLATORCONFIG_HPP +#define CLP_REGEX_UTILS_REGEXTOWILDCARDTRANSLATORCONFIG_HPP + +namespace clp::regex_utils { +/** + * Allows users to customize and fine tune how to translate a regex string to wildcard. + * + * This class won't affect the core logic and state trasition mechanics of the regex to wildcard + * translator, but it can make the translator more versatile. For detailed descriptions of how each + * option should be used, see the getter function docstrings. + */ +class RegexToWildcardTranslatorConfig { +public: + RegexToWildcardTranslatorConfig( + bool case_insensitive_wildcard, + bool add_prefix_suffix_wildcards + ) + : m_case_insensitive_wildcard{case_insensitive_wildcard}, + m_add_prefix_suffix_wildcards{add_prefix_suffix_wildcards} {}; + + /** + * @return True if the final translated wildcard string will be fed into a case-insensitive + * wildcard analyzer. In such cases, we can safely translate charset patterns such as [aA] [Bb] + * into singular lowercase characters a, b. + */ + [[nodiscard]] auto case_insensitive_wildcard() const -> bool { + return m_case_insensitive_wildcard; + } + + /** + * @return True if in the absense of starting or ending anchors in the regex string, we append + * prefix or suffix zero or more characters wildcards. In other words, this config is true if + * the search is a substring search, and false if the search is an exact search. + */ + [[nodiscard]] auto add_prefix_suffix_wildcards() const -> bool { + return m_add_prefix_suffix_wildcards; + } + +private: + // Variables + bool m_case_insensitive_wildcard; + bool m_add_prefix_suffix_wildcards; +}; +} // namespace clp::regex_utils + +#endif // CLP_REGEX_UTILS_REGEXTOWILDCARDTRANSLATORCONFIG_HPP diff --git a/components/core/src/clp/regex_utils/constants.hpp b/components/core/src/clp/regex_utils/constants.hpp new file mode 100644 index 000000000..879e7641d --- /dev/null +++ b/components/core/src/clp/regex_utils/constants.hpp @@ -0,0 +1,19 @@ +#ifndef CLP_REGEX_UTILS_CONSTANTS_HPP +#define CLP_REGEX_UTILS_CONSTANTS_HPP + +namespace clp::regex_utils { +// Wildcard meta characters +constexpr char cZeroOrMoreCharsWildcard{'*'}; +constexpr char cSingleCharWildcard{'?'}; + +// Regex meta characters +constexpr char cRegexZeroOrMore{'*'}; +constexpr char cRegexOneOrMore{'+'}; +constexpr char cRegexZeroOrOne{'?'}; +constexpr char cRegexStartAnchor{'^'}; +constexpr char cRegexEndAnchor{'$'}; +constexpr char cEscapeChar{'\\'}; +constexpr char cCharsetNegate{'^'}; +} // namespace clp::regex_utils + +#endif // CLP_REGEX_UTILS_CONSTANTS_HPP diff --git a/components/core/src/clp/regex_utils/regex_translation_utils.cpp b/components/core/src/clp/regex_utils/regex_translation_utils.cpp new file mode 100644 index 000000000..349c106f4 --- /dev/null +++ b/components/core/src/clp/regex_utils/regex_translation_utils.cpp @@ -0,0 +1,248 @@ +#include "regex_utils/regex_translation_utils.hpp" + +#include +#include +#include +#include + +#include + +#include "regex_utils/constants.hpp" +#include "regex_utils/ErrorCode.hpp" +#include "regex_utils/RegexToWildcardTranslatorConfig.hpp" + +namespace clp::regex_utils { +using std::error_code; +using std::string; +using std::string_view; + +namespace { +/** + * Class for storing regex translation analysis states, capture group, quantifier information, etc. + */ +class TranslatorState { +public: + /** + * States for which we apply specific rules to translate encountered regex patterns. + * + * This list may be expanded as the translator supports translating more regex patterns. + *
    + *
  • NORMAL: The initial state, where characters have no special meanings and are treated + * literally.
  • + *
  • DOT: Encountered a period `.`. Expecting wildcard expression.
  • + *
  • END: Encountered a dollar sign `$`, meaning the regex string has reached the end + * anchor.
  • + *
+ */ + enum class RegexPatternState : uint8_t { + NORMAL = 0, + DOT, + END, + }; + + // Constructor + TranslatorState() = default; + + // Getters + [[nodiscard]] auto get_state() const -> RegexPatternState { return m_state; } + + // Setters + auto set_next_state(RegexPatternState const& state) -> void { m_state = state; } + +private: + // Members + RegexPatternState m_state{RegexPatternState::NORMAL}; +}; + +/** + * Functions that handle current-state-specific tasks before transitioning to the next state. + * + * @param[in, out] state The object that stores translator's internal information. The primary + * state member variable is always updated if a transition occures. Even if there's no state + * transition, other analysis info may be updated. + * @param[in, out] it The iterator that represents the current regex string scan position. May be + * updated to advance or backtrack the scan position. + * @param[out] wildcard_str The translated wildcard string. May or may not be updated. + * @param[in] config The translator config. + * @return clp::regex_utils::ErrorCode + */ +using StateTransitionFuncSig + = auto(TranslatorState& state, + string_view::const_iterator& it, + string& wildcard_str, + RegexToWildcardTranslatorConfig const& config) -> error_code; + +/** + * Treats each character literally and directly append it to the wildcard string, unless it is a + * meta-character. + * + * Each meta-character either triggers a state transition, or makes the regex string untranslatable. + */ +[[nodiscard]] StateTransitionFuncSig normal_state_transition; + +/** + * Attempts to translate regex wildcard patterns that start with `.` character. + * + * Performs the following translation if possible: + *
    + *
  • `.*` gets translated into `*`
  • + *
  • `.+` gets translated into `?*`
  • + *
  • `.` gets translated into `?`
  • + *
+ */ +[[nodiscard]] StateTransitionFuncSig dot_state_transition; + +/** + * Disallows the appearances of other characters after encountering an end anchor in the string. + */ +[[nodiscard]] StateTransitionFuncSig end_state_transition; + +/** + * States other than the NORMAL state may require special handling after the whole regex string has + * been scanned and processed. + */ +[[nodiscard]] StateTransitionFuncSig final_state_cleanup; + +auto normal_state_transition( + TranslatorState& state, + string_view::const_iterator& it, + string& wildcard_str, + [[maybe_unused]] RegexToWildcardTranslatorConfig const& config +) -> error_code { + auto const ch{*it}; + switch (ch) { + case '.': + state.set_next_state(TranslatorState::RegexPatternState::DOT); + break; + case cRegexEndAnchor: + state.set_next_state(TranslatorState::RegexPatternState::END); + break; + case cRegexZeroOrMore: + return ErrorCode::UntranslatableStar; + case cRegexOneOrMore: + return ErrorCode::UntranslatablePlus; + case cRegexZeroOrOne: + return ErrorCode::UnsupportedQuestionMark; + case '|': + return ErrorCode::UnsupportedPipe; + case cRegexStartAnchor: + return ErrorCode::IllegalCaret; + case ')': + return ErrorCode::UnmatchedParenthesis; + default: + wildcard_str += ch; + break; + } + return ErrorCode::Success; +} + +auto dot_state_transition( + TranslatorState& state, + string_view::const_iterator& it, + string& wildcard_str, + [[maybe_unused]] RegexToWildcardTranslatorConfig const& config +) -> error_code { + switch (*it) { + case cZeroOrMoreCharsWildcard: + wildcard_str += cZeroOrMoreCharsWildcard; + break; + case cRegexOneOrMore: + wildcard_str = wildcard_str + cSingleCharWildcard + cZeroOrMoreCharsWildcard; + break; + default: + wildcard_str += cSingleCharWildcard; + // Backtrack the scan by one position to handle the current char in the next iteration. + --it; + break; + } + state.set_next_state(TranslatorState::RegexPatternState::NORMAL); + return ErrorCode::Success; +} + +auto end_state_transition( + [[maybe_unused]] TranslatorState& state, + string_view::const_iterator& it, + [[maybe_unused]] string& wildcard_str, + [[maybe_unused]] RegexToWildcardTranslatorConfig const& config +) -> error_code { + if (cRegexEndAnchor != *it) { + return ErrorCode::IllegalDollarSign; + } + return ErrorCode::Success; +} + +auto final_state_cleanup( + TranslatorState& state, + [[maybe_unused]] string_view::const_iterator& it, + string& wildcard_str, + RegexToWildcardTranslatorConfig const& config +) -> error_code { + switch (state.get_state()) { + case TranslatorState::RegexPatternState::DOT: + // The last character is a single `.`, without the possibility of becoming a + // multichar wildcard + wildcard_str += cSingleCharWildcard; + break; + default: + break; + } + + if (TranslatorState::RegexPatternState::END != state.get_state() + && config.add_prefix_suffix_wildcards()) + { + wildcard_str += cZeroOrMoreCharsWildcard; + } + return ErrorCode::Success; +} +} // namespace + +auto regex_to_wildcard(string_view regex_str) -> OUTCOME_V2_NAMESPACE::std_result { + return regex_to_wildcard(regex_str, {false, false}); +} + +auto regex_to_wildcard(string_view regex_str, RegexToWildcardTranslatorConfig const& config) + -> OUTCOME_V2_NAMESPACE::std_result { + if (regex_str.empty()) { + return string{}; + } + + TranslatorState state; + string_view::const_iterator it{regex_str.cbegin()}; + string wildcard_str; + + // If there is no starting anchor character, append multichar wildcard prefix + if (cRegexStartAnchor == *it) { + ++it; + } else if (config.add_prefix_suffix_wildcards()) { + wildcard_str += cZeroOrMoreCharsWildcard; + } + + error_code ec{}; + while (it != regex_str.cend()) { + switch (state.get_state()) { + case TranslatorState::RegexPatternState::NORMAL: + ec = normal_state_transition(state, it, wildcard_str, config); + break; + case TranslatorState::RegexPatternState::DOT: + ec = dot_state_transition(state, it, wildcard_str, config); + break; + case TranslatorState::RegexPatternState::END: + ec = end_state_transition(state, it, wildcard_str, config); + break; + default: + ec = ErrorCode::IllegalState; + break; + } + if (ec) { + return ec; + } + ++it; + } + + ec = final_state_cleanup(state, it, wildcard_str, config); + if (ec) { + return ec; + } + return wildcard_str; +} +} // namespace clp::regex_utils diff --git a/components/core/src/clp/regex_utils/regex_translation_utils.hpp b/components/core/src/clp/regex_utils/regex_translation_utils.hpp new file mode 100644 index 000000000..8ca703403 --- /dev/null +++ b/components/core/src/clp/regex_utils/regex_translation_utils.hpp @@ -0,0 +1,36 @@ +#ifndef CLP_REGEX_UTILS_REGEX_UTILS_HPP +#define CLP_REGEX_UTILS_REGEX_UTILS_HPP + +#include +#include + +#include + +#include "regex_utils/RegexToWildcardTranslatorConfig.hpp" + +namespace clp::regex_utils { + +/** + * Translate a given regex string to wildcard with the default configuration that has all the + * options set to false. + * + * @param regex_str The regex string to be translated. + * @return The translated wildcard string. + */ +[[nodiscard]] auto regex_to_wildcard(std::string_view regex_str +) -> OUTCOME_V2_NAMESPACE::std_result; + +/** + * Translate a given regex string to wildcard with a custom configuration. + * + * @param regex_str The regex string to be translated. + * @return The translated wildcard string. + */ +[[nodiscard]] auto regex_to_wildcard( + std::string_view regex_str, + RegexToWildcardTranslatorConfig const& config +) -> OUTCOME_V2_NAMESPACE::std_result; + +} // namespace clp::regex_utils + +#endif // CLP_REGEX_UTILS_REGEX_UTILS_HPP diff --git a/components/core/tests/test-regex_utils.cpp b/components/core/tests/test-regex_utils.cpp new file mode 100644 index 000000000..fc79b966a --- /dev/null +++ b/components/core/tests/test-regex_utils.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#include + +using clp::regex_utils::ErrorCode; +using clp::regex_utils::regex_to_wildcard; +using clp::regex_utils::RegexToWildcardTranslatorConfig; + +TEST_CASE("regex_to_wildcard", "[regex_utils][regex_to_wildcard]") { + // Test empty string + REQUIRE(regex_to_wildcard("").value().empty()); + + // Test simple wildcard translations + REQUIRE((regex_to_wildcard("xyz").value() == "xyz")); + REQUIRE((regex_to_wildcard(". xyz .* zyx .").value() == "? xyz * zyx ?")); + REQUIRE((regex_to_wildcard(". xyz .+ zyx .*").value() == "? xyz ?* zyx *")); + + // Test unescaped meta characters + REQUIRE((regex_to_wildcard(".? xyz .* zyx .").error() == ErrorCode::UnsupportedQuestionMark)); + REQUIRE((regex_to_wildcard(". xyz .** zyx .").error() == ErrorCode::UntranslatableStar)); + REQUIRE((regex_to_wildcard(". xyz .*+ zyx .").error() == ErrorCode::UntranslatablePlus)); + REQUIRE((regex_to_wildcard(". xyz |.* zyx .").error() == ErrorCode::UnsupportedPipe)); + REQUIRE((regex_to_wildcard(". xyz ^.* zyx .").error() == ErrorCode::IllegalCaret)); +} + +TEST_CASE("regex_to_wildcard_anchor_config", "[regex_utils][regex_to_wildcard][anchor_config]") { + // Test anchors and prefix/suffix wildcards + RegexToWildcardTranslatorConfig const config{false, true}; + REQUIRE(((regex_to_wildcard("^", config).value() == "*"))); + REQUIRE((regex_to_wildcard("$", config).value() == "*")); + REQUIRE((regex_to_wildcard("^xyz$", config).value() == "xyz")); + REQUIRE((regex_to_wildcard("xyz", config).value() == "*xyz*")); + REQUIRE((regex_to_wildcard("xyz$$", config).value() == "*xyz")); + + REQUIRE((regex_to_wildcard("xyz$zyx$", config).error() == ErrorCode::IllegalDollarSign)); +} diff --git a/docs/src/dev-guide/components-core/index.md b/docs/src/dev-guide/components-core/index.md index 0e9fd2623..62360486a 100644 --- a/docs/src/dev-guide/components-core/index.md +++ b/docs/src/dev-guide/components-core/index.md @@ -91,6 +91,7 @@ centos7.4-deps-install macos12-deps-install ubuntu-focal-deps-install ubuntu-jammy-deps-install +regex-utils ::: [feature-req]: https://github.com/y-scope/clp/issues/new?assignees=&labels=enhancement&template=feature-request.yml diff --git a/docs/src/dev-guide/components-core/regex-utils.md b/docs/src/dev-guide/components-core/regex-utils.md new file mode 100644 index 000000000..a7ec16774 --- /dev/null +++ b/docs/src/dev-guide/components-core/regex-utils.md @@ -0,0 +1,77 @@ +# regex_utils library + +This library contains useful utilities to handle all regex related tasks. + +## Regex to Wildcard Translator + +### Goal + +Performs a best-effort translation to turn a regex string to an equivalent wildcard string. + +CLP currently only recognizes three meta-characters in the wildcard syntax: + +* `?` Matches any single character +* `*` Matches zero or more characters +* `\` Suppresses the special meaning of meta characters (including itself) + +If the regex query can actually be expressed as a wildcard query only deploying the three +metacharacters above, CLP should use the wildcard version. + +### Includes + +* The translator function returns a `Result` type, which can either +contain a value or an error code. + +To use the translator: + +```cpp +#include + +using clp::regex_utils::regex_to_wildcard; + +// Other code + +auto result{regex_to_wildcard(wildcard_str)}; +if (result.has_error()) { + auto err_code{result.error()}; + // Handle error +} else { + auto regex_str{result.value()}; + // Do things with the translated string +} +``` + +* To add custom configuration to the translator: + +```cpp +#include + +RegexToWildcardTranslatorConfig config{true, false, /*...other booleans*/}; +auto result{regex_to_wildcard(wildcard_str, config)}; + +// Same as above +``` + +For a detailed description on the options order and usage, see the +[Custom Configuration](#custom-configuration) section. + +### Functionalities + +* Wildcards + * Turn `.` into `?` + * Turn `.*` into `*` + * Turn `.+` into `?*` + * E.g. `abc.*def.ghi.+` will get translated to `abc*def?ghi?*` + +### Custom configuration + +The `RegexToWildcardTranslatorConfig` class objects are currently immutable once instantiated. The +constructor takes the following arguments in order: + +* `case_insensitive_wildcard`: to be added later along with the character set translation + implementation. + +* `add_prefix_suffix_wildcards`: in the absence of regex anchors, add prefix or suffix wildcards so + the query becomes a substring query. + * E.g. `info.*system` gets translated into `*info*system*` which makes the original query a + substring query. From 1d71b6f4f6d918755ae4b9c1b3ca7d52f241bddb Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Fri, 19 Jul 2024 10:14:44 -0400 Subject: [PATCH 031/114] clp-package: Add support for extracting files as IR streams through the CLI. (#472) --- .../clp_package_utils/general.py | 10 +- .../clp_package_utils/scripts/decompress.py | 203 ++++++++++++++---- .../scripts/native/decompress.py | 189 ++++++++++++++-- .../clp_package_utils/scripts/native/utils.py | 2 +- 4 files changed, 338 insertions(+), 66 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index a2e6e344f..d1edf7d5b 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -8,7 +8,7 @@ import typing import uuid from enum import auto -from typing import List, Tuple +from typing import List, Optional, Tuple import yaml from clp_py_utils.clp_config import ( @@ -31,6 +31,9 @@ from strenum import KebabCaseStrEnum # CONSTANTS +EXTRACT_FILE_CMD = "x" +EXTRACT_IR_CMD = "i" + # Paths CONTAINER_CLP_HOME = pathlib.Path("/") / "opt" / "clp" CONTAINER_INPUT_LOGS_ROOT_DIR = pathlib.Path("/") / "mnt" / "logs" @@ -45,7 +48,8 @@ class DockerMountType(enum.IntEnum): class JobType(KebabCaseStrEnum): COMPRESSION = auto() - DECOMPRESSION = auto() + FILE_EXTRACTION = auto() + IR_EXTRACTION = auto() SEARCH = auto() @@ -283,7 +287,7 @@ def dump_container_config( def generate_container_start_cmd( - container_name: str, container_mounts: List[CLPDockerMounts], container_image: str + container_name: str, container_mounts: List[Optional[DockerMount]], container_image: str ) -> List[str]: """ Generates the command to start a container with the given mounts and name. diff --git a/components/clp-package-utils/clp_package_utils/scripts/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/decompress.py index f700d9721..1a2973fec 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/decompress.py @@ -3,6 +3,7 @@ import pathlib import subprocess import sys +from typing import Optional from clp_py_utils.clp_config import CLPConfig @@ -11,6 +12,8 @@ DockerMount, DockerMountType, dump_container_config, + EXTRACT_FILE_CMD, + EXTRACT_IR_CMD, generate_container_config, generate_container_name, generate_container_start_cmd, @@ -32,40 +35,43 @@ logger.addHandler(logging_console_handler) -def main(argv): - clp_home = get_clp_home() - default_config_file_path = clp_home / CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH - - args_parser = argparse.ArgumentParser(description="Decompresses logs") - args_parser.add_argument( - "--config", - "-c", - type=str, - default=str(default_config_file_path), - help="CLP package configuration file.", - ) - args_parser.add_argument("paths", metavar="PATH", nargs="*", help="Files to decompress.") - args_parser.add_argument("-f", "--files-from", help="A file listing all files to decompress.") - args_parser.add_argument( - "-d", "--extraction-dir", metavar="DIR", default=".", help="Decompress files into DIR" - ) - parsed_args = args_parser.parse_args(argv[1:]) - - # Validate and load config file +def validate_and_load_config( + clp_home: pathlib.Path, + config_file_path: pathlib.Path, + default_config_file_path: pathlib.Path, +) -> Optional[CLPConfig]: + """ + Validates and loads the config file. + :param clp_home: + :param config_file_path: + :param default_config_file_path: + :return: The config object on success, None otherwise. + """ try: - config_file_path = pathlib.Path(parsed_args.config) clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) clp_config.validate_logs_dir() # Validate and load necessary credentials validate_and_load_db_credentials_file(clp_config, clp_home, False) + return clp_config except: logger.exception("Failed to load config.") - return -1 + return None + - paths_to_decompress_file_path = None +def handle_extract_file_cmd( + parsed_args, clp_home: pathlib.Path, default_config_file_path: pathlib.Path +) -> int: + """ + Handles the file extraction command. + :param parsed_args: + :param clp_home: + :param default_config_file_path: + :return: 0 on success, -1 otherwise. + """ + paths_to_extract_file_path = None if parsed_args.files_from: - paths_to_decompress_file_path = pathlib.Path(parsed_args.files_from) + paths_to_extract_file_path = pathlib.Path(parsed_args.files_from) # Validate extraction directory extraction_dir = pathlib.Path(parsed_args.extraction_dir).resolve() @@ -74,15 +80,22 @@ def main(argv): except ValueError as ex: logger.error(f"extraction-dir is invalid: {ex}") return -1 - extraction_dir.mkdir(exist_ok=True) - container_name = generate_container_name(JobType.DECOMPRESSION) + # Validate and load config file + clp_config = validate_and_load_config( + clp_home, pathlib.Path(parsed_args.config), default_config_file_path + ) + if clp_config is None: + return -1 + + container_name = generate_container_name(JobType.FILE_EXTRACTION) container_clp_config, mounts = generate_container_config(clp_config, clp_home) generated_config_path_on_container, generated_config_path_on_host = dump_container_config( container_clp_config, clp_config, container_name ) # Set up mounts + extraction_dir.mkdir(exist_ok=True) container_extraction_dir = pathlib.Path("/") / "mnt" / "extraction-dir" necessary_mounts = [ mounts.clp_home, @@ -91,16 +104,14 @@ def main(argv): mounts.archives_output_dir, DockerMount(DockerMountType.BIND, extraction_dir, container_extraction_dir), ] - container_paths_to_decompress_file_path = None - if paths_to_decompress_file_path: - container_paths_to_decompress_file_path = ( - pathlib.Path("/") / "mnt" / "paths-to-decompress.txt" - ) + container_paths_to_extract_file_path = None + if paths_to_extract_file_path: + container_paths_to_extract_file_path = pathlib.Path("/") / "mnt" / "paths-to-extract.txt" necessary_mounts.append( DockerMount( DockerMountType.BIND, - paths_to_decompress_file_path, - container_paths_to_decompress_file_path, + paths_to_extract_file_path, + container_paths_to_extract_file_path, ) ) container_start_cmd = generate_container_start_cmd( @@ -108,21 +119,26 @@ def main(argv): ) # fmt: off - decompress_cmd = [ + extract_cmd = [ "python3", "-m", "clp_package_utils.scripts.native.decompress", "--config", str(generated_config_path_on_container), + EXTRACT_FILE_CMD, "-d", str(container_extraction_dir), ] # fmt: on for path in parsed_args.paths: - decompress_cmd.append(path) - if container_paths_to_decompress_file_path: - decompress_cmd.append("--input-list") - decompress_cmd.append(container_paths_to_decompress_file_path) + extract_cmd.append(path) + if container_paths_to_extract_file_path: + extract_cmd.append("--input-list") + extract_cmd.append(container_paths_to_extract_file_path) - cmd = container_start_cmd + decompress_cmd - subprocess.run(cmd, check=True) + cmd = container_start_cmd + extract_cmd + try: + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + logger.exception("Docker or file extraction command failed.") + return -1 # Remove generated files generated_config_path_on_host.unlink() @@ -130,5 +146,112 @@ def main(argv): return 0 +def handle_extract_ir_cmd( + parsed_args, clp_home: pathlib.Path, default_config_file_path: pathlib.Path +) -> int: + """ + Handles the IR extraction command. + :param parsed_args: + :param clp_home: + :param default_config_file_path: + :return: 0 on success, -1 otherwise. + """ + # Validate and load config file + clp_config = validate_and_load_config( + clp_home, pathlib.Path(parsed_args.config), default_config_file_path + ) + if clp_config is None: + return -1 + + container_name = generate_container_name(JobType.IR_EXTRACTION) + container_clp_config, mounts = generate_container_config(clp_config, clp_home) + generated_config_path_on_container, generated_config_path_on_host = dump_container_config( + container_clp_config, clp_config, container_name + ) + necessary_mounts = [mounts.clp_home, mounts.logs_dir] + container_start_cmd = generate_container_start_cmd( + container_name, necessary_mounts, clp_config.execution_container + ) + + # fmt: off + extract_cmd = [ + "python3", + "-m", "clp_package_utils.scripts.native.decompress", + "--config", str(generated_config_path_on_container), + EXTRACT_IR_CMD, + str(parsed_args.msg_ix), + ] + # fmt: on + if parsed_args.orig_file_id: + extract_cmd.append("--orig-file-id") + extract_cmd.append(str(parsed_args.orig_file_id)) + else: + extract_cmd.append("--orig-file-path") + extract_cmd.append(str(parsed_args.orig_file_path)) + if parsed_args.target_uncompressed_size: + extract_cmd.append("--target-uncompressed-size") + extract_cmd.append(str(parsed_args.target_uncompressed_size)) + cmd = container_start_cmd + extract_cmd + + try: + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + logger.exception("Docker or IR extraction command failed.") + return -1 + + # Remove generated files + generated_config_path_on_host.unlink() + + return 0 + + +def main(argv): + clp_home = get_clp_home() + default_config_file_path = clp_home / CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH + + args_parser = argparse.ArgumentParser(description="Decompresses logs") + args_parser.add_argument( + "--config", + "-c", + default=str(default_config_file_path), + help="CLP configuration file.", + ) + command_args_parser = args_parser.add_subparsers(dest="command", required=True) + + # File extraction command parser + file_extraction_parser = command_args_parser.add_parser(EXTRACT_FILE_CMD) + file_extraction_parser.add_argument( + "paths", metavar="PATH", nargs="*", help="Files to extract." + ) + file_extraction_parser.add_argument( + "-f", "--files-from", help="A file listing all files to extract." + ) + file_extraction_parser.add_argument( + "-d", "--extraction-dir", metavar="DIR", default=".", help="Extract files into DIR." + ) + + # IR extraction command parser + ir_extraction_parser = command_args_parser.add_parser(EXTRACT_IR_CMD) + ir_extraction_parser.add_argument("msg_ix", type=int, help="Message index.") + ir_extraction_parser.add_argument( + "--target-uncompressed-size", type=int, help="Target uncompressed IR size." + ) + + group = ir_extraction_parser.add_mutually_exclusive_group(required=True) + group.add_argument("--orig-file-id", type=str, help="Original file's ID.") + group.add_argument("--orig-file-path", type=str, help="Original file's path.") + + parsed_args = args_parser.parse_args(argv[1:]) + + command = parsed_args.command + if EXTRACT_FILE_CMD == command: + return handle_extract_file_cmd(parsed_args, clp_home, default_config_file_path) + elif EXTRACT_IR_CMD == command: + return handle_extract_ir_cmd(parsed_args, clp_home, default_config_file_path) + else: + logger.exception(f"Unexpected command: {command}") + return -1 + + if "__main__" == __name__: sys.exit(main(sys.argv)) diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py index 9331492b4..b6585b192 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py @@ -1,19 +1,31 @@ import argparse +import asyncio import logging import pathlib import subprocess import sys import uuid +from contextlib import closing from typing import Optional import yaml -from clp_py_utils.clp_config import CLPConfig +from clp_py_utils.clp_config import CLP_METADATA_TABLE_PREFIX, CLPConfig, Database +from clp_py_utils.sql_adapter import SQL_Adapter +from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType +from job_orchestration.scheduler.job_config import ExtractIrJobConfig from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, + EXTRACT_FILE_CMD, + EXTRACT_IR_CMD, get_clp_home, load_config_file, ) +from clp_package_utils.scripts.native.utils import ( + run_function_in_process, + submit_query_job, + wait_for_query_job, +) # Setup logging # Create logger @@ -26,6 +38,112 @@ logger.addHandler(logging_console_handler) +def get_orig_file_id(db_config: Database, path: str) -> Optional[str]: + """ + :param db_config: + :param path: Path of the original file. + :return: The ID of an original file which has the given path, or None if no such file exists. + NOTE: Multiple original files may have the same path in which case this method returns the ID of + only one of them. + """ + sql_adapter = SQL_Adapter(db_config) + with closing(sql_adapter.create_connection(True)) as db_conn, closing( + db_conn.cursor(dictionary=True) + ) as db_cursor: + db_cursor.execute( + f"SELECT orig_file_id FROM `{CLP_METADATA_TABLE_PREFIX}files` WHERE path = (%s)", + (path,), + ) + results = db_cursor.fetchall() + db_conn.commit() + + if len(results) == 0: + logger.error("No file found for the given path.") + return None + + if len(results) > 1: + logger.warning( + "Multiple files found for the given path." + " Returning the orig_file_id of one of them." + ) + + return results[0]["orig_file_id"] + + +def submit_and_monitor_ir_extraction_job_in_db( + db_config: Database, + orig_file_id: str, + msg_ix: int, + target_uncompressed_size: Optional[int], +) -> int: + """ + Submits an IR extraction job to the scheduler and waits until the job finishes. + :param db_config: + :param orig_file_id: + :param msg_ix: + :param target_uncompressed_size: + :return: 0 on success, -1 otherwise. + """ + extract_ir_config = ExtractIrJobConfig( + orig_file_id=orig_file_id, + msg_ix=msg_ix, + target_uncompressed_size=target_uncompressed_size, + ) + + sql_adapter = SQL_Adapter(db_config) + job_id = submit_query_job(sql_adapter, extract_ir_config, QueryJobType.EXTRACT_IR) + job_status = wait_for_query_job(sql_adapter, job_id) + + if QueryJobStatus.SUCCEEDED == job_status: + logger.info(f"Finished IR extraction job {job_id}.") + return 0 + + logger.error( + f"IR extraction job {job_id} finished with unexpected status: {job_status.to_str()}." + ) + return -1 + + +def handle_extract_ir_cmd( + parsed_args: argparse.Namespace, clp_home: pathlib.Path, default_config_file_path: pathlib.Path +) -> int: + """ + Handles the IR extraction command. + :param parsed_args: + :param clp_home: + :param default_config_file_path: + :return: 0 on success, -1 otherwise. + """ + # Validate and load config file + clp_config = validate_and_load_config_file( + clp_home, pathlib.Path(parsed_args.config), default_config_file_path + ) + if clp_config is None: + return -1 + + orig_file_id: str + if parsed_args.orig_file_id: + orig_file_id = parsed_args.orig_file_id + else: + orig_file_id = get_orig_file_id(clp_config.database, parsed_args.orig_file_path) + if orig_file_id is None: + return -1 + + try: + return asyncio.run( + run_function_in_process( + submit_and_monitor_ir_extraction_job_in_db, + clp_config.database, + orig_file_id, + parsed_args.msg_ix, + parsed_args.target_uncompressed_size, + ) + ) + except asyncio.CancelledError: + logger.error("IR extraction cancelled.") + return -1 + + def validate_and_load_config_file( clp_home: pathlib.Path, config_file_path: pathlib.Path, @@ -48,11 +166,11 @@ def validate_and_load_config_file( return None -def handle_decompression_command( +def handle_extract_file_cmd( parsed_args: argparse.Namespace, clp_home: pathlib.Path, default_config_file_path: pathlib.Path -): +) -> int: """ - Handles the decompression command. + Handles the file extraction command. :param parsed_args: :param clp_home: :param default_config_file_path: @@ -73,7 +191,7 @@ def handle_decompression_command( clp_config = validate_and_load_config_file( clp_home, pathlib.Path(parsed_args.config), default_config_file_path ) - if not clp_config: + if clp_config is None: return -1 paths = parsed_args.paths @@ -88,36 +206,36 @@ def handle_decompression_command( yaml.safe_dump(clp_config.database.get_clp_connection_params_and_type(True), f) # fmt: off - decompression_cmd = [ + extract_cmd = [ str(clp_home / "bin" / "clp"), "x", str(archives_dir), str(extraction_dir), "--db-config-file", str(db_config_file_path), ] # fmt: on - files_to_decompress_list_path = None + files_to_extract_list_path = None if list_path is not None: - decompression_cmd.append("-f") - decompression_cmd.append(str(list_path)) + extract_cmd.append("-f") + extract_cmd.append(str(list_path)) elif len(paths) > 0: # Write paths to file - files_to_decompress_list_path = logs_dir / f"paths-to-decompress-{uuid.uuid4()}.txt" - with open(files_to_decompress_list_path, "w") as stream: + files_to_extract_list_path = logs_dir / f"paths-to-extract-{uuid.uuid4()}.txt" + with open(files_to_extract_list_path, "w") as stream: for path in paths: stream.write(path + "\n") - decompression_cmd.append("-f") - decompression_cmd.append(str(files_to_decompress_list_path)) + extract_cmd.append("-f") + extract_cmd.append(str(files_to_extract_list_path)) - proc = subprocess.Popen(decompression_cmd) + proc = subprocess.Popen(extract_cmd) return_code = proc.wait() if 0 != return_code: - logger.error(f"Decompression failed, return_code={return_code}") + logger.error(f"File extraction failed, return_code={return_code}") return return_code # Remove generated files - if files_to_decompress_list_path is not None: - files_to_decompress_list_path.unlink() + if files_to_extract_list_path is not None: + files_to_extract_list_path.unlink() db_config_file_path.unlink() return 0 @@ -135,14 +253,41 @@ def main(argv): default=str(default_config_file_path), help="CLP configuration file.", ) - args_parser.add_argument("paths", metavar="PATH", nargs="*", help="Paths to decompress.") - args_parser.add_argument("-f", "--files-from", help="Decompress all paths in the given list.") - args_parser.add_argument( - "-d", "--extraction-dir", metavar="DIR", help="Decompress files into DIR", default="." + command_args_parser = args_parser.add_subparsers(dest="command", required=True) + + # File extraction command parser + file_extraction_parser = command_args_parser.add_parser(EXTRACT_FILE_CMD) + file_extraction_parser.add_argument( + "paths", metavar="PATH", nargs="*", help="Files to extract." + ) + file_extraction_parser.add_argument( + "-f", "--files-from", help="A file listing all files to extract." + ) + file_extraction_parser.add_argument( + "-d", "--extraction-dir", metavar="DIR", default=".", help="Extract files into DIR." ) + + # IR extraction command parser + ir_extraction_parser = command_args_parser.add_parser(EXTRACT_IR_CMD) + ir_extraction_parser.add_argument("msg_ix", type=int, help="Message index.") + ir_extraction_parser.add_argument( + "--target-uncompressed-size", type=int, help="Target uncompressed IR size." + ) + + group = ir_extraction_parser.add_mutually_exclusive_group(required=True) + group.add_argument("--orig-file-id", type=str, help="Original file's ID.") + group.add_argument("--orig-file-path", type=str, help="Original file's path.") + parsed_args = args_parser.parse_args(argv[1:]) - return handle_decompression_command(parsed_args, clp_home, default_config_file_path) + command = parsed_args.command + if EXTRACT_FILE_CMD == command: + return handle_extract_file_cmd(parsed_args, clp_home, default_config_file_path) + elif EXTRACT_IR_CMD == command: + return handle_extract_ir_cmd(parsed_args, clp_home, default_config_file_path) + else: + logger.exception(f"Unexpected command: {command}") + return -1 if "__main__" == __name__: diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/utils.py b/components/clp-package-utils/clp_package_utils/scripts/native/utils.py index 6b94e4676..2f5c51a11 100644 --- a/components/clp-package-utils/clp_package_utils/scripts/native/utils.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/utils.py @@ -86,7 +86,7 @@ def wait_for_query_job(sql_adapter: SQL_Adapter, job_id: int) -> QueryJobStatus: ) # There will only ever be one row since it's impossible to have more than one job with # the same ID - new_status = db_cursor.fetchall()[0]["status"] + new_status = QueryJobStatus(db_cursor.fetchall()[0]["status"]) db_conn.commit() if new_status in ( QueryJobStatus.SUCCEEDED, From c62b7588eecaaac6c864c74d0565a6bff49021a0 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 19 Jul 2024 18:00:48 -0400 Subject: [PATCH 032/114] core-clp: Fix ArchiveMetadata deserialization by deserializing previously missed field. (#488) --- components/core/src/clp/streaming_archive/ArchiveMetadata.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/core/src/clp/streaming_archive/ArchiveMetadata.cpp b/components/core/src/clp/streaming_archive/ArchiveMetadata.cpp index 7b40022a9..9cf578eb8 100644 --- a/components/core/src/clp/streaming_archive/ArchiveMetadata.cpp +++ b/components/core/src/clp/streaming_archive/ArchiveMetadata.cpp @@ -26,6 +26,7 @@ ArchiveMetadata::ArchiveMetadata(FileReader& file_reader) { file_reader.read_numeric_value(m_archive_format_version, false); file_reader.read_numeric_value(m_creator_id_len, false); file_reader.read_string(m_creator_id_len, m_creator_id, false); + file_reader.read_numeric_value(m_creation_idx, false); file_reader.read_numeric_value(m_uncompressed_size, false); file_reader.read_numeric_value(m_compressed_size, false); file_reader.read_numeric_value(m_begin_timestamp, false); From 921a388cfcccf465e344e103fe7956459056dc9e Mon Sep 17 00:00:00 2001 From: wraymo <37269683+wraymo@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:56:44 -0400 Subject: [PATCH 033/114] log-viewer-webui: Add server implementation for submitting IR extraction jobs and serving IR files; Don't copy unnecessary files when building component. (#458) --- Taskfile.yml | 35 +- .../clp_package_utils/general.py | 10 +- .../clp_package_utils/scripts/start_clp.py | 79 +- .../clp-py-utils/clp_py_utils/clp_config.py | 1 - components/log-viewer-webui/server/.env | 5 + components/log-viewer-webui/server/.gitignore | 3 + .../log-viewer-webui/server/package-lock.json | 1318 +++++++++++++++-- .../log-viewer-webui/server/package.json | 19 +- .../log-viewer-webui/server/settings.json | 13 + .../log-viewer-webui/server/src/DbManager.js | 241 +++ components/log-viewer-webui/server/src/app.js | 57 +- .../log-viewer-webui/server/src/app.test.js | 9 +- .../log-viewer-webui/server/src/main.js | 22 +- .../src/routes/{examples.js => example.js} | 4 +- .../server/src/routes/query.js | 40 + .../log-viewer-webui/server/src/utils.js | 13 + .../package-template/src/etc/clp-config.yml | 2 +- lint-tasks.yml | 6 +- 18 files changed, 1653 insertions(+), 224 deletions(-) create mode 100644 components/log-viewer-webui/server/settings.json create mode 100644 components/log-viewer-webui/server/src/DbManager.js rename components/log-viewer-webui/server/src/routes/{examples.js => example.js} (75%) create mode 100644 components/log-viewer-webui/server/src/routes/query.js create mode 100644 components/log-viewer-webui/server/src/utils.js diff --git a/Taskfile.yml b/Taskfile.yml index e01bda896..e547dd68b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -10,6 +10,7 @@ vars: G_BUILD_DIR: "{{.ROOT_DIR}}/build" G_CORE_COMPONENT_BUILD_DIR: "{{.G_BUILD_DIR}}/core" G_LOG_VIEWER_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/log-viewer-webui" + G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" G_METEOR_BUILD_DIR: "{{.G_BUILD_DIR}}/meteor" G_NODEJS_14_BUILD_DIR: "{{.G_BUILD_DIR}}/nodejs-14" G_NODEJS_14_BIN_DIR: "{{.G_NODEJS_14_BUILD_DIR}}/bin" @@ -73,6 +74,7 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_PACKAGE_BUILD_DIR}}" sources: + - "{{.G_BUILD_DIR}}/log-viewer-webui-client.md5" - "{{.G_BUILD_DIR}}/package-venv.md5" - "{{.G_BUILD_DIR}}/webui.md5" - "{{.G_BUILD_DIR}}/webui-nodejs.md5" @@ -81,6 +83,10 @@ tasks: - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/package.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/package-lock.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/settings.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/*.js" - "{{.TASKFILE}}" - "/etc/os-release" - "components/clp-package-utils/dist/*.whl" @@ -94,7 +100,7 @@ tasks: - "clp-py-utils" - "init" - "job-orchestration" - - "log-viewer-webui" + - "log-viewer-webui-client" - "nodejs-14" - "package-venv" - task: "utils:validate-checksum" @@ -143,10 +149,15 @@ tasks: PATH="{{.G_NODEJS_14_BIN_DIR}}":$PATH npm install - >- rsync -a - "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/" - "{{.OUTPUT_DIR}}/var/www/log_viewer/" + "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/client" + "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/" - |- - cd "{{.OUTPUT_DIR}}/var/www/log_viewer/server" + cd components/log-viewer-webui/server/ + rsync -a \ + package.json package-lock.json settings.json src \ + "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/server/" + - |- + cd "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/server" PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm clean-install # This command must be last - task: "utils:compute-checksum" @@ -195,19 +206,17 @@ tasks: vars: COMPONENT: "{{.TASK}}" - log-viewer-webui: + log-viewer-webui-client: vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}" sources: - "{{.G_BUILD_DIR}}/log-viewer-modules.md5" - "{{.TASKFILE}}" + - "client/package.json" - "client/src/**/*.css" - "client/src/**/*.jsx" - - "client/src/package.json" - "client/src/webpack.config.js" - - "server/src/**/*.js" - - "server/src/**/package.json" dir: "components/log-viewer-webui" generates: ["{{.CHECKSUM_FILE}}"] deps: @@ -219,14 +228,10 @@ tasks: DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - - "rsync -a client {{.OUTPUT_DIR}}/" - - |- - cd "{{.OUTPUT_DIR}}/client" - PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build - - "mkdir {{.OUTPUT_DIR}}/server" - |- - cd server - rsync -a src package-lock.json package.json {{.OUTPUT_DIR}}/server/ + cd client + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build -- \ + --output-path "{{.OUTPUT_DIR}}/client" - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index d1edf7d5b..4dca481b0 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -501,11 +501,11 @@ def validate_webui_config( validate_port(f"{WEBUI_COMPONENT_NAME}.port", clp_config.webui.host, clp_config.webui.port) -def validate_log_viewer_config(clp_config: CLPConfig, logs_dir: pathlib.Path): - try: - validate_path_could_be_dir(logs_dir) - except ValueError as ex: - raise ValueError(f"{LOG_VIEWER_WEBUI_COMPONENT_NAME} logs directory is invalid: {ex}") +def validate_log_viewer_webui_config(clp_config: CLPConfig, settings_json_path: pathlib.Path): + if not settings_json_path.exists(): + raise ValueError( + f"{WEBUI_COMPONENT_NAME} {settings_json_path} is not a valid path to settings.json" + ) validate_port( f"{LOG_VIEWER_WEBUI_COMPONENT_NAME}.port", diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 4c072752e..655c1dae1 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -50,7 +50,7 @@ validate_and_load_queue_credentials_file, validate_and_load_redis_credentials_file, validate_db_config, - validate_log_viewer_config, + validate_log_viewer_webui_config, validate_queue_config, validate_redis_config, validate_reducer_config, @@ -668,13 +668,13 @@ def generic_start_worker( logger.info(f"Started {component_name}.") -def update_meteor_settings( +def update_settings_object( parent_key_prefix: str, settings: Dict[str, Any], updates: Dict[str, Any], ): """ - Recursively updates the given Meteor settings object with the values from `updates`. + Recursively updates the given settings object with the values from `updates`. :param parent_key_prefix: The prefix for keys at this level in the settings dictionary. :param settings: The settings to update. @@ -686,11 +686,25 @@ def update_meteor_settings( error_msg = f"{parent_key_prefix}{key} is not a valid configuration key for the webui." raise ValueError(error_msg) if isinstance(value, dict): - update_meteor_settings(f"{parent_key_prefix}{key}.", settings[key], value) + update_settings_object(f"{parent_key_prefix}{key}.", settings[key], value) else: settings[key] = updates[key] +def read_and_update_settings_json(settings_file_path: pathlib.Path, updates: Dict[str, Any]): + """ + Reads and updates a settings JSON file. + + :param settings_file_path: + :param updates: + """ + with open(settings_file_path, "r") as settings_json_file: + settings_object = json.loads(settings_json_file.read()) + update_settings_object("", settings_object, updates) + + return settings_object + + def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts): component_name = WEBUI_COMPONENT_NAME logger.info(f"Starting {component_name}...") @@ -710,8 +724,8 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts webui_logs_dir.mkdir(exist_ok=True, parents=True) container_webui_logs_dir = pathlib.Path("/") / "var" / "log" / component_name - with open(settings_json_path, "r") as settings_json_file: - meteor_settings = json.loads(settings_json_file.read()) + + # Read and update settings.json meteor_settings_updates = { "private": { "SqlDbHost": clp_config.database.host, @@ -726,7 +740,7 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts "ClpStorageEngine": clp_config.package.storage_engine, }, } - update_meteor_settings("", meteor_settings, meteor_settings_updates) + meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) # Start container # fmt: off @@ -769,7 +783,12 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts logger.info(f"Started {component_name}.") -def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts): +def start_log_viewer_webui( + instance_id: str, + clp_config: CLPConfig, + container_clp_config: CLPConfig, + mounts: CLPDockerMounts, +): component_name = LOG_VIEWER_WEBUI_COMPONENT_NAME logger.info(f"Starting {component_name}...") @@ -777,16 +796,30 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD if container_exists(container_name): return - log_viewer_webui_logs_dir = clp_config.logs_directory / component_name - container_log_viewer_dir = CONTAINER_CLP_HOME / "var" / "www" / "log_viewer" - node_path = str(container_log_viewer_dir / "server" / "node_modules") - - validate_log_viewer_config(clp_config, log_viewer_webui_logs_dir) - - # Create directories - log_viewer_webui_logs_dir.mkdir(exist_ok=True, parents=True) + container_log_viewer_webui_dir = CONTAINER_CLP_HOME / "var" / "www" / "log_viewer_webui" + node_path = str(container_log_viewer_webui_dir / "server" / "node_modules") + settings_json_path = ( + get_clp_home() / "var" / "www" / "log_viewer_webui" / "server" / "settings.json" + ) - container_log_viewer_webui_logs_dir = pathlib.Path("/") / "var" / "log" / component_name + validate_log_viewer_webui_config(clp_config, settings_json_path) + + # Read, update, and write back settings.json + settings_json_updates = { + "SqlDbHost": clp_config.database.host, + "SqlDbPort": clp_config.database.port, + "SqlDbName": clp_config.database.name, + "SqlDbQueryJobsTableName": QUERY_JOBS_TABLE_NAME, + "MongoDbHost": clp_config.results_cache.host, + "MongoDbPort": clp_config.results_cache.port, + "MongoDbName": clp_config.results_cache.db_name, + "MongoDbIrFilesCollectionName": clp_config.results_cache.ir_collection_name, + "ClientDir": str(container_log_viewer_webui_dir / "client"), + "IrFilesDir": str(container_clp_config.ir_output.directory), + } + settings_json = read_and_update_settings_json(settings_json_path, settings_json_updates) + with open(settings_json_path, "w") as settings_json_file: + settings_json_file.write(json.dumps(settings_json)) # Start container # fmt: off @@ -797,9 +830,10 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD "--name", container_name, "--log-driver", "local", "-e", f"NODE_PATH={node_path}", - "-e", f"CLIENT_DIR={container_log_viewer_dir}/client/dist", - "-e", f"PORT={clp_config.log_viewer_webui.port}", "-e", f"HOST={clp_config.log_viewer_webui.host}", + "-e", f"PORT={clp_config.log_viewer_webui.port}", + "-e", f"CLP_DB_USER={clp_config.database.username}", + "-e", f"CLP_DB_PASS={clp_config.database.password}", "-e", f"NODE_ENV=production", "-u", f"{os.getuid()}:{os.getgid()}", ] @@ -807,9 +841,6 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD necessary_mounts = [ mounts.clp_home, mounts.ir_output_dir, - DockerMount( - DockerMountType.BIND, log_viewer_webui_logs_dir, container_log_viewer_webui_logs_dir - ), ] for mount in necessary_mounts: if mount: @@ -819,7 +850,7 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD node_cmd = [ str(CONTAINER_CLP_HOME / "bin" / "node-22"), - str(container_log_viewer_dir / "server" / "src" / "main.js"), + str(container_log_viewer_webui_dir / "server" / "src" / "main.js"), ] cmd = container_cmd + node_cmd subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) @@ -1046,7 +1077,7 @@ def main(argv): if target in (ALL_TARGET_NAME, WEBUI_COMPONENT_NAME): start_webui(instance_id, clp_config, mounts) if target in (ALL_TARGET_NAME, LOG_VIEWER_WEBUI_COMPONENT_NAME): - start_log_viewer_webui(instance_id, clp_config, mounts) + start_log_viewer_webui(instance_id, clp_config, container_clp_config, mounts) except Exception as ex: if type(ex) == ValueError: diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index 9485b43c2..f5a813057 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -393,7 +393,6 @@ def validate_logging_level(cls, field): class LogViewerWebUi(BaseModel): host: str = "localhost" port: int = 3000 - logging_level: str = "INFO" @validator("host") def validate_host(cls, field): diff --git a/components/log-viewer-webui/server/.env b/components/log-viewer-webui/server/.env index 699f2cb90..b66dc997b 100644 --- a/components/log-viewer-webui/server/.env +++ b/components/log-viewer-webui/server/.env @@ -1,3 +1,8 @@ CLIENT_DIR=../client/dist +IR_DATA_DIR=../../../build/clp-package/var/data/ir +LOG_VIEWER_DIR=../yscope-log-viewer/dist + HOST=localhost PORT=3000 +CLP_DB_USER=clp-user +CLP_DB_PASS= diff --git a/components/log-viewer-webui/server/.gitignore b/components/log-viewer-webui/server/.gitignore index d0e829eda..e19dcc6a4 100644 --- a/components/log-viewer-webui/server/.gitignore +++ b/components/log-viewer-webui/server/.gitignore @@ -1,2 +1,5 @@ + # Local development +.env.local + # Testing /.tap diff --git a/components/log-viewer-webui/server/package-lock.json b/components/log-viewer-webui/server/package-lock.json index 1066e05ef..b5ad7d428 100644 --- a/components/log-viewer-webui/server/package-lock.json +++ b/components/log-viewer-webui/server/package-lock.json @@ -9,13 +9,19 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "@fastify/mongodb": "^8.0.0", + "@fastify/mysql": "^4.3.0", "@fastify/static": "^7.0.4", + "@msgpack/msgpack": "^3.0.0-beta2", "dotenv": "^16.4.5", "fastify": "^4.28.0", + "fastify-plugin": "^4.5.1", "http-status-codes": "^2.3.0", "pino-pretty": "^11.2.1" }, "devDependencies": { + "@babel/eslint-parser": "^7.24.8", + "@babel/plugin-syntax-import-attributes": "^7.24.7", "eslint-config-yscope": "latest", "nodemon": "^3.1.3", "tap": "^19.2.5" @@ -58,6 +64,554 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.8.tgz", + "integrity": "sha512-nYAikI4XTGokU2QX7Jx+v4rxZKhKivaQaREZjuW3mrJrbdWJ5yUfohnoUULge+zEEaKjPYNxhoRgUKktjXtbwA==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", + "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "dev": true, + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@base2/pretty-print-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", @@ -83,37 +637,20 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", - "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", + "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", "dev": true, "peer": true, "dependencies": { - "@types/eslint": "^8.56.5", - "@types/estree": "^1.0.5", - "@typescript-eslint/types": "^7.2.0", "comment-parser": "1.4.1", - "esquery": "^1.5.0", + "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { "node": ">=16" } }, - "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", - "dev": true, - "peer": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -217,20 +754,25 @@ } }, "node_modules/@fastify/ajv-compiler/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv/node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -257,6 +799,24 @@ "fast-deep-equal": "^3.1.3" } }, + "node_modules/@fastify/mongodb": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@fastify/mongodb/-/mongodb-8.0.0.tgz", + "integrity": "sha512-IDw/wWpdc53+Y5sPpMg+ek71HOIVuz8NoD2GlfIOcvGE/lYdrZvnFQxqJcaZtlwPZ7YflDDkIu5aNkCPWdZQ0Q==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mongodb": "^6.0.0" + } + }, + "node_modules/@fastify/mysql": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/mysql/-/mysql-4.3.0.tgz", + "integrity": "sha512-eVx5/PyMmoBWp3hTaqdvXiZdo8YnKsAx3k/8AEXgI/MjUbgcn8YrSdy8eHSpCL3YZtBhD/2vLpOXFFciyqlWjQ==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mysql2": "^3.9.7" + } + }, "node_modules/@fastify/send": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", @@ -443,6 +1003,32 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -452,10 +1038,20 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -476,6 +1072,53 @@ "node": ">=8" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", + "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "3.0.0-beta2", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz", + "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -530,6 +1173,12 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/@npmcli/fs": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", @@ -543,12 +1192,13 @@ } }, "node_modules/@npmcli/git": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", - "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", + "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", "dev": true, "dependencies": { "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", @@ -570,6 +1220,12 @@ "node": ">=16" } }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/@npmcli/git/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -1065,9 +1721,9 @@ } }, "node_modules/@tapjs/fixture/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1076,7 +1732,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1270,9 +1926,9 @@ } }, "node_modules/@tapjs/run/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1281,7 +1937,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1404,9 +2060,9 @@ } }, "node_modules/@tapjs/test/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1415,7 +2071,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1577,6 +2233,19 @@ "dev": true, "peer": true }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", @@ -1816,20 +2485,25 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats/node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -2152,6 +2826,14 @@ "fastq": "^1.17.1" } }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", + "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2208,6 +2890,47 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -2257,9 +2980,9 @@ } }, "node_modules/cacache": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", - "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", @@ -2279,6 +3002,12 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2309,6 +3038,27 @@ "node": ">=6" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2747,6 +3497,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2806,6 +3564,13 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/electron-to-chromium": { + "version": "1.4.828", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.828.tgz", + "integrity": "sha512-QOIJiWpQJDHAVO4P58pwb133Cwee0nbvy/MV1CwzZVGpkH1RX33N3vsaWRCpR6bF63AAq366neZrRTu7Qlsbbw==", + "dev": true, + "peer": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -3275,19 +4040,19 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.5.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.2.tgz", - "integrity": "sha512-VXBJFviQz30rynlOEQ+dNWLmeopjoAgutUVrWOZwm6Ki4EVDm4XkyIqAV/Zhf7FcDr0AG0aGmRn5FxxCtAF0tA==", + "version": "48.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.7.0.tgz", + "integrity": "sha512-5oiVf7Y+ZxGYQTlLq81X72n+S+hjvS/u0upAdbpPEeaIZILK3MKN8lm/6QqKioBjm/qZ0B5XpMQUtc2fUkqXAg==", "dev": true, "peer": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.43.1", + "@es-joy/jsdoccomment": "~0.46.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "parse-imports": "^2.1.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", "semver": "^7.6.2", "spdx-expression-parse": "^4.0.0", "synckit": "^0.9.0" @@ -3317,9 +4082,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", - "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", + "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", "dev": true, "peer": true, "dependencies": { @@ -3331,16 +4096,17 @@ "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.hasown": "^1.1.4", "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" @@ -3520,9 +4286,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "peer": true, "dependencies": { @@ -3537,7 +4303,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "peer": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3550,7 +4315,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "peer": true, "engines": { "node": ">=4.0" } @@ -3668,14 +4432,14 @@ } }, "node_modules/fast-json-stringify/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3698,6 +4462,11 @@ } } }, + "node_modules/fast-json-stringify/node_modules/ajv/node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -3988,6 +4757,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -4036,9 +4823,9 @@ } }, "node_modules/glob": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", - "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -4050,9 +4837,6 @@ "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -4268,6 +5052,12 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4330,8 +5120,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -4440,6 +5228,15 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/ink": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/ink/-/ink-4.4.1.tgz", @@ -4538,7 +5335,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, + "devOptional": true, "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -4852,6 +5649,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5061,15 +5863,12 @@ } }, "node_modules/jackspeak": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.1.tgz", - "integrity": "sha512-U23pQPDnmYybVkYjObcuYMk43VRlMLLqLI+RdZy8s8WV8WsxO9SnqSroKaluuvcNOdCAlauKszDwd+umbot5Mg==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -5108,7 +5907,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true + "devOptional": true }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", @@ -5120,6 +5919,19 @@ "node": ">=12.0.0" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5258,6 +6070,11 @@ "dev": true, "peer": true }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5271,11 +6088,11 @@ } }, "node_modules/lru-cache": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.1.tgz", - "integrity": "sha512-9/8QXrtbGeMB6LxwQd4x1tIMnsmUxMvIH/qWGsccz6bt9Uln3S+sgAaqfQNhbGA8ufzs2fHuP/yqapGgP9Hh2g==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", "engines": { - "node": ">=18" + "node": ">=16.14" } }, "node_modules/make-dir": { @@ -5322,6 +6139,11 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5573,12 +6395,104 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mysql2": { + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.3.tgz", + "integrity": "sha512-k43gmH9i79rZD4hGPdj7pDuT0UBiFjs4UzXEy1cJrV0QqcSABomoLwvejqdbcXN+Vd7gi999CVM6o9vCPKq29g==", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5596,9 +6510,9 @@ } }, "node_modules/node-gyp": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", - "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", + "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", "dev": true, "dependencies": { "env-paths": "^2.2.0", @@ -5607,9 +6521,9 @@ "graceful-fs": "^4.2.6", "make-fetch-happen": "^13.0.0", "nopt": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.1.0", "semver": "^7.3.5", - "tar": "^6.1.2", + "tar": "^6.2.1", "which": "^4.0.0" }, "bin": { @@ -5628,15 +6542,6 @@ "node": ">=16" } }, - "node_modules/node-gyp/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/node-gyp/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -5652,6 +6557,13 @@ "node": "^16.13.0 || >=18.0.0" } }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "peer": true + }, "node_modules/nodemon": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", @@ -5822,9 +6734,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", - "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, "dependencies": { "npm-install-checks": "^6.0.0", @@ -5956,24 +6868,6 @@ "node": ">= 0.4" } }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "peer": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", @@ -6216,6 +7110,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6226,6 +7125,13 @@ "node": ">=8" } }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "peer": true + }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", @@ -6240,9 +7146,9 @@ } }, "node_modules/pino": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", - "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.3.1.tgz", + "integrity": "sha512-afSfrq/hUiW/MFmQcLEwV9Zh8Ry6MrMTOyBU53o/fc0gEl+1OZ/Fks/xQCM2nOC0C/OfDtQMnT2d8c3kpcfSzA==", "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", @@ -6736,9 +7642,9 @@ } }, "node_modules/resolve-import": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", - "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.6.tgz", + "integrity": "sha512-CIw9e64QcKcCFUj9+KxUCJPy8hYofv6eVfo3U9wdhCm2E4IjvFnZ6G4/yIC4yP3f11+h6uU5b3LdS7O64LgqrA==", "dev": true, "dependencies": { "glob": "^10.3.3", @@ -6966,9 +7872,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/scheduler": { "version": "0.23.2", @@ -6995,6 +7899,11 @@ "node": ">=10" } }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, "node_modules/set-cookie-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", @@ -7178,7 +8087,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -7188,7 +8097,7 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, + "devOptional": true, "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -7220,6 +8129,14 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -7275,7 +8192,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true + "devOptional": true + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } }, "node_modules/ssri": { "version": "10.0.6", @@ -7455,6 +8380,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -7598,9 +8534,9 @@ } }, "node_modules/sync-content/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -7609,16 +8545,16 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/synckit": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", - "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "peer": true, "dependencies": { @@ -7845,6 +8781,16 @@ "real-require": "^0.2.0" } }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7882,6 +8828,17 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/trivial-deferred": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-2.0.0.tgz", @@ -7918,9 +8875,9 @@ } }, "node_modules/tshy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.17.0.tgz", - "integrity": "sha512-95BrHQTZCrJ3LnoGQoDCv7PtyNKyIIY9A9FPgY04IpsmV0URmlI8OWjMkQWRONUAJqJeJCij9p8REXLuv+7MXg==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.18.0.tgz", + "integrity": "sha512-FQudIujBazHRu7CVPHKQE9/Xq1Wc7lezxD/FCnTXx2PTcnoSN32DVpb/ZXvzV2NJBTDB3XKjqX8Cdm+2UK1DlQ==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -7982,9 +8939,9 @@ } }, "node_modules/tshy/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -7993,7 +8950,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -8188,10 +9145,43 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -8270,6 +9260,26 @@ "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", "dev": true }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/components/log-viewer-webui/server/package.json b/components/log-viewer-webui/server/package.json index e7e52d521..f952b6c86 100644 --- a/components/log-viewer-webui/server/package.json +++ b/components/log-viewer-webui/server/package.json @@ -8,19 +8,25 @@ "lint:fix": "npx eslint --fix --no-eslintrc --config package.json src", "prod": "NODE_ENV=production node src/main.js", "start": "NODE_ENV=development nodemon src/main.js", - "test": "tap" + "test": "NODE_ENV=test tap" }, "author": "YScope Inc. ", "license": "Apache-2.0", "type": "module", "dependencies": { + "@fastify/mongodb": "^8.0.0", + "@fastify/mysql": "^4.3.0", "@fastify/static": "^7.0.4", + "fastify-plugin": "^4.5.1", + "@msgpack/msgpack": "^3.0.0-beta2", "dotenv": "^16.4.5", "fastify": "^4.28.0", "http-status-codes": "^2.3.0", "pino-pretty": "^11.2.1" }, "devDependencies": { + "@babel/eslint-parser": "^7.24.8", + "@babel/plugin-syntax-import-attributes": "^7.24.7", "eslint-config-yscope": "latest", "nodemon": "^3.1.3", "tap": "^19.2.5" @@ -28,6 +34,15 @@ "eslintConfig": { "extends": [ "yscope/common" - ] + ], + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false, + "babelOptions": { + "plugins": [ + "@babel/plugin-syntax-import-attributes" + ] + } + } } } diff --git a/components/log-viewer-webui/server/settings.json b/components/log-viewer-webui/server/settings.json new file mode 100644 index 000000000..76183a879 --- /dev/null +++ b/components/log-viewer-webui/server/settings.json @@ -0,0 +1,13 @@ +{ + "SqlDbHost": "localhost", + "SqlDbPort": 3306, + "SqlDbName": "clp-db", + "SqlDbQueryJobsTableName": "query_jobs", + "MongoDbHost": "localhost", + "MongoDbPort": 27017, + "MongoDbName": "clp-query-results", + "MongoDbIrFilesCollectionName": "ir-files", + + "ClientDir": "../client/dist", + "IrFilesDir": "../../../build/clp-package/var/data/ir" +} diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js new file mode 100644 index 000000000..ad71518a5 --- /dev/null +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -0,0 +1,241 @@ +import fastifyPlugin from "fastify-plugin"; + +import fastifyMongo from "@fastify/mongodb"; +import fastifyMysql from "@fastify/mysql"; +import msgpack from "@msgpack/msgpack"; + +import {sleep} from "./utils.js"; + + +/** + * Interval in milliseconds for polling the completion status of a job. + */ +const JOB_COMPLETION_STATUS_POLL_INTERVAL_MILLIS = 0.5; + +/** + * Enum of the `query_jobs` table's column names. + * + * @enum {string} + */ +const QUERY_JOBS_TABLE_COLUMN_NAMES = Object.freeze({ + ID: "id", + STATUS: "status", + TYPE: "type", + JOB_CONFIG: "job_config", +}); + +/* eslint-disable sort-keys */ +let enumQueryJobStatus; +/** + * Enum of job statuses, matching the `QueryJobStatus` class in + * `job_orchestration.query_scheduler.constants`. + * + * @enum {number} + */ +const QUERY_JOB_STATUS = Object.freeze({ + PENDING: (enumQueryJobStatus = 0), + RUNNING: ++enumQueryJobStatus, + SUCCEEDED: ++enumQueryJobStatus, + FAILED: ++enumQueryJobStatus, + CANCELLING: ++enumQueryJobStatus, + CANCELLED: ++enumQueryJobStatus, +}); +/* eslint-enable sort-keys */ + +/** + * List of states that indicate the job is either pending or in progress. + */ +const QUERY_JOB_STATUS_WAITING_STATES = Object.freeze([ + QUERY_JOB_STATUS.PENDING, + QUERY_JOB_STATUS.RUNNING, + QUERY_JOB_STATUS.CANCELLING, +]); + +/* eslint-disable sort-keys */ +let enumQueryType; +/** + * Enum of job types, matching the `QueryJobType` class in + * `job_orchestration.query_scheduler.constants`. + * + * @enum {number} + */ +const QUERY_JOB_TYPE = Object.freeze({ + SEARCH_OR_AGGREGATION: (enumQueryType = 0), + EXTRACT_IR: ++enumQueryType, +}); +/* eslint-enable sort-keys */ + +/** + * Class to manage connections to the jobs database (MySQL) and results cache (MongoDB). + */ +class DbManager { + /** + * @type {import("fastify").FastifyInstance | + * {mysql: import("@fastify/mysql").MySQLPromisePool} | + * {mongo: import("@fastify/mongodb").FastifyMongoObject}} + */ + #fastify; + + /** + * @type {import("@fastify/mysql").PromisePool} + */ + #mysqlConnectionPool; + + /** + * @type {import("mongodb").Collection} + */ + #irFilesCollection; + + #queryJobsTableName; + + /** + * @param {import("fastify").FastifyInstance} app + * @param {object} dbConfig + * @param {object} dbConfig.mysqlConfig + * @param {object} dbConfig.mongoConfig + */ + constructor (app, dbConfig) { + this.#fastify = app; + this.#initMySql(dbConfig.mysqlConfig); + this.#initMongo(dbConfig.mongoConfig); + } + + /** + * Submits an IR extraction job to the scheduler and waits for it to finish. + * + * @param {object} jobConfig + * @return {Promise} The ID of the job or null if an error occurred. + */ + async submitAndWaitForExtractIrJob (jobConfig) { + let jobId; + try { + const [result] = await this.#mysqlConnectionPool.query( + `INSERT INTO ${this.#queryJobsTableName} (job_config, type) + VALUES (?, ?)`, + [ + Buffer.from(msgpack.encode(jobConfig)), + QUERY_JOB_TYPE.EXTRACT_IR, + ] + ); + + ({insertId: jobId} = result); + await this.#awaitJobCompletion(jobId); + } catch (e) { + this.#fastify.log.error(e); + + return null; + } + + return jobId; + } + + /** + * Gets the metadata for an IR file extracted from part of an original file, where the original + * file has the given ID and the extracted part contains the given message index. + * + * @param {string} origFileId + * @param {number} msgIdx + * @return {Promise} A promise that resolves to the extracted IR file's metadata. + */ + async getExtractedIrFileMetadata (origFileId, msgIdx) { + return await this.#irFilesCollection.findOne({ + orig_file_id: origFileId, + begin_msg_ix: {$lte: msgIdx}, + end_msg_ix: {$gt: msgIdx}, + }); + } + + /** + * Initializes the MySQL plugin. + * + * @param {object} config + * @param {string} config.user + * @param {string} config.password + * @param {string} config.host + * @param {number} config.port + * @param {string} config.database + * @param {string} config.queryJobsTableName + */ + #initMySql (config) { + this.#fastify.register(fastifyMysql, { + promise: true, + connectionString: `mysql://${config.user}:${config.password}@${config.host}:` + + `${config.port}/${config.database}`, + }).after(async (err) => { + if (err) { + throw err; + } + this.#mysqlConnectionPool = this.#fastify.mysql.pool; + this.#queryJobsTableName = config.queryJobsTableName; + }); + } + + /** + * Initializes the MongoDB plugin. + * + * @param {object} config + * @param {string} config.host + * @param {number} config.port + * @param {string} config.database + * @param {string} config.irFilesCollectionName + */ + #initMongo (config) { + this.#fastify.register(fastifyMongo, { + forceClose: true, + url: `mongodb://${config.host}:${config.port}/${config.database}`, + }).after((err) => { + if (err) { + throw err; + } + this.#irFilesCollection = + this.#fastify.mongo.db.collection(config.irFilesCollectionName); + }); + } + + /** + * Waits for the job with the given ID to finish. + * + * @param {number} jobId + * @throws {Error} If there's an error querying the job's status, the job is not found in the + * database, the job was cancelled, or it exited with an unexpected status. + */ + async #awaitJobCompletion (jobId) { + while (true) { + let rows; + try { + const [queryRows] = await this.#mysqlConnectionPool.query( + ` + SELECT ${QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS} + FROM ${this.#queryJobsTableName} + WHERE ${QUERY_JOBS_TABLE_COLUMN_NAMES.ID} = ? + `, + jobId, + ); + + rows = queryRows; + } catch (e) { + throw new Error(`Failed to query status for job ${jobId} - ${e}`); + } + if (0 === rows.length) { + throw new Error(`Job ${jobId} not found in database.`); + } + const status = rows[0][QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS]; + + if (false === QUERY_JOB_STATUS_WAITING_STATES.includes(status)) { + if (QUERY_JOB_STATUS.CANCELLED === status) { + throw new Error(`Job ${jobId} was cancelled.`); + } else if (QUERY_JOB_STATUS.SUCCEEDED !== status) { + throw new Error(`Job ${jobId} exited with unexpected status=${status}: ` + + `${Object.keys(QUERY_JOB_STATUS)[status]}.`); + } + break; + } + + await sleep(JOB_COMPLETION_STATUS_POLL_INTERVAL_MILLIS); + } + } +} + +export default fastifyPlugin(async (app, options) => { + await app.decorate("dbManager", new DbManager(app, options)); +}); diff --git a/components/log-viewer-webui/server/src/app.js b/components/log-viewer-webui/server/src/app.js index d67b7136a..28c7fdfe5 100644 --- a/components/log-viewer-webui/server/src/app.js +++ b/components/log-viewer-webui/server/src/app.js @@ -1,36 +1,79 @@ import fastify from "fastify"; import * as path from "node:path"; import process from "node:process"; +import {fileURLToPath} from "node:url"; import {fastifyStatic} from "@fastify/static"; -import exampleRoutes from "./routes/examples.js"; +import settings from "../settings.json" with {type: "json"}; +import DbManager from "./DbManager.js"; +import exampleRoutes from "./routes/example.js"; +import queryRoutes from "./routes/query.js"; /** * Creates the Fastify app with the given options. * - * @param {string} clientDir Absolute path to the client directory to serve when in running in a - * production environment. - * @param {import("fastify").FastifyServerOptions} fastifyOptions + * @param {object} props + * @param {import("fastify").FastifyServerOptions} props.fastifyOptions + * @param {string} props.sqlDbUser + * @param {string} props.sqlDbPass * @return {Promise} */ -const app = async (clientDir, fastifyOptions = {}) => { +const app = async ({ + fastifyOptions, + sqlDbUser, + sqlDbPass, +}) => { const server = fastify(fastifyOptions); + const filename = fileURLToPath(import.meta.url); + const dirname = path.dirname(filename); + const parentDirname = path.resolve(dirname, ".."); + + if ("test" !== process.env.NODE_ENV) { + let irFilesDir = settings.IrFilesDir; + if (false === path.isAbsolute(irFilesDir)) { + irFilesDir = path.resolve(parentDirname, irFilesDir); + } + await server.register(fastifyStatic, { + prefix: "/ir", + root: irFilesDir, + }); + + await server.register(DbManager, { + mysqlConfig: { + database: settings.SqlDbName, + host: settings.SqlDbHost, + password: sqlDbPass, + port: settings.SqlDbPort, + queryJobsTableName: settings.SqlDbQueryJobsTableName, + user: sqlDbUser, + }, + mongoConfig: { + database: settings.MongoDbName, + host: settings.MongoDbHost, + irFilesCollectionName: settings.MongoDbIrFilesCollectionName, + port: settings.MongoDbPort, + }, + }); + } if ("production" === process.env.NODE_ENV) { // In the development environment, we expect the client to use a separate webserver that // supports live reloading. - if (false === path.isAbsolute(clientDir)) { + if (false === path.isAbsolute(settings.ClientDir)) { throw new Error("`clientDir` must be an absolute path."); } await server.register(fastifyStatic, { prefix: "/", - root: clientDir, + root: settings.ClientDir, + decorateReply: false, }); } + await server.register(exampleRoutes); + await server.register(queryRoutes); return server; }; diff --git a/components/log-viewer-webui/server/src/app.test.js b/components/log-viewer-webui/server/src/app.test.js index 1215c795f..3a19208f7 100644 --- a/components/log-viewer-webui/server/src/app.test.js +++ b/components/log-viewer-webui/server/src/app.test.js @@ -5,12 +5,12 @@ import app from "./app.js"; test("Tests the example routes", async (t) => { - const server = await app(); + const server = await app({}); t.teardown(() => server.close()); let resp = await server.inject({ method: "GET", - url: "/examples/get/Alice", + url: "/example/get/Alice", }); t.equal(resp.statusCode, httpStatusCodes.OK); @@ -18,9 +18,12 @@ test("Tests the example routes", async (t) => { resp = await server.inject({ method: "POST", - url: "/examples/post", + url: "/example/post", payload: {name: "Bob"}, }); t.equal(resp.statusCode, httpStatusCodes.OK); t.match(JSON.parse(resp.body), {msg: String}); }); + +// eslint-disable-next-line no-warning-comments +// TODO: Add tests for `query` routes. diff --git a/components/log-viewer-webui/server/src/main.js b/components/log-viewer-webui/server/src/main.js index f1507d3ef..c3b7ef5cf 100644 --- a/components/log-viewer-webui/server/src/main.js +++ b/components/log-viewer-webui/server/src/main.js @@ -1,5 +1,4 @@ import dotenv from "dotenv"; -import * as path from "node:path"; import process from "node:process"; import app from "./app.js"; @@ -8,20 +7,25 @@ import app from "./app.js"; /** * Parses environment variables into config values for the application. * - * @return {{CLIENT_DIR: string, HOST: string, PORT: string}} + * @return {{CLP_DB_USER: string, CLP_DB_PASS: string, HOST: string, PORT: string}} * @throws {Error} if any required environment variable is undefined. */ const parseEnvVars = () => { dotenv.config({ - path: ".env", + path: [ + ".env.local", + ".env", + ], }); + /* eslint-disable sort-keys */ const { - CLIENT_DIR, HOST, PORT, + CLP_DB_USER, CLP_DB_PASS, HOST, PORT, } = process.env; const envVars = { - CLIENT_DIR, HOST, PORT, + CLP_DB_USER, CLP_DB_PASS, HOST, PORT, }; + /* eslint-enable sort-keys */ // Check for mandatory environment variables for (const [key, value] of Object.entries(envVars)) { @@ -48,8 +52,12 @@ const main = async () => { }; const envVars = parseEnvVars(); - const server = await app(path.resolve(envVars.CLIENT_DIR), { - logger: envToLogger[process.env.NODE_ENV] ?? true, + const server = await app({ + fastifyOptions: { + logger: envToLogger[process.env.NODE_ENV] ?? true, + }, + sqlDbPass: envVars.CLP_DB_PASS, + sqlDbUser: envVars.CLP_DB_USER, }); try { diff --git a/components/log-viewer-webui/server/src/routes/examples.js b/components/log-viewer-webui/server/src/routes/example.js similarity index 75% rename from components/log-viewer-webui/server/src/routes/examples.js rename to components/log-viewer-webui/server/src/routes/example.js index 8074f4a29..fb4aa31c7 100644 --- a/components/log-viewer-webui/server/src/routes/examples.js +++ b/components/log-viewer-webui/server/src/routes/example.js @@ -6,11 +6,11 @@ * @return {Promise} */ const routes = async (fastify, options) => { - fastify.get("/examples/get/:name", async (req, resp) => { + fastify.get("/example/get/:name", async (req, resp) => { return {msg: `Hello, ${req.params.name}!`}; }); - fastify.post("/examples/post", async (req, resp) => { + fastify.post("/example/post", async (req, resp) => { return {msg: `Goodbye, ${req.body.name}!`}; }); }; diff --git a/components/log-viewer-webui/server/src/routes/query.js b/components/log-viewer-webui/server/src/routes/query.js new file mode 100644 index 000000000..2f790ebc3 --- /dev/null +++ b/components/log-viewer-webui/server/src/routes/query.js @@ -0,0 +1,40 @@ +/** + * Creates query routes. + * + * @param {import("fastify").FastifyInstance | {dbManager: DbManager}} fastify + * @param {import("fastify").FastifyPluginOptions} options + * @return {Promise} + */ +const routes = async (fastify, options) => { + fastify.post("/query/extract-ir", async (req, resp) => { + const {orig_file_id: origFileId, msg_ix: msgIdx} = req.body; + const sanitizedMsgIdx = Number(msgIdx); + + let irMetadata = + await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + + if (null === irMetadata) { + const extractResult = await fastify.dbManager.submitAndWaitForExtractIrJob({ + file_split_id: null, + msg_ix: sanitizedMsgIdx, + orig_file_id: origFileId, + // eslint-disable-next-line no-magic-numbers + target_uncompressed_size: 128 * 1024 * 1024, + }); + + if (null === extractResult) { + const err = new Error("Unable to extract IR for file with " + + `orig_file_id=${origFileId} at msg_ix=${sanitizedMsgIdx}`); + + err.statusCode = 400; + throw err; + } + irMetadata = + await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + } + + return irMetadata; + }); +}; + +export default routes; diff --git a/components/log-viewer-webui/server/src/utils.js b/components/log-viewer-webui/server/src/utils.js new file mode 100644 index 000000000..580ea76f8 --- /dev/null +++ b/components/log-viewer-webui/server/src/utils.js @@ -0,0 +1,13 @@ +const MILLIS_PER_SECOND = 1000; + +/** + * Creates a promise that resolves after a specified number of seconds. + * + * @param {number} seconds Number of seconds to wait before resolving the promise. + * @return {Promise} A promise that resolves after the specified delay. + */ +const sleep = (seconds) => new Promise((resolve) => { + setTimeout(resolve, seconds * MILLIS_PER_SECOND); +}); + +export {sleep}; diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index ce626afa3..cb66f40cd 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -60,7 +60,7 @@ # port: 4000 # logging_level: "INFO" # -#log_viewer_webui +#log_viewer_webui: # host: "localhost" # port: 3000 # diff --git a/lint-tasks.yml b/lint-tasks.yml index a7de6e49e..9f21cd8ed 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -2,7 +2,6 @@ version: "3" vars: G_LINT_VENV_DIR: "{{.G_BUILD_DIR}}/lint-venv" - G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" G_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/webui" tasks: @@ -51,12 +50,13 @@ tasks: - "{{.G_BUILD_DIR}}/lint#linter-node-modules.md5" - "{{.G_BUILD_DIR}}/log-viewer-webui-node-modules.md5" - "{{.G_BUILD_DIR}}/webui-node-modules.md5" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/package.json" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/**/*.css" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/**/*.jsx" - - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/package.json" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/webpack.config.js" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/package.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/settings.json" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/*.js" - - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/package.json" - "{{.G_WEBUI_SRC_DIR}}/client/**/*.js" - "{{.G_WEBUI_SRC_DIR}}/client/**/*.jsx" - "{{.G_WEBUI_SRC_DIR}}/imports/**/*.js" From 0becae0b0c555aafe004abae506137c666dc0b04 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:53:52 -0400 Subject: [PATCH 034/114] clp-package: Prevent query scheduler from scheduling two IR extraction jobs targeting the same file split. (#483) --- .../clp_package_utils/scripts/start_clp.py | 50 +++++++++++ .../create-results-cache-indices.py | 42 ++++++++++ components/core/src/clp/clo/clo.cpp | 4 + components/core/src/clp/clo/constants.hpp | 1 + .../scheduler/query/query_scheduler.py | 84 ++++++++++++++++++- .../scheduler/scheduler_data.py | 1 + 6 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 components/clp-py-utils/clp_py_utils/create-results-cache-indices.py diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 655c1dae1..74bb5f018 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -234,6 +234,54 @@ def create_db_tables( logger.info(f"Created {component_name} tables.") +def create_results_cache_indices( + instance_id: str, + clp_config: CLPConfig, + container_clp_config: CLPConfig, + mounts: CLPDockerMounts, +): + component_name = RESULTS_CACHE_COMPONENT_NAME + logger.info(f"Creating {component_name} indices...") + + container_name = f"clp-{component_name}-indices-creator-{instance_id}" + + clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" + # fmt: off + container_start_cmd = [ + "docker", "run", + "-i", + "--network", "host", + "--rm", + "--name", container_name, + "--log-driver", "local", + "-e", f"PYTHONPATH={clp_site_packages_dir}", + "-u", f"{os.getuid()}:{os.getgid()}", + ] + # fmt: on + necessary_mounts = [mounts.clp_home, mounts.data_dir, mounts.logs_dir] + for mount in necessary_mounts: + if mount: + container_start_cmd.append("--mount") + container_start_cmd.append(str(mount)) + container_start_cmd.append(clp_config.execution_container) + + clp_py_utils_dir = clp_site_packages_dir / "clp_py_utils" + # fmt: off + create_tables_cmd = [ + "python3", + str(clp_py_utils_dir / "create-results-cache-indices.py"), + "--uri", container_clp_config.results_cache.get_uri(), + "--ir-collection", container_clp_config.results_cache.ir_collection_name, + ] + # fmt: on + + cmd = container_start_cmd + create_tables_cmd + logger.debug(" ".join(cmd)) + subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) + + logger.info(f"Created {component_name} indices.") + + def start_queue(instance_id: str, clp_config: CLPConfig): component_name = QUEUE_COMPONENT_NAME logger.info(f"Starting {component_name}...") @@ -1058,6 +1106,8 @@ def main(argv): start_redis(instance_id, clp_config, conf_dir) if target in (ALL_TARGET_NAME, RESULTS_CACHE_COMPONENT_NAME): start_results_cache(instance_id, clp_config, conf_dir) + if target in (ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, RESULTS_CACHE_COMPONENT_NAME): + create_results_cache_indices(instance_id, clp_config, container_clp_config, mounts) if target in ( ALL_TARGET_NAME, CONTROLLER_TARGET_NAME, diff --git a/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py b/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py new file mode 100644 index 000000000..dafbd3bde --- /dev/null +++ b/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py @@ -0,0 +1,42 @@ +import argparse +import logging +import sys + +from pymongo import IndexModel, MongoClient + +# Setup logging +# Create logger +logger = logging.getLogger(__file__) +logger.setLevel(logging.INFO) +# Setup console logging +logging_console_handler = logging.StreamHandler() +logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") +logging_console_handler.setFormatter(logging_formatter) +logger.addHandler(logging_console_handler) + + +def main(argv): + args_parser = argparse.ArgumentParser(description="Creates results cache indices for CLP.") + args_parser.add_argument("--uri", required=True, help="URI of the results cache.") + args_parser.add_argument("--ir-collection", required=True, help="Collection for IR metadata.") + parsed_args = args_parser.parse_args(argv[1:]) + + results_cache_uri = parsed_args.uri + ir_collection_name = parsed_args.ir_collection + + try: + with MongoClient(results_cache_uri) as results_cache_client: + ir_collection = results_cache_client.get_default_database()[ir_collection_name] + + file_split_id_index = IndexModel(["file_split_id"]) + orig_file_id_index = IndexModel(["orig_file_id", "begin_msg_ix", "end_msg_ix"]) + ir_collection.create_indexes([file_split_id_index, orig_file_id_index]) + except Exception: + logger.exception("Failed to create clp results cache indices.") + return -1 + + return 0 + + +if "__main__" == __name__: + sys.exit(main(sys.argv)) diff --git a/components/core/src/clp/clo/clo.cpp b/components/core/src/clp/clo/clo.cpp index 4216a2c6e..f29df0306 100644 --- a/components/core/src/clp/clo/clo.cpp +++ b/components/core/src/clp/clo/clo.cpp @@ -198,6 +198,10 @@ bool extract_ir(CommandLineArguments const& command_line_args) { clp::clo::cResultsCacheKeys::OrigFileId, orig_file_id ), + bsoncxx::builder::basic::kvp( + clp::clo::cResultsCacheKeys::IrOutput::FileSplitId, + file_split_id + ), bsoncxx::builder::basic::kvp( clp::clo::cResultsCacheKeys::IrOutput::BeginMsgIx, static_cast(begin_message_ix) diff --git a/components/core/src/clp/clo/constants.hpp b/components/core/src/clp/clo/constants.hpp index d2eb32db4..86f7313f2 100644 --- a/components/core/src/clp/clo/constants.hpp +++ b/components/core/src/clp/clo/constants.hpp @@ -7,6 +7,7 @@ constexpr char OrigFileId[]{"orig_file_id"}; namespace IrOutput { constexpr char Path[]{"path"}; +constexpr char FileSplitId[]{"file_split_id"}; constexpr char BeginMsgIx[]{"begin_msg_ix"}; constexpr char EndMsgIx[]{"end_msg_ix"}; constexpr char IsLastIrChunk[]{"is_last_ir_chunk"}; diff --git a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py index 015480662..2a0f855a3 100644 --- a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py +++ b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py @@ -64,6 +64,9 @@ # Dictionary of active jobs indexed by job id active_jobs: Dict[str, QueryJob] = {} +# Dictionary that maps IDs of file splits being extracted to IDs of jobs waiting for them +active_file_split_ir_extractions: Dict[str, List[str]] = {} + reducer_connection_queue: Optional[asyncio.Queue] = None @@ -463,12 +466,13 @@ def handle_pending_query_jobs( db_conn_pool, clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, + ir_collection_name: str, num_archives_to_search_per_sub_job: int, ) -> List[asyncio.Task]: global active_jobs + global active_file_split_ir_extractions reducer_acquisition_tasks = [] - pending_search_jobs = [ job for job in active_jobs.values() @@ -542,10 +546,58 @@ def handle_pending_query_jobs( logger.error(f"Failed to set job {job_id} as failed") continue + # NOTE: The following two if blocks should not be reordered since if we first check + # whether *an* IR file has been extracted for the requested file split, it doesn't + # mean that *all* IR files have has been extracted for the file split (since the + # extraction job may still be in progress). Thus, we must first check whether the + # file split is in the process of being extracted, and then check whether it's + # already been extracted. + + # Check if the file split is currently being extracted; if so, add the job ID to the + # list of jobs waiting for it. + if file_split_id in active_file_split_ir_extractions: + active_file_split_ir_extractions[file_split_id].append(job_id) + logger.info( + f"Split {file_split_id} is being extracted, so mark job {job_id} as running" + ) + if not set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + QueryJobStatus.RUNNING, + QueryJobStatus.PENDING, + start_time=datetime.datetime.now(), + num_tasks=0, + ): + logger.error(f"Failed to set job {job_id} as running") + continue + + # Check if the file split has already been extracted + if ir_file_exists_for_file_split( + results_cache_uri, ir_collection_name, file_split_id + ): + logger.info( + f"Split {file_split_id} already extracted, so mark job {job_id} as done" + ) + if not set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + job_id, + QueryJobStatus.SUCCEEDED, + QueryJobStatus.PENDING, + start_time=datetime.datetime.now(), + num_tasks=0, + duration=0, + ): + logger.error(f"Failed to set job {job_id} as succeeded") + continue + + active_file_split_ir_extractions[file_split_id] = [job_id] extract_ir_config.file_split_id = file_split_id new_extract_ir_job = ExtractIrJob( id=job_id, archive_id=archive_id, + file_split_id=file_split_id, extract_ir_config=extract_ir_config, state=InternalJobState.WAITING_FOR_DISPATCH, ) @@ -633,6 +685,15 @@ def found_max_num_latest_results( return max_timestamp_in_remaining_archives <= min_timestamp_in_top_results +def ir_file_exists_for_file_split( + results_cache_uri: str, ir_collection_name: str, file_split_id: str +): + with pymongo.MongoClient(results_cache_uri) as results_cache_client: + ir_collection = results_cache_client.get_default_database()[ir_collection_name] + results_count = ir_collection.count_documents({"file_split_id": file_split_id}) + return 0 != results_count + + async def handle_finished_search_job( db_conn, job: SearchJob, task_results: Optional[Any], results_cache_uri: str ) -> None: @@ -723,8 +784,10 @@ async def handle_finished_extract_ir_job( db_conn, job: ExtractIrJob, task_results: Optional[Any] ) -> None: global active_jobs + global active_file_split_ir_extractions job_id = job.id + file_split_id = job.file_split_id new_job_status = QueryJobStatus.SUCCEEDED num_tasks = len(task_results) if 1 != num_tasks: @@ -761,6 +824,22 @@ async def handle_finished_extract_ir_job( logger.info(f"Completed IR extraction job {job_id}.") else: logger.info(f"Completed IR extraction job {job_id} with failing tasks.") + + waiting_jobs = active_file_split_ir_extractions[file_split_id] + waiting_jobs.remove(job_id) + for waiting_job in waiting_jobs: + logger.info(f"Setting status to {new_job_status.to_str()} for waiting jobs: {waiting_job}.") + set_job_or_task_status( + db_conn, + QUERY_JOBS_TABLE_NAME, + waiting_job, + new_job_status, + QueryJobStatus.RUNNING, + num_tasks_completed=0, + duration=(datetime.datetime.now() - job.start_time).total_seconds(), + ) + + del active_file_split_ir_extractions[file_split_id] del active_jobs[job_id] @@ -819,6 +898,7 @@ async def handle_jobs( db_conn_pool, clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, + ir_collection_name: str, jobs_poll_delay: float, num_archives_to_search_per_sub_job: int, ) -> None: @@ -832,6 +912,7 @@ async def handle_jobs( db_conn_pool, clp_metadata_db_conn_params, results_cache_uri, + ir_collection_name, num_archives_to_search_per_sub_job, ) if 0 == len(reducer_acquisition_tasks): @@ -915,6 +996,7 @@ async def main(argv: List[str]) -> int: True ), results_cache_uri=clp_config.results_cache.get_uri(), + ir_collection_name=clp_config.results_cache.ir_collection_name, jobs_poll_delay=clp_config.query_scheduler.jobs_poll_delay, num_archives_to_search_per_sub_job=batch_size, ) diff --git a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py index 3d4c0d7a7..5ef92a5d6 100644 --- a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py +++ b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py @@ -59,6 +59,7 @@ def get_config(self) -> QueryJobConfig: ... class ExtractIrJob(QueryJob): extract_ir_config: ExtractIrJobConfig + file_split_id: str archive_id: str def get_type(self) -> QueryJobType: From 2a6218ec99be2b913731cadeb182944704bf9854 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Tue, 23 Jul 2024 19:26:49 -0400 Subject: [PATCH 035/114] clp-s: Add option to record metadata about decompressed archive chunks. (#485) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../core/src/clp_s/CommandLineArguments.cpp | 29 +++++++ components/core/src/clp_s/JsonConstructor.cpp | 75 +++++++++++++++---- components/core/src/clp_s/JsonConstructor.hpp | 22 ++++-- .../core/src/clp_s/archive_constants.hpp | 9 +++ components/core/src/clp_s/clp-s.cpp | 10 ++- 5 files changed, 121 insertions(+), 24 deletions(-) diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index 77e896160..4cfe017ac 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -302,6 +302,20 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { // clang-format on extraction_options.add(decompression_options); + po::options_description output_metadata_options("Output Metadata Options"); + // clang-format off + output_metadata_options.add_options()( + "mongodb-uri", + po::value(&m_mongodb_uri)->value_name("URI"), + "MongoDB URI for the database to write decompression metadata to" + )( + "mongodb-collection", + po::value(&m_mongodb_collection)->value_name("COLLECTION"), + "MongoDB collection to write decompression metadata to" + ); + // clang-format on + extraction_options.add(output_metadata_options); + po::positional_options_description positional_options; positional_options.add("archives-dir", 1); positional_options.add("output-dir", 1); @@ -333,6 +347,7 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { visible_options.add(general_options); visible_options.add(input_options); visible_options.add(decompression_options); + visible_options.add(output_metadata_options); std::cerr << visible_options << std::endl; return ParsingResult::InfoCommand; } @@ -349,6 +364,20 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { throw std::invalid_argument("ordered-chunk-size must be used with ordered argument" ); } + + // We use xor to check that these arguments are either both specified or both + // unspecified. + if (m_mongodb_uri.empty() ^ m_mongodb_collection.empty()) { + throw std::invalid_argument( + "mongodb-uri and mongodb-collection must both be non-empty" + ); + } + + if (false == m_mongodb_uri.empty() && false == m_ordered_decompression) { + throw std::invalid_argument( + "Recording decompression metadata only supported for ordered decompression" + ); + } } else if ((char)Command::Search == command_input) { std::string archives_dir; std::string query; diff --git a/components/core/src/clp_s/JsonConstructor.cpp b/components/core/src/clp_s/JsonConstructor.cpp index 68151a1a7..90887f1e5 100644 --- a/components/core/src/clp_s/JsonConstructor.cpp +++ b/components/core/src/clp_s/JsonConstructor.cpp @@ -5,19 +5,19 @@ #include #include +#include +#include +#include +#include +#include "archive_constants.hpp" #include "ErrorCode.hpp" #include "ReaderUtils.hpp" #include "SchemaTree.hpp" #include "TraceableException.hpp" namespace clp_s { -JsonConstructor::JsonConstructor(JsonConstructorOption const& option) - : m_output_dir(option.output_dir), - m_archives_dir(option.archives_dir), - m_ordered{option.ordered}, - m_archive_id(option.archive_id), - m_ordered_chunk_size(option.ordered_chunk_size) { +JsonConstructor::JsonConstructor(JsonConstructorOption const& option) : m_option{option} { std::error_code error_code; if (false == std::filesystem::create_directory(option.output_dir, error_code) && error_code) { throw OperationFailed( @@ -32,8 +32,8 @@ JsonConstructor::JsonConstructor(JsonConstructorOption const& option) ); } - std::filesystem::path archive_path{m_archives_dir}; - archive_path /= m_archive_id; + std::filesystem::path archive_path{m_option.archives_dir}; + archive_path /= m_option.archive_id; if (false == std::filesystem::is_directory(archive_path)) { throw OperationFailed( ErrorCodeFailure, @@ -46,12 +46,12 @@ JsonConstructor::JsonConstructor(JsonConstructorOption const& option) void JsonConstructor::store() { m_archive_reader = std::make_unique(); - m_archive_reader->open(m_archives_dir, m_archive_id); + m_archive_reader->open(m_option.archives_dir, m_option.archive_id); m_archive_reader->read_dictionaries_and_metadata(); - if (false == m_ordered) { + if (false == m_option.ordered) { FileWriter writer; writer.open( - m_output_dir + "/original", + m_option.output_dir + "/original", FileWriter::OpenMode::CreateIfNonexistentForAppending ); m_archive_reader->store(writer); @@ -78,10 +78,24 @@ void JsonConstructor::construct_in_order() { epochtime_t first_timestamp{0}; epochtime_t last_timestamp{0}; size_t num_records_marshalled{0}; - auto src_path = std::filesystem::path(m_output_dir) / m_archive_id; + auto src_path = std::filesystem::path(m_option.output_dir) / m_option.archive_id; FileWriter writer; writer.open(src_path, FileWriter::OpenMode::CreateForWriting); + mongocxx::client client; + mongocxx::collection collection; + + if (m_option.metadata_db.has_value()) { + try { + auto const mongo_uri{mongocxx::uri(m_option.metadata_db->mongodb_uri)}; + client = mongocxx::client{mongo_uri}; + collection = client[mongo_uri.database()][m_option.metadata_db->mongodb_collection]; + } catch (mongocxx::exception const& e) { + throw OperationFailed(ErrorCodeBadParamDbUri, __FILE__, __LINE__, e.what()); + } + } + + std::vector results; auto finalize_chunk = [&](bool open_new_writer) { writer.close(); std::string new_file_name = src_path.string() + "_" + std::to_string(first_timestamp) + "_" @@ -93,6 +107,31 @@ void JsonConstructor::construct_in_order() { throw OperationFailed(ErrorCodeFailure, __FILE__, __LINE__, ec.message()); } + if (m_option.metadata_db.has_value()) { + results.emplace_back(std::move(bsoncxx::builder::basic::make_document( + bsoncxx::builder::basic::kvp( + constants::results_cache::decompression::cPath, + new_file_path.filename() + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::decompression::cOrigFileId, + m_option.archive_id + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::decompression::cBeginMsgIx, + static_cast(first_timestamp) + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::decompression::cEndMsgIx, + static_cast(last_timestamp) + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::decompression::cIsLastIrChunk, + false == open_new_writer + ) + ))); + } + if (open_new_writer) { writer.open(src_path, FileWriter::OpenMode::CreateForWriting); } @@ -112,7 +151,9 @@ void JsonConstructor::construct_in_order() { writer.write(buffer.c_str(), buffer.length()); num_records_marshalled += 1; - if (0 != m_ordered_chunk_size && num_records_marshalled >= m_ordered_chunk_size) { + if (0 != m_option.ordered_chunk_size + && num_records_marshalled >= m_option.ordered_chunk_size) + { finalize_chunk(true); num_records_marshalled = 0; } @@ -128,5 +169,13 @@ void JsonConstructor::construct_in_order() { throw OperationFailed(ErrorCodeFailure, __FILE__, __LINE__, ec.message()); } } + + if (false == results.empty()) { + try { + collection.insert_many(results); + } catch (mongocxx::exception const& e) { + throw OperationFailed(ErrorCodeFailureDbBulkWrite, __FILE__, __LINE__, e.what()); + } + } } } // namespace clp_s diff --git a/components/core/src/clp_s/JsonConstructor.hpp b/components/core/src/clp_s/JsonConstructor.hpp index 22a2daf59..f1f71f9d8 100644 --- a/components/core/src/clp_s/JsonConstructor.hpp +++ b/components/core/src/clp_s/JsonConstructor.hpp @@ -1,6 +1,7 @@ #ifndef CLP_S_JSONCONSTRUCTOR_HPP #define CLP_S_JSONCONSTRUCTOR_HPP +#include #include #include #include @@ -15,12 +16,22 @@ #include "TraceableException.hpp" namespace clp_s { +struct MetadataDbOption { + MetadataDbOption(std::string const& uri, std::string const& collection) + : mongodb_uri{uri}, + mongodb_collection{collection} {} + + std::string mongodb_uri; + std::string mongodb_collection; +}; + struct JsonConstructorOption { std::string archives_dir; std::string archive_id; std::string output_dir; - bool ordered; - size_t ordered_chunk_size; + bool ordered{false}; + size_t ordered_chunk_size{0}; + std::optional metadata_db; }; class JsonConstructor { @@ -59,12 +70,7 @@ class JsonConstructor { */ void construct_in_order(); - std::string m_archives_dir; - std::string m_archive_id; - std::string m_output_dir; - bool m_ordered{false}; - size_t m_ordered_chunk_size{0}; - + JsonConstructorOption m_option{}; std::unique_ptr m_archive_reader; }; } // namespace clp_s diff --git a/components/core/src/clp_s/archive_constants.hpp b/components/core/src/clp_s/archive_constants.hpp index d5a89d0bf..30e2b78d5 100644 --- a/components/core/src/clp_s/archive_constants.hpp +++ b/components/core/src/clp_s/archive_constants.hpp @@ -15,5 +15,14 @@ constexpr char cArchiveArrayDictFile[] = "/array.dict"; constexpr char cArchiveLogDictFile[] = "/log.dict"; constexpr char cArchiveTimestampDictFile[] = "/timestamp.dict"; constexpr char cArchiveVarDictFile[] = "/var.dict"; + +namespace results_cache::decompression { +constexpr char cPath[]{"path"}; +constexpr char cOrigFileId[]{"orig_file_id"}; +constexpr char cBeginMsgIx[]{"begin_msg_ix"}; +constexpr char cEndMsgIx[]{"end_msg_ix"}; +constexpr char cIsLastIrChunk[]{"is_last_ir_chunk"}; +} // namespace results_cache::decompression + } // namespace clp_s::constants #endif // CLP_S_ARCHIVE_CONSTANTS_HPP diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index d01ed0fe0..0e0401ad1 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -245,6 +245,7 @@ int main(int argc, char const* argv[]) { } clp_s::TimestampPattern::init(); + mongocxx::instance const mongocxx_instance{}; CommandLineArguments command_line_arguments("clp-s"); auto parsing_result = command_line_arguments.parse_arguments(argc, argv); @@ -269,11 +270,16 @@ int main(int argc, char const* argv[]) { return 1; } - clp_s::JsonConstructorOption option; + clp_s::JsonConstructorOption option{}; option.output_dir = command_line_arguments.get_output_dir(); option.ordered = command_line_arguments.get_ordered_decompression(); option.archives_dir = archives_dir; option.ordered_chunk_size = command_line_arguments.get_ordered_chunk_size(); + if (false == command_line_arguments.get_mongodb_uri().empty()) { + option.metadata_db + = {command_line_arguments.get_mongodb_uri(), + command_line_arguments.get_mongodb_collection()}; + } try { auto const& archive_id = command_line_arguments.get_archive_id(); if (false == archive_id.empty()) { @@ -295,8 +301,6 @@ int main(int argc, char const* argv[]) { return 1; } } else { - mongocxx::instance const mongocxx_instance{}; - auto const& query = command_line_arguments.get_query(); auto query_stream = std::istringstream(query); auto expr = kql::parse_kql_expression(query_stream); From 9f85a883e4809152ea4016105f81755c569a34c3 Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Wed, 24 Jul 2024 13:49:15 -0400 Subject: [PATCH 036/114] regex-utils: Add support for handling escaped regex metacharacters. (#487) --- components/core/.clang-format | 2 +- .../core/src/clp/regex_utils/ErrorCode.cpp | 4 ++ .../core/src/clp/regex_utils/ErrorCode.hpp | 1 + .../core/src/clp/regex_utils/constants.hpp | 30 +++++++++ .../regex_utils/regex_translation_utils.cpp | 67 ++++++++++++++----- components/core/tests/test-regex_utils.cpp | 30 +++++++-- .../dev-guide/components-core/regex-utils.md | 15 +++++ 7 files changed, 125 insertions(+), 24 deletions(-) diff --git a/components/core/.clang-format b/components/core/.clang-format index c8e66579c..35934f594 100644 --- a/components/core/.clang-format +++ b/components/core/.clang-format @@ -75,7 +75,7 @@ IncludeCategories: # Library headers. Update when adding new libraries. # NOTE: clang-format retains leading white-space on a line in violation of the YAML spec. - Regex: "<(absl|antlr4|archive|boost|bsoncxx|catch2|curl|date|fmt|json|log_surgeon|mariadb\ -|mongocxx|msgpack|outcome|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" +|mongocxx|msgpack|outcome|regex_utils|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" Priority: 3 # C system headers - Regex: "^<.+\\.h>" diff --git a/components/core/src/clp/regex_utils/ErrorCode.cpp b/components/core/src/clp/regex_utils/ErrorCode.cpp index 5779263e8..112ede242 100644 --- a/components/core/src/clp/regex_utils/ErrorCode.cpp +++ b/components/core/src/clp/regex_utils/ErrorCode.cpp @@ -65,6 +65,10 @@ auto ErrorCodeCategory::message(int ev) const -> string { case ErrorCode::IllegalDollarSign: return "Failed to translate due to end anchor `$` in the middle of the string."; + case ErrorCode::IllegalEscapeSequence: + return "Currently only supports escape sequences that are used to suppress special " + "meanings of regex metacharacters. Alphanumeric characters are disallowed."; + case ErrorCode::UnmatchedParenthesis: return "Unmatched opening `(` or closing `)`."; diff --git a/components/core/src/clp/regex_utils/ErrorCode.hpp b/components/core/src/clp/regex_utils/ErrorCode.hpp index 1babb2fec..77a52cf58 100644 --- a/components/core/src/clp/regex_utils/ErrorCode.hpp +++ b/components/core/src/clp/regex_utils/ErrorCode.hpp @@ -19,6 +19,7 @@ enum class ErrorCode : uint8_t { UnsupportedPipe, IllegalCaret, IllegalDollarSign, + IllegalEscapeSequence, UnmatchedParenthesis, }; diff --git a/components/core/src/clp/regex_utils/constants.hpp b/components/core/src/clp/regex_utils/constants.hpp index 879e7641d..9833543fc 100644 --- a/components/core/src/clp/regex_utils/constants.hpp +++ b/components/core/src/clp/regex_utils/constants.hpp @@ -1,7 +1,29 @@ #ifndef CLP_REGEX_UTILS_CONSTANTS_HPP #define CLP_REGEX_UTILS_CONSTANTS_HPP +#include +#include +#include + namespace clp::regex_utils { +constexpr size_t cCharBitarraySize = 128; + +/** + * Creates an ASCII character lookup table at compile time. + * + * @param char_str A string that contains the characters to look up. + * @return The lookup table as bit array. + */ +[[nodiscard]] constexpr auto create_char_bit_array(std::string_view char_str +) -> std::array { + std::array bit_array{}; + bit_array.fill(false); + for (auto const ch : char_str) { + bit_array.at(ch) = true; + } + return bit_array; +} + // Wildcard meta characters constexpr char cZeroOrMoreCharsWildcard{'*'}; constexpr char cSingleCharWildcard{'?'}; @@ -14,6 +36,14 @@ constexpr char cRegexStartAnchor{'^'}; constexpr char cRegexEndAnchor{'$'}; constexpr char cEscapeChar{'\\'}; constexpr char cCharsetNegate{'^'}; + +// Character bitmaps +// The set of regex metacharacters that can be preceded with an escape backslash to be treated as a +// literal. +constexpr auto cRegexEscapeSeqMetaCharsLut = create_char_bit_array("*+?|^$.{}[]()<>-_/=!\\"); +// The set of wildcard metacharacters that must remain escaped in the translated string to be +// treated as a literal. +constexpr auto cWildcardMetaCharsLut = create_char_bit_array("?*\\"); } // namespace clp::regex_utils #endif // CLP_REGEX_UTILS_CONSTANTS_HPP diff --git a/components/core/src/clp/regex_utils/regex_translation_utils.cpp b/components/core/src/clp/regex_utils/regex_translation_utils.cpp index 349c106f4..f26d70521 100644 --- a/components/core/src/clp/regex_utils/regex_translation_utils.cpp +++ b/components/core/src/clp/regex_utils/regex_translation_utils.cpp @@ -27,17 +27,19 @@ class TranslatorState { * * This list may be expanded as the translator supports translating more regex patterns. *
    - *
  • NORMAL: The initial state, where characters have no special meanings and are treated + *
  • Normal: The initial state, where characters have no special meanings and are treated * literally.
  • - *
  • DOT: Encountered a period `.`. Expecting wildcard expression.
  • - *
  • END: Encountered a dollar sign `$`, meaning the regex string has reached the end + *
  • Dot: Encountered a period `.`. Expecting wildcard expression.
  • + *
  • Escaped: Encountered a backslash `\`. Expecting an escape sequence.
  • + *
  • End: Encountered a dollar sign `$`, meaning the regex string has reached the end * anchor.
  • *
*/ enum class RegexPatternState : uint8_t { - NORMAL = 0, - DOT, - END, + Normal = 0, + Dot, + Escaped, + End, }; // Constructor @@ -51,7 +53,7 @@ class TranslatorState { private: // Members - RegexPatternState m_state{RegexPatternState::NORMAL}; + RegexPatternState m_state{RegexPatternState::Normal}; }; /** @@ -92,13 +94,22 @@ using StateTransitionFuncSig */ [[nodiscard]] StateTransitionFuncSig dot_state_transition; +/** + * Appends an escaped regex metacharacter as a literal character to the wildcard string by + * discarding its preceding backslash. + * + * The preceding backslash must be kept for characters that also have special meanings in the + * wildcard syntax, e.g. `abc.\*xyz` should be translated into `abc?\*xyz` instead of `abc?*xyz`. + */ +[[nodiscard]] StateTransitionFuncSig escaped_state_transition; + /** * Disallows the appearances of other characters after encountering an end anchor in the string. */ [[nodiscard]] StateTransitionFuncSig end_state_transition; /** - * States other than the NORMAL state may require special handling after the whole regex string has + * States other than the Normal state may require special handling after the whole regex string has * been scanned and processed. */ [[nodiscard]] StateTransitionFuncSig final_state_cleanup; @@ -112,10 +123,13 @@ auto normal_state_transition( auto const ch{*it}; switch (ch) { case '.': - state.set_next_state(TranslatorState::RegexPatternState::DOT); + state.set_next_state(TranslatorState::RegexPatternState::Dot); + break; + case cEscapeChar: + state.set_next_state(TranslatorState::RegexPatternState::Escaped); break; case cRegexEndAnchor: - state.set_next_state(TranslatorState::RegexPatternState::END); + state.set_next_state(TranslatorState::RegexPatternState::End); break; case cRegexZeroOrMore: return ErrorCode::UntranslatableStar; @@ -155,7 +169,25 @@ auto dot_state_transition( --it; break; } - state.set_next_state(TranslatorState::RegexPatternState::NORMAL); + state.set_next_state(TranslatorState::RegexPatternState::Normal); + return ErrorCode::Success; +} + +auto escaped_state_transition( + TranslatorState& state, + string_view::const_iterator& it, + string& wildcard_str, + [[maybe_unused]] RegexToWildcardTranslatorConfig const& config +) -> error_code { + auto const ch{*it}; + if (false == cRegexEscapeSeqMetaCharsLut.at(ch)) { + return ErrorCode::IllegalEscapeSequence; + } + if (cWildcardMetaCharsLut.at(ch)) { + wildcard_str += cEscapeChar; + } + wildcard_str += ch; + state.set_next_state(TranslatorState::RegexPatternState::Normal); return ErrorCode::Success; } @@ -178,7 +210,7 @@ auto final_state_cleanup( RegexToWildcardTranslatorConfig const& config ) -> error_code { switch (state.get_state()) { - case TranslatorState::RegexPatternState::DOT: + case TranslatorState::RegexPatternState::Dot: // The last character is a single `.`, without the possibility of becoming a // multichar wildcard wildcard_str += cSingleCharWildcard; @@ -187,7 +219,7 @@ auto final_state_cleanup( break; } - if (TranslatorState::RegexPatternState::END != state.get_state() + if (TranslatorState::RegexPatternState::End != state.get_state() && config.add_prefix_suffix_wildcards()) { wildcard_str += cZeroOrMoreCharsWildcard; @@ -220,13 +252,16 @@ auto regex_to_wildcard(string_view regex_str, RegexToWildcardTranslatorConfig co error_code ec{}; while (it != regex_str.cend()) { switch (state.get_state()) { - case TranslatorState::RegexPatternState::NORMAL: + case TranslatorState::RegexPatternState::Normal: ec = normal_state_transition(state, it, wildcard_str, config); break; - case TranslatorState::RegexPatternState::DOT: + case TranslatorState::RegexPatternState::Dot: ec = dot_state_transition(state, it, wildcard_str, config); break; - case TranslatorState::RegexPatternState::END: + case TranslatorState::RegexPatternState::Escaped: + ec = escaped_state_transition(state, it, wildcard_str, config); + break; + case TranslatorState::RegexPatternState::End: ec = end_state_transition(state, it, wildcard_str, config); break; default: diff --git a/components/core/tests/test-regex_utils.cpp b/components/core/tests/test-regex_utils.cpp index fc79b966a..9defd7d08 100644 --- a/components/core/tests/test-regex_utils.cpp +++ b/components/core/tests/test-regex_utils.cpp @@ -1,31 +1,47 @@ +#include #include #include #include -#include - using clp::regex_utils::ErrorCode; using clp::regex_utils::regex_to_wildcard; using clp::regex_utils::RegexToWildcardTranslatorConfig; -TEST_CASE("regex_to_wildcard", "[regex_utils][regex_to_wildcard]") { - // Test empty string +TEST_CASE("regex_to_wildcard_simple_translations", "[regex_utils][re2wc][simple_translations]") { REQUIRE(regex_to_wildcard("").value().empty()); - // Test simple wildcard translations REQUIRE((regex_to_wildcard("xyz").value() == "xyz")); REQUIRE((regex_to_wildcard(". xyz .* zyx .").value() == "? xyz * zyx ?")); REQUIRE((regex_to_wildcard(". xyz .+ zyx .*").value() == "? xyz ?* zyx *")); +} - // Test unescaped meta characters +TEST_CASE("regex_to_wildcard_unescaped_metachar", "[regex_utils][re2wc][unescaped_metachar]") { REQUIRE((regex_to_wildcard(".? xyz .* zyx .").error() == ErrorCode::UnsupportedQuestionMark)); REQUIRE((regex_to_wildcard(". xyz .** zyx .").error() == ErrorCode::UntranslatableStar)); REQUIRE((regex_to_wildcard(". xyz .*+ zyx .").error() == ErrorCode::UntranslatablePlus)); REQUIRE((regex_to_wildcard(". xyz |.* zyx .").error() == ErrorCode::UnsupportedPipe)); REQUIRE((regex_to_wildcard(". xyz ^.* zyx .").error() == ErrorCode::IllegalCaret)); + REQUIRE((regex_to_wildcard(". xyz $.* zyx .").error() == ErrorCode::IllegalDollarSign)); +} + +TEST_CASE("regex_to_wildcard_escaped_metachar", "[regex_utils][re2wc][escaped_metachar]") { + // Escape backslash is superfluous for the following set of characters + REQUIRE((regex_to_wildcard("<>-_/=!").value() == "<>-_/=!")); + REQUIRE((regex_to_wildcard("\\<\\>\\-\\_\\/\\=\\!").value() == "<>-_/=!")); + // Test the full escape sequences set + REQUIRE( + (regex_to_wildcard("\\*\\+\\?\\|\\^\\$\\.\\{\\}\\[\\]\\(\\)\\<\\>\\-\\_\\/\\=\\!\\\\") + .value() + == "\\*+\\?|^$.{}[]()<>-_/=!\\\\") + ); + // Test unsupported escape sequences + REQUIRE( + (regex_to_wildcard("abc\\Qdefghi\\Ejkl").error() + == clp::regex_utils::ErrorCode::IllegalEscapeSequence) + ); } -TEST_CASE("regex_to_wildcard_anchor_config", "[regex_utils][regex_to_wildcard][anchor_config]") { +TEST_CASE("regex_to_wildcard_anchor_config", "[regex_utils][re2wc][anchor_config]") { // Test anchors and prefix/suffix wildcards RegexToWildcardTranslatorConfig const config{false, true}; REQUIRE(((regex_to_wildcard("^", config).value() == "*"))); diff --git a/docs/src/dev-guide/components-core/regex-utils.md b/docs/src/dev-guide/components-core/regex-utils.md index a7ec16774..f7af037df 100644 --- a/docs/src/dev-guide/components-core/regex-utils.md +++ b/docs/src/dev-guide/components-core/regex-utils.md @@ -62,6 +62,21 @@ For a detailed description on the options order and usage, see the * Turn `.*` into `*` * Turn `.+` into `?*` * E.g. `abc.*def.ghi.+` will get translated to `abc*def?ghi?*` +* Metacharacter escape sequences + * An escaped regex metacharacter is treated as a literal and appended to the wildcard output. + * The list of characters that require escaping to have their special meanings suppressed is + `[\/^$.|?*+(){}`. + * Superfluous escape characters are ignored for the following characters: `],<>-_=!`. + * E.g. `a\[\+b\-\_c-_d` will get translated to `a[+b-_c-_d` + * Note: generally, any non-alphanumeric character can be escaped to use it as a literal. The + list this utils library supports is non-exhaustive and can be expanded when necessary. + * For metacharacters shared by both syntaxes, keep the escape backslashes. + * The list of characters that fall into this category is `*?\`. All wildcard metacharacters are + also regex metacharacters. + * E.g. `a\*b\?c\\d` will get translated to `a\*b\?c\\d` (no change) + * Escape sequences with alphanumeric characters are disallowed. + * E.g. Special utility escape sequences `\Q`, `\E`, `\A` etc. and back references `\1` `\2` etc. + cannot be translated. ### Custom configuration From be1877d390000ac693836ffb98f864d03d797490 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:35:07 -0400 Subject: [PATCH 037/114] clp-package: Add the log-viewer and serve it using the log-viewer-webui. (#490) --- .gitmodules | 3 + Taskfile.yml | 81 ++++++++++++++++--- .../clp_package_utils/scripts/start_clp.py | 1 + .../log-viewer-webui/server/settings.json | 3 +- components/log-viewer-webui/server/src/app.js | 32 +------- .../server/src/routes/static.js | 56 +++++++++++++ components/log-viewer-webui/yscope-log-viewer | 1 + 7 files changed, 134 insertions(+), 43 deletions(-) create mode 100644 components/log-viewer-webui/server/src/routes/static.js create mode 160000 components/log-viewer-webui/yscope-log-viewer diff --git a/.gitmodules b/.gitmodules index 5eb798197..3935b0101 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,6 @@ [submodule "components/core/submodules/outcome"] path = components/core/submodules/outcome url = https://github.com/ned14/outcome.git +[submodule "components/log-viewer-webui/yscope-log-viewer"] + path = components/log-viewer-webui/yscope-log-viewer + url = https://github.com/y-scope/yscope-log-viewer.git diff --git a/Taskfile.yml b/Taskfile.yml index e547dd68b..f0c466e31 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -47,6 +47,7 @@ tasks: - "rm -rf 'components/log-viewer-webui/client/node_modules'" - "rm -rf 'components/log-viewer-webui/node_modules'" - "rm -rf 'components/log-viewer-webui/server/node_modules'" + - "rm -rf 'components/log-viewer-webui/yscope-log-viewer/node_modules'" clean-webui: cmds: @@ -74,7 +75,7 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_PACKAGE_BUILD_DIR}}" sources: - - "{{.G_BUILD_DIR}}/log-viewer-webui-client.md5" + - "{{.G_BUILD_DIR}}/log-viewer-webui-clients.md5" - "{{.G_BUILD_DIR}}/package-venv.md5" - "{{.G_BUILD_DIR}}/webui.md5" - "{{.G_BUILD_DIR}}/webui-nodejs.md5" @@ -100,7 +101,7 @@ tasks: - "clp-py-utils" - "init" - "job-orchestration" - - "log-viewer-webui-client" + - "log-viewer-webui-clients" - "nodejs-14" - "package-venv" - task: "utils:validate-checksum" @@ -150,6 +151,7 @@ tasks: - >- rsync -a "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/client" + "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/yscope-log-viewer" "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/" - |- cd components/log-viewer-webui/server/ @@ -206,17 +208,23 @@ tasks: vars: COMPONENT: "{{.TASK}}" - log-viewer-webui-client: + log-viewer-webui-clients: vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}" sources: - - "{{.G_BUILD_DIR}}/log-viewer-modules.md5" + - "{{.G_BUILD_DIR}}/log-viewer-webui-node-modules.md5" - "{{.TASKFILE}}" - "client/package.json" - "client/src/**/*.css" - "client/src/**/*.jsx" - "client/src/webpack.config.js" + - "yscope-log-viewer/.babelrc" + - "yscope-log-viewer/customized-packages/**/*" + - "yscope-log-viewer/package.json" + - "yscope-log-viewer/src/**/*" + - "yscope-log-viewer/webpack.common.js" + - "yscope-log-viewer/webpack.prod.js" dir: "components/log-viewer-webui" generates: ["{{.CHECKSUM_FILE}}"] deps: @@ -228,10 +236,13 @@ tasks: DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - - |- - cd client - PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build -- \ - --output-path "{{.OUTPUT_DIR}}/client" + - for: + - "client" + - "yscope-log-viewer" + cmd: |- + cd "{{.ITEM}}" + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build -- \ + --output-path "{{.OUTPUT_DIR}}/{{.ITEM}}" - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" @@ -364,25 +375,31 @@ tasks: DATA_DIR: "{{.OUTPUT_DIR}}" OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - # NOTE: The log-viewer-webui has three different node_modules directories (client, server, and the - # top-level one we call "package"), meaning we have to create three different checksums. To allow - # tasks which depend on this task to only have to check one checksum file, we concatenate the - # three checksum files into one. + # NOTE: The log-viewer-webui has four different node_modules directories: + # * client + # * server + # * log-viewer submodule + # * the top-level one we call "package" + # This means we have to create four different checksums. To allow tasks which depend on this task + # to only have to check one checksum file, we concatenate the four checksum files into one. log-viewer-webui-node-modules: internal: true vars: # Checksum files CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" CLIENT_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-client-node-modules.md5" + LOG_VIEWER_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-log-viewer-node-modules.md5" PACKAGE_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-package-node-modules.md5" SERVER_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/log-viewer-webui-server-node-modules.md5" # Directories SRC_DIR: "{{.TASKFILE_DIR}}/components/log-viewer-webui" CLIENT_OUTPUT_DIR: "{{.SRC_DIR}}/client/node_modules" + LOG_VIEWER_OUTPUT_DIR: "{{.SRC_DIR}}/yscope-log-viewer/node_modules" PACKAGE_OUTPUT_DIR: "{{.SRC_DIR}}/node_modules" SERVER_OUTPUT_DIR: "{{.SRC_DIR}}/server/node_modules" sources: + - "{{.G_BUILD_DIR}}/log-viewer-webui-submodules.md5" - "{{.G_BUILD_DIR}}/nodejs-22.md5" - "{{.TASKFILE}}" - "client/package.json" @@ -391,13 +408,17 @@ tasks: - "package-lock.json" - "server/package.json" - "server/package-lock.json" + - "yscope-log-viewer/package.json" + - "yscope-log-viewer/package-lock.json" dir: "{{.SRC_DIR}}" generates: - "{{.CHECKSUM_FILE}}" - "{{.CLIENT_CHECKSUM_FILE}}" + - "{{.LOG_VIEWER_CHECKSUM_FILE}}" - "{{.PACKAGE_CHECKSUM_FILE}}" - "{{.SERVER_CHECKSUM_FILE}}" deps: + - "log-viewer-webui-submodules" - "nodejs-22" - task: "utils:validate-checksum" vars: @@ -411,15 +432,26 @@ tasks: vars: CHECKSUM_FILE: "{{.PACKAGE_CHECKSUM_FILE}}" DATA_DIR: "{{.PACKAGE_OUTPUT_DIR}}" + - task: "utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.LOG_VIEWER_CHECKSUM_FILE}}" + DATA_DIR: "{{.LOG_VIEWER_OUTPUT_DIR}}" cmds: - "rm -f {{.CHECKSUM_FILE}}" - task: "clean-log-viewer-webui" - "PATH='{{.G_NODEJS_22_BIN_DIR}}':$PATH npm run init" + - |- + cd yscope-log-viewer + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm install # These commands must be last - task: "utils:compute-checksum" vars: DATA_DIR: "{{.CLIENT_OUTPUT_DIR}}" OUTPUT_FILE: "{{.CLIENT_CHECKSUM_FILE}}" + - task: "utils:compute-checksum" + vars: + DATA_DIR: "{{.LOG_VIEWER_OUTPUT_DIR}}" + OUTPUT_FILE: "{{.LOG_VIEWER_CHECKSUM_FILE}}" - task: "utils:compute-checksum" vars: DATA_DIR: "{{.PACKAGE_OUTPUT_DIR}}" @@ -432,10 +464,35 @@ tasks: - >- cat "{{.CLIENT_CHECKSUM_FILE}}" + "{{.LOG_VIEWER_CHECKSUM_FILE}}" "{{.PACKAGE_CHECKSUM_FILE}}" "{{.SERVER_CHECKSUM_FILE}}" > "{{.CHECKSUM_FILE}}" + log-viewer-webui-submodules: + internal: true + vars: + CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" + OUTPUT_DIR: "yscope-log-viewer" + sources: + - "{{.TASKFILE}}" + - ".gitmodules" + dir: "components/log-viewer-webui" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - "init" + - task: "utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.OUTPUT_DIR}}" + cmds: + - "git submodule update --init --recursive yscope-log-viewer" + # This command must be last + - task: "utils:compute-checksum" + vars: + DATA_DIR: "{{.OUTPUT_DIR}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + meteor: vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 74bb5f018..5e5965bf5 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -864,6 +864,7 @@ def start_log_viewer_webui( "MongoDbIrFilesCollectionName": clp_config.results_cache.ir_collection_name, "ClientDir": str(container_log_viewer_webui_dir / "client"), "IrFilesDir": str(container_clp_config.ir_output.directory), + "LogViewerDir": str(container_log_viewer_webui_dir / "yscope-log-viewer"), } settings_json = read_and_update_settings_json(settings_json_path, settings_json_updates) with open(settings_json_path, "w") as settings_json_file: diff --git a/components/log-viewer-webui/server/settings.json b/components/log-viewer-webui/server/settings.json index 76183a879..bb1aac48a 100644 --- a/components/log-viewer-webui/server/settings.json +++ b/components/log-viewer-webui/server/settings.json @@ -9,5 +9,6 @@ "MongoDbIrFilesCollectionName": "ir-files", "ClientDir": "../client/dist", - "IrFilesDir": "../../../build/clp-package/var/data/ir" + "IrFilesDir": "../../../build/clp-package/var/data/ir", + "LogViewerDir": "../yscope-log-viewer/dist" } diff --git a/components/log-viewer-webui/server/src/app.js b/components/log-viewer-webui/server/src/app.js index 28c7fdfe5..69918ea58 100644 --- a/components/log-viewer-webui/server/src/app.js +++ b/components/log-viewer-webui/server/src/app.js @@ -1,14 +1,11 @@ import fastify from "fastify"; -import * as path from "node:path"; import process from "node:process"; -import {fileURLToPath} from "node:url"; - -import {fastifyStatic} from "@fastify/static"; import settings from "../settings.json" with {type: "json"}; import DbManager from "./DbManager.js"; import exampleRoutes from "./routes/example.js"; import queryRoutes from "./routes/query.js"; +import staticRoutes from "./routes/static.js"; /** @@ -26,20 +23,8 @@ const app = async ({ sqlDbPass, }) => { const server = fastify(fastifyOptions); - const filename = fileURLToPath(import.meta.url); - const dirname = path.dirname(filename); - const parentDirname = path.resolve(dirname, ".."); if ("test" !== process.env.NODE_ENV) { - let irFilesDir = settings.IrFilesDir; - if (false === path.isAbsolute(irFilesDir)) { - irFilesDir = path.resolve(parentDirname, irFilesDir); - } - await server.register(fastifyStatic, { - prefix: "/ir", - root: irFilesDir, - }); - await server.register(DbManager, { mysqlConfig: { database: settings.SqlDbName, @@ -58,20 +43,7 @@ const app = async ({ }); } - if ("production" === process.env.NODE_ENV) { - // In the development environment, we expect the client to use a separate webserver that - // supports live reloading. - if (false === path.isAbsolute(settings.ClientDir)) { - throw new Error("`clientDir` must be an absolute path."); - } - - await server.register(fastifyStatic, { - prefix: "/", - root: settings.ClientDir, - decorateReply: false, - }); - } - + await server.register(staticRoutes); await server.register(exampleRoutes); await server.register(queryRoutes); diff --git a/components/log-viewer-webui/server/src/routes/static.js b/components/log-viewer-webui/server/src/routes/static.js new file mode 100644 index 000000000..42d9048f0 --- /dev/null +++ b/components/log-viewer-webui/server/src/routes/static.js @@ -0,0 +1,56 @@ +import path from "node:path"; +import process from "node:process"; +import {fileURLToPath} from "node:url"; + +import {fastifyStatic} from "@fastify/static"; + +import settings from "../../settings.json" with {type: "json"}; + + +/** + * Creates static files serving routes. + * + * @param {import("fastify").FastifyInstance} fastify + * @param {import("fastify").FastifyPluginOptions} options + */ +const routes = async (fastify, options) => { + const filename = fileURLToPath(import.meta.url); + const dirname = path.dirname(filename); + const rootDirname = path.resolve(dirname, "../.."); + + let irFilesDir = settings.IrFilesDir; + if (false === path.isAbsolute(irFilesDir)) { + irFilesDir = path.resolve(rootDirname, irFilesDir); + } + await fastify.register(fastifyStatic, { + prefix: "/ir", + root: irFilesDir, + }); + + let logViewerDir = settings.LogViewerDir; + if (false === path.isAbsolute(logViewerDir)) { + logViewerDir = path.resolve(rootDirname, logViewerDir); + } + await fastify.register(fastifyStatic, { + prefix: "/log-viewer", + root: logViewerDir, + decorateReply: false, + }); + + if ("production" === process.env.NODE_ENV) { + // In the development environment, we expect the client to use a separate webserver that + // supports live reloading. + let clientDir = settings.ClientDir; + if (false === path.isAbsolute(clientDir)) { + clientDir = path.resolve(rootDirname, settings.ClientDir); + } + + await fastify.register(fastifyStatic, { + prefix: "/", + root: clientDir, + decorateReply: false, + }); + } +}; + +export default routes; diff --git a/components/log-viewer-webui/yscope-log-viewer b/components/log-viewer-webui/yscope-log-viewer new file mode 160000 index 000000000..df996eac0 --- /dev/null +++ b/components/log-viewer-webui/yscope-log-viewer @@ -0,0 +1 @@ +Subproject commit df996eac000823d02f9cd0b9eb4bb732dd634ae5 From 0837494e12724813399266852539cebb4591d691 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:28:21 -0400 Subject: [PATCH 038/114] core-clp: Add class to encapsulate `libcurl`'s global resource management. (#461) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 2 + .../core/src/clp/CurlGlobalInstance.cpp | 45 +++++++++++++++++++ .../core/src/clp/CurlGlobalInstance.hpp | 35 +++++++++++++++ components/core/src/clp/NetworkReader.cpp | 30 ------------- components/core/src/clp/NetworkReader.hpp | 33 +++++++------- components/core/tests/test-NetworkReader.cpp | 20 +++------ 6 files changed, 103 insertions(+), 62 deletions(-) create mode 100644 components/core/src/clp/CurlGlobalInstance.cpp create mode 100644 components/core/src/clp/CurlGlobalInstance.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 57ae8cda1..19c9151bf 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -283,6 +283,8 @@ set(SOURCE_FILES_unitTest src/clp/CurlDownloadHandler.cpp src/clp/CurlDownloadHandler.hpp src/clp/CurlEasyHandle.hpp + src/clp/CurlGlobalInstance.cpp + src/clp/CurlGlobalInstance.hpp src/clp/CurlOperationFailed.hpp src/clp/CurlStringList.hpp src/clp/database_utils.cpp diff --git a/components/core/src/clp/CurlGlobalInstance.cpp b/components/core/src/clp/CurlGlobalInstance.cpp new file mode 100644 index 000000000..7add2afe9 --- /dev/null +++ b/components/core/src/clp/CurlGlobalInstance.cpp @@ -0,0 +1,45 @@ +#include "CurlGlobalInstance.hpp" + +#include + +#include + +#include "CurlOperationFailed.hpp" +#include "ErrorCode.hpp" + +namespace clp { +CurlGlobalInstance::CurlGlobalInstance() { + std::scoped_lock const global_lock{m_ref_count_mutex}; + if (0 == m_ref_count) { + if (auto const err{curl_global_init(CURL_GLOBAL_ALL)}; 0 != err) { + throw CurlOperationFailed( + ErrorCode_Failure, + __FILE__, + __LINE__, + err, + "`curl_global_init` failed." + ); + } + } + ++m_ref_count; +} + +CurlGlobalInstance::~CurlGlobalInstance() { + std::scoped_lock const global_lock{m_ref_count_mutex}; + --m_ref_count; + if (0 == m_ref_count) { +#if defined(__APPLE__) + // NOTE: On macOS, calling `curl_global_init` after `curl_global_cleanup` will fail with + // CURLE_SSL_CONNECT_ERROR. Thus, for now, we skip `deinit` on macOS. Luckily, it is safe to + // call `curl_global_init` multiple times without calling `curl_global_cleanup`. Related + // issues: + // - https://github.com/curl/curl/issues/12525 + // - https://github.com/curl/curl/issues/13805 + // TODO: Remove this conditional logic when the issues are resolved. + return; +#else + curl_global_cleanup(); +#endif + } +} +} // namespace clp diff --git a/components/core/src/clp/CurlGlobalInstance.hpp b/components/core/src/clp/CurlGlobalInstance.hpp new file mode 100644 index 000000000..56ec60ed8 --- /dev/null +++ b/components/core/src/clp/CurlGlobalInstance.hpp @@ -0,0 +1,35 @@ +#ifndef CLP_CURLGLOBALINSTANCE_HPP +#define CLP_CURLGLOBALINSTANCE_HPP + +#include +#include + +namespace clp { +/** + * Class to wrap `libcurl`'s global initialization/de-initialization calls using RAII. Before using + * any `libcurl` functionalities, an instance of this class must be created. Although unnecessasry, + * it can be safely instantiated multiple times; it maintains a static reference count to all + * existing instances and only de-initializes `libcurl`'s global resources when the reference count + * reaches 0. + */ +class CurlGlobalInstance { +public: + // Constructors + CurlGlobalInstance(); + + // Disable copy/move constructors and assignment operators + CurlGlobalInstance(CurlGlobalInstance const&) = delete; + CurlGlobalInstance(CurlGlobalInstance&&) = delete; + auto operator=(CurlGlobalInstance const&) -> CurlGlobalInstance& = delete; + auto operator=(CurlGlobalInstance&&) -> CurlGlobalInstance& = delete; + + // Destructor + ~CurlGlobalInstance(); + +private: + static inline std::mutex m_ref_count_mutex; + static inline size_t m_ref_count{0}; +}; +} // namespace clp + +#endif // CLP_CURLGLOBALINSTANCE_HPP diff --git a/components/core/src/clp/NetworkReader.cpp b/components/core/src/clp/NetworkReader.cpp index 1ab746a54..c0b5359bf 100644 --- a/components/core/src/clp/NetworkReader.cpp +++ b/components/core/src/clp/NetworkReader.cpp @@ -110,33 +110,6 @@ curl_write_callback(char* ptr, size_t size, size_t nmemb, void* reader_ptr) -> s } } // namespace -bool NetworkReader::m_static_init_complete{false}; - -auto NetworkReader::init() -> ErrorCode { - if (m_static_init_complete) { - return ErrorCode_Success; - } - if (0 != curl_global_init(CURL_GLOBAL_ALL)) { - return ErrorCode_Failure; - } - m_static_init_complete = true; - return ErrorCode_Success; -} - -auto NetworkReader::deinit() -> void { -#if defined(__APPLE__) - // NOTE: On macOS, calling `curl_global_init` after `curl_global_cleanup` will fail with - // CURLE_SSL_CONNECT_ERROR. Thus, for now, we skip `deinit` on macOS. Related issues: - // - https://github.com/curl/curl/issues/12525 - // - https://github.com/curl/curl/issues/13805 - // TODO: Remove this conditional logic when the issues are resolved. - return; -#else - curl_global_cleanup(); - m_static_init_complete = false; -#endif -} - NetworkReader::NetworkReader( std::string_view src_url, size_t offset, @@ -157,9 +130,6 @@ NetworkReader::NetworkReader( // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) m_buffer_pool.emplace_back(std::make_unique(m_buffer_size)); } - if (false == m_static_init_complete) { - throw OperationFailed(ErrorCode_NotReady, __FILE__, __LINE__); - } m_downloader_thread = std::make_unique(*this, offset, disable_caching); m_downloader_thread->start(); } diff --git a/components/core/src/clp/NetworkReader.hpp b/components/core/src/clp/NetworkReader.hpp index 5a593029f..68e6d1019 100644 --- a/components/core/src/clp/NetworkReader.hpp +++ b/components/core/src/clp/NetworkReader.hpp @@ -18,6 +18,7 @@ #include #include "CurlDownloadHandler.hpp" +#include "CurlGlobalInstance.hpp" #include "ErrorCode.hpp" #include "ReaderInterface.hpp" #include "Thread.hpp" @@ -69,24 +70,20 @@ class NetworkReader : public ReaderInterface { static constexpr size_t cMinBufferPoolSize{2}; static constexpr size_t cMinBufferSize{512}; - /** - * Initializes static resources for this class. This must be called before using the class. - * @return ErrorCode_Success on success. - * @return ErrorCode_Failure if libcurl initialization failed. - */ - [[nodiscard]] static auto init() -> ErrorCode; - - /** - * De-initializes any static resources. - */ - static auto deinit() -> void; - /** * Constructs a reader to stream data from the given URL, starting at the given offset. - * TODO: the current implementation doesn't handle the case when the given offset is out of - * range. The file_pos will be set to an invalid state if this happens, which can be - * problematic if the other part of the program depends on this position. It can be fixed by - * capturing the error code 416 in the response header. + * NOTE: This class depends on `libcurl`, so an instance of `clp::CurlGlobalInstance` must + * remain alive for the entire lifespan of any instance of this class. + * + * This class maintains an instance of `CurlGlobalInstance` in case the user forgets to + * instantiate one, but it is better for performance if the user instantiates one. For instance, + * if the user doesn't instantiate a `CurlGlobalInstance` and only ever creates one + * `NetworkReader` at a time, then every construction and destruction of `NetworkReader` would + * cause `libcurl` to init and deinit. In contrast, if the user instantiates a + * `CurlGlobalInstance` before instantiating any `NetworkReader`s, then the `CurlGlobalInstance` + * maintained by this class will simply be a reference to the existing one rather than + * initializing and deinitializing `libcurl`. + * * @param src_url * @param offset Index of the byte at which to start the download * @param disable_caching Whether to disable the caching. @@ -246,8 +243,6 @@ class NetworkReader : public ReaderInterface { bool m_disable_caching{false}; }; - static bool m_static_init_complete; - /** * Submits a request to abort the ongoing curl download session. */ @@ -308,6 +303,8 @@ class NetworkReader : public ReaderInterface { return m_at_least_one_byte_downloaded.load(); } + CurlGlobalInstance m_curl_global_instance; + std::string m_src_url; size_t m_offset{0}; diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index 958e31d8b..d06876f5f 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -12,6 +12,7 @@ #include #include "../src/clp/CurlDownloadHandler.hpp" +#include "../src/clp/CurlGlobalInstance.hpp" #include "../src/clp/ErrorCode.hpp" #include "../src/clp/FileReader.hpp" #include "../src/clp/NetworkReader.hpp" @@ -71,7 +72,7 @@ TEST_CASE("network_reader_basic", "[NetworkReader]") { auto const expected{get_content(ref_reader)}; ref_reader.close(); - REQUIRE((clp::ErrorCode_Success == clp::NetworkReader::init())); + clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url()}; auto const actual{get_content(reader)}; auto const ret_code{reader.get_curl_ret_code()}; @@ -79,7 +80,6 @@ TEST_CASE("network_reader_basic", "[NetworkReader]") { // NOLINTNEXTLINE(bugprone-unchecked-optional-access) REQUIRE((CURLE_OK == ret_code.value())); REQUIRE((actual == expected)); - clp::NetworkReader::deinit(); } TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { @@ -91,10 +91,9 @@ TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { auto const ref_end_pos{ref_reader.get_pos()}; ref_reader.close(); - REQUIRE((clp::ErrorCode_Success == clp::NetworkReader::init())); - // Read from an offset onwards by starting the download from that offset. { + clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url(), cOffset}; auto const actual{get_content(reader)}; auto const ret_code{reader.get_curl_ret_code()}; @@ -107,6 +106,7 @@ TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { // Read from an offset onwards by seeking to that offset. { + clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader(get_test_input_remote_url()); reader.seek_from_begin(cOffset); auto const actual{get_content(reader)}; @@ -117,19 +117,16 @@ TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { REQUIRE((reader.get_pos() == ref_end_pos)); REQUIRE((actual == expected)); } - - clp::NetworkReader::deinit(); } TEST_CASE("network_reader_destruct", "[NetworkReader]") { - REQUIRE((clp::ErrorCode_Success == clp::NetworkReader::init())); - // We sleep to fill out all the buffers, and then we delete the reader. The destructor will try // to abort the underlying download and then destroy the instance. So should ensure destructor // is successfully executed without deadlock or exceptions. bool no_exception{true}; try { // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + clp::CurlGlobalInstance const curl_global_instance; auto reader{std::make_unique( get_test_input_remote_url(), 0, @@ -147,15 +144,12 @@ TEST_CASE("network_reader_destruct", "[NetworkReader]") { no_exception = false; } REQUIRE(no_exception); - - clp::NetworkReader::deinit(); } TEST_CASE("network_reader_illegal_offset", "[NetworkReader]") { - REQUIRE((clp::ErrorCode_Success == clp::NetworkReader::init())); - // Try to read from an out-of-bound offset. constexpr size_t cIllegalOffset{UINT32_MAX}; + clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url(), cIllegalOffset}; while (true) { auto const ret_code{reader.get_curl_ret_code()}; @@ -166,6 +160,4 @@ TEST_CASE("network_reader_illegal_offset", "[NetworkReader]") { break; } } - - clp::NetworkReader::deinit(); } From 2c99375202b9f49991f13503c936854862bce8df Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sat, 27 Jul 2024 23:13:20 -0400 Subject: [PATCH 039/114] Add support for viewing search results in context for text logs (clp-text). (#489) --- .../clp_package_utils/scripts/start_clp.py | 3 + .../log-viewer-webui/client/package-lock.json | 668 ++++++++++++++++-- .../log-viewer-webui/client/package.json | 5 + .../log-viewer-webui/client/public/index.html | 5 + .../log-viewer-webui/client/src/App.jsx | 10 +- .../log-viewer-webui/client/src/api/query.js | 32 + .../client/src/typings/LOCAL_STORAGE_KEY.js | 8 + .../client/src/typings/query.js | 37 + .../client/src/ui/Loading.css | 24 + .../client/src/ui/Loading.jsx | 130 ++++ .../client/src/ui/QueryStatus.jsx | 80 +++ .../log-viewer-webui/client/webpack.config.js | 8 + .../log-viewer-webui/server/src/DbManager.js | 10 +- .../server/src/routes/query.js | 26 +- .../SearchResultsTable.scss | 2 + .../SearchResultsTable/index.jsx | 59 +- components/webui/settings.json | 1 + 17 files changed, 1000 insertions(+), 108 deletions(-) create mode 100644 components/log-viewer-webui/client/src/api/query.js create mode 100644 components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js create mode 100644 components/log-viewer-webui/client/src/typings/query.js create mode 100644 components/log-viewer-webui/client/src/ui/Loading.css create mode 100644 components/log-viewer-webui/client/src/ui/Loading.jsx create mode 100644 components/log-viewer-webui/client/src/ui/QueryStatus.jsx diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 5e5965bf5..4d0d461ba 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -786,6 +786,9 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts }, "public": { "ClpStorageEngine": clp_config.package.storage_engine, + "LogViewerWebuiUrl": ( + f"http://{clp_config.log_viewer_webui.host}:{clp_config.log_viewer_webui.port}", + ), }, } meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index bf75b0710..4141c89aa 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -9,6 +9,11 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "@emotion/react": "^11.13.0", + "@emotion/styled": "^11.13.0", + "@mui/joy": "^5.0.0-beta.48", + "@types/react": "^18.3.3", + "axios": "^1.7.2", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -46,7 +51,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, "dependencies": { "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" @@ -98,7 +102,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7", "@jridgewell/gen-mapping": "^0.3.5", @@ -210,7 +213,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -222,7 +224,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, "dependencies": { "@babel/template": "^7.24.7", "@babel/types": "^7.24.7" @@ -235,7 +236,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -260,7 +260,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -373,7 +372,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, "dependencies": { "@babel/types": "^7.24.7" }, @@ -385,7 +383,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -394,7 +391,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -440,7 +436,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", @@ -455,7 +450,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -1764,7 +1758,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1776,7 +1769,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/parser": "^7.24.7", @@ -1790,7 +1782,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/generator": "^7.24.7", @@ -1811,7 +1802,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.24.7", "@babel/helper-validator-identifier": "^7.24.7", @@ -1830,6 +1820,152 @@ "node": ">=10.0.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", + "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", + "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", + "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.9.0", + "@emotion/utils": "^1.4.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.43.1", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", @@ -1962,6 +2098,40 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", + "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", + "dependencies": { + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -2072,7 +2242,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2086,7 +2255,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2095,7 +2263,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2113,14 +2280,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2186,6 +2351,228 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", + "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/joy": { + "version": "5.0.0-beta.48", + "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.48.tgz", + "integrity": "sha512-OhTvjuGl9I5IvpBr0BQyDehIW/xb2yteW6YglHJMdOb/279nItn76X1NBtPV9ImldNlBjReGwvpOXmBTTGER9w==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.16.1", + "@mui/system": "^5.16.1", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.1", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", + "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.16.4", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", + "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", + "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.16.4", + "@mui/styled-engine": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", + "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", + "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2304,6 +2691,15 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@stylistic/eslint-plugin-js": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.8.1.tgz", @@ -2503,6 +2899,16 @@ "@types/node": "*" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -2515,6 +2921,15 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -3061,7 +3476,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -3298,6 +3712,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3314,6 +3733,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-loader": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", @@ -3331,6 +3760,20 @@ "webpack": ">=5" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", @@ -3573,8 +4016,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -3613,7 +4054,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -3627,7 +4067,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -3703,11 +4142,18 @@ "node": ">=6" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -3715,8 +4161,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/colorette": { "version": "2.0.20", @@ -3724,6 +4169,17 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -3888,6 +4344,21 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3989,6 +4460,11 @@ "node": ">=4" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -4047,7 +4523,6 @@ "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4154,6 +4629,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4367,6 +4850,14 @@ "node": ">=4" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/error-stack-parser": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", @@ -4565,8 +5056,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "peer": true, "engines": { "node": ">=10" }, @@ -5435,6 +5924,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -5487,7 +5981,6 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, "funding": [ { "type": "individual", @@ -5541,6 +6034,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5584,7 +6090,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5745,7 +6250,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -5833,7 +6337,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -5894,7 +6397,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -5911,6 +6413,14 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -6169,8 +6679,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -6343,6 +6851,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", @@ -6418,7 +6931,6 @@ "version": "2.14.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", - "dev": true, "dependencies": { "hasown": "^2.0.2" }, @@ -6938,7 +7450,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -6956,8 +7467,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -7043,6 +7553,11 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -7230,7 +7745,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7239,7 +7753,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -7320,8 +7833,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -7438,8 +7950,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -7736,8 +8246,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -7759,6 +8267,23 @@ "node": ">= 18" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -7809,8 +8334,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -7847,8 +8371,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "peer": true, "engines": { "node": ">=8" } @@ -7856,8 +8378,7 @@ "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "4.0.2", @@ -8115,8 +8636,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -8145,6 +8664,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8258,9 +8782,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "peer": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-refresh": { "version": "0.14.2", @@ -8364,8 +8886,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -8474,7 +8995,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -8512,8 +9032,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -9347,11 +9865,15 @@ "webpack": "^5.27.0" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -9363,7 +9885,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -9502,7 +10023,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -10496,6 +11016,14 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index 47b2a7af3..8978b8aee 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -34,6 +34,11 @@ ] }, "dependencies": { + "@emotion/react": "^11.13.0", + "@emotion/styled": "^11.13.0", + "@mui/joy": "^5.0.0-beta.48", + "@types/react": "^18.3.3", + "axios": "^1.7.2", "react": "^18.3.1", "react-dom": "^18.3.1" } diff --git a/components/log-viewer-webui/client/public/index.html b/components/log-viewer-webui/client/public/index.html index e0646892c..c2e5d6b78 100644 --- a/components/log-viewer-webui/client/public/index.html +++ b/components/log-viewer-webui/client/public/index.html @@ -5,6 +5,11 @@ + + +
diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx index 3a6f57fff..6d7a65e45 100644 --- a/components/log-viewer-webui/client/src/App.jsx +++ b/components/log-viewer-webui/client/src/App.jsx @@ -1,3 +1,9 @@ +import {CssVarsProvider} from "@mui/joy/styles/CssVarsProvider"; + +import LOCAL_STORAGE_KEY from "./typings/LOCAL_STORAGE_KEY.js"; +import QueryStatus from "./ui/QueryStatus.jsx"; + + /** * Renders the main application. * @@ -5,7 +11,9 @@ */ const App = () => { return ( -

Hello world!

+ + + ); }; diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js new file mode 100644 index 000000000..be17d0fc8 --- /dev/null +++ b/components/log-viewer-webui/client/src/api/query.js @@ -0,0 +1,32 @@ +import axios from "axios"; + + +/** + * @typedef {object} ExtractIrResp + * @property {number} begin_msg_ix + * @property {number} end_msg_ix + * @property {string} file_split_id + * @property {boolean} is_last_ir_chunk + * @property {string} orig_file_id + * @property {string} path + * @property {string} _id + */ + +/** + * Submits a job to extract the split of an original file that contains a given log event. The file + * is extracted as a CLP IR file. + * + * @param {number|string} origFileId The ID of the original file + * @param {number} logEventIdx The index of the log event + * @param {Function} onUploadProgress Callback to handle upload progress events. + * @return {Promise>} + */ +const submitExtractIrJob = async (origFileId, logEventIdx, onUploadProgress) => { + return await axios.post( + "/query/extract-ir", + {logEventIdx, origFileId}, + {onUploadProgress} + ); +}; + +export {submitExtractIrJob}; diff --git a/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js b/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js new file mode 100644 index 000000000..c1dc19979 --- /dev/null +++ b/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js @@ -0,0 +1,8 @@ +/** + * Enum of `window.localStorage` keys. + */ +const LOCAL_STORAGE_KEY = Object.freeze({ + UI_THEME: "uiTheme", +}); + +export default LOCAL_STORAGE_KEY; diff --git a/components/log-viewer-webui/client/src/typings/query.js b/components/log-viewer-webui/client/src/typings/query.js new file mode 100644 index 000000000..b91a814f1 --- /dev/null +++ b/components/log-viewer-webui/client/src/typings/query.js @@ -0,0 +1,37 @@ +/** + * @typedef {number} QueryLoadingState + */ +let enumQueryLoadingState; +/** + * Enum of query loading state. + * + * @enum {QueryLoadingState} + */ +const QUERY_LOADING_STATES = Object.freeze({ + SUBMITTING: (enumQueryLoadingState = 0), + WAITING: ++enumQueryLoadingState, + LOADING: ++enumQueryLoadingState, +}); + +/** + * Descriptions for query loading states. + */ +const QUERY_LOADING_STATE_DESCRIPTIONS = Object.freeze({ + [QUERY_LOADING_STATES.SUBMITTING]: { + label: "Submitting query Job", + description: "Parsing arguments and submitting job to the server.", + }, + [QUERY_LOADING_STATES.WAITING]: { + label: "Waiting for job to finish", + description: "The job is running. Waiting for the job to finish.", + }, + [QUERY_LOADING_STATES.LOADING]: { + label: "Loading Log Viewer", + description: "The query has been completed and the results are being loaded.", + }, +}); + +export { + QUERY_LOADING_STATE_DESCRIPTIONS, + QUERY_LOADING_STATES, +}; diff --git a/components/log-viewer-webui/client/src/ui/Loading.css b/components/log-viewer-webui/client/src/ui/Loading.css new file mode 100644 index 000000000..d8bec1842 --- /dev/null +++ b/components/log-viewer-webui/client/src/ui/Loading.css @@ -0,0 +1,24 @@ +.loading-sheet { + height: 100%; + + display: flex; + flex-direction: column; + + align-items: center; + justify-content: center; +} + +.loading-progress-container { + width: 100%; +} + +.loading-stepper-container { + display: flex; + flex-grow: 1; + + align-items: center; +} + +.loading-stepper { + --Stepper-verticalGap: 2rem !important; +} diff --git a/components/log-viewer-webui/client/src/ui/Loading.jsx b/components/log-viewer-webui/client/src/ui/Loading.jsx new file mode 100644 index 000000000..e157d1224 --- /dev/null +++ b/components/log-viewer-webui/client/src/ui/Loading.jsx @@ -0,0 +1,130 @@ +import { + Box, + LinearProgress, + Sheet, + Step, + StepIndicator, + Stepper, + Typography, +} from "@mui/joy"; + +import { + QUERY_LOADING_STATE_DESCRIPTIONS, + QUERY_LOADING_STATES, +} from "../typings/query.js"; + +import "./Loading.css"; + + +/** + * Renders a step with a label and description. + * + * @param {object} props + * @param {string} props.description + * @param {boolean} props.isActive + * @param {boolean} props.isError + * @param {string} props.label + * @param {number | string} props.stepIndicatorText + * @return {React.ReactElement} + */ +const LoadingStep = ({ + description, + isActive, + isError, + label, + stepIndicatorText, +}) => { + let color = isActive ? + "primary" : + "neutral"; + + if (isError) { + color = "danger"; + } + + return ( + + {stepIndicatorText} + + } + > + + {label} + + + {description} + + + ); +}; + +/** + * Displays status of a pending query job. + * + * @param {object} props + * @param {QueryLoadState} props.currentState + * @param {string} props.errorMsg + * @return {React.ReactElement} + */ +const Loading = ({currentState, errorMsg}) => { + const steps = []; + Object.values(QUERY_LOADING_STATES).forEach((state) => { + const isActive = (currentState === state); + const stateDescription = QUERY_LOADING_STATE_DESCRIPTIONS[state]; + steps.push( + + ); + if (isActive && null !== errorMsg) { + steps.push( + + ); + } + }); + + return ( + <> + + + + + + + {steps} + + + + + ); +}; + +export default Loading; diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx new file mode 100644 index 000000000..d46e6b885 --- /dev/null +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -0,0 +1,80 @@ +import { + useEffect, + useRef, + useState, +} from "react"; + +import {AxiosError} from "axios"; + +import {submitExtractIrJob} from "../api/query.js"; +import {QUERY_LOADING_STATES} from "../typings/query.js"; +import Loading from "./Loading.jsx"; + + +/** + * Submits queries and renders the query states. + * + * @return {React.ReactElement} + */ +const QueryStatus = () => { + const [queryState, setQueryState] = useState(QUERY_LOADING_STATES.SUBMITTING); + const [errorMsg, setErrorMsg] = useState(null); + const isFirstRun = useRef(true); + + useEffect(() => { + if (false === isFirstRun.current) { + return; + } + isFirstRun.current = false; + + const searchParams = new URLSearchParams(window.location.search); + const origFileId = searchParams.get("origFileId"); + const logEventIdx = searchParams.get("logEventIdx"); + if (null === origFileId || null === logEventIdx) { + const error = "Either `origFileId` or `logEventIdx` are missing from the URL " + + "parameters. Note that non-IR-extraction queries are not supported at the moment."; + + console.error(error); + setErrorMsg(error); + return; + } + + submitExtractIrJob( + origFileId, + Number(logEventIdx), + () => { + setQueryState(QUERY_LOADING_STATES.WAITING); + } + ) + .then(({data}) => { + setQueryState(QUERY_LOADING_STATES.LOADING); + + const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; + window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + + `#logEventIdx=${innerLogEventNum}`; + }) + .catch((e) => { + let msg = "Unknown error."; + if (e instanceof AxiosError) { + msg = e.message; + if ("undefined" !== typeof e.response) { + if ("undefined" !== typeof e.response.data.message) { + msg = e.response.data.message; + } else { + msg = e.response.statusText; + } + } + } + console.error(msg, e); + setErrorMsg(msg); + }); + }, []); + + return ( + + ); +}; + +export default QueryStatus; diff --git a/components/log-viewer-webui/client/webpack.config.js b/components/log-viewer-webui/client/webpack.config.js index 2829b3c10..61ec64bb6 100644 --- a/components/log-viewer-webui/client/webpack.config.js +++ b/components/log-viewer-webui/client/webpack.config.js @@ -22,6 +22,14 @@ const plugins = [ ]; const config = { + devServer: { + proxy: [ + { + context: ["/"], + target: "http://localhost:3000", + }, + ], + }, devtool: isProduction ? "source-map" : "eval-source-map", diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js index ad71518a5..2cb7ef3e0 100644 --- a/components/log-viewer-webui/server/src/DbManager.js +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -131,17 +131,17 @@ class DbManager { /** * Gets the metadata for an IR file extracted from part of an original file, where the original - * file has the given ID and the extracted part contains the given message index. + * file has the given ID and the extracted part contains the given log event index. * * @param {string} origFileId - * @param {number} msgIdx + * @param {number} logEventIdx * @return {Promise} A promise that resolves to the extracted IR file's metadata. */ - async getExtractedIrFileMetadata (origFileId, msgIdx) { + async getExtractedIrFileMetadata (origFileId, logEventIdx) { return await this.#irFilesCollection.findOne({ orig_file_id: origFileId, - begin_msg_ix: {$lte: msgIdx}, - end_msg_ix: {$gt: msgIdx}, + begin_msg_ix: {$lte: logEventIdx}, + end_msg_ix: {$gt: logEventIdx}, }); } diff --git a/components/log-viewer-webui/server/src/routes/query.js b/components/log-viewer-webui/server/src/routes/query.js index 2f790ebc3..628bcd053 100644 --- a/components/log-viewer-webui/server/src/routes/query.js +++ b/components/log-viewer-webui/server/src/routes/query.js @@ -1,3 +1,6 @@ +// eslint-disable-next-line no-magic-numbers +const EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE = 128 * 1024 * 1024; + /** * Creates query routes. * @@ -7,30 +10,33 @@ */ const routes = async (fastify, options) => { fastify.post("/query/extract-ir", async (req, resp) => { - const {orig_file_id: origFileId, msg_ix: msgIdx} = req.body; - const sanitizedMsgIdx = Number(msgIdx); + const {origFileId, logEventIdx} = req.body; + const sanitizedLogEventIdx = Number(logEventIdx); - let irMetadata = - await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + let irMetadata = await fastify.dbManager.getExtractedIrFileMetadata( + origFileId, + sanitizedLogEventIdx + ); if (null === irMetadata) { const extractResult = await fastify.dbManager.submitAndWaitForExtractIrJob({ file_split_id: null, - msg_ix: sanitizedMsgIdx, + msg_ix: sanitizedLogEventIdx, orig_file_id: origFileId, - // eslint-disable-next-line no-magic-numbers - target_uncompressed_size: 128 * 1024 * 1024, + target_uncompressed_size: EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE, }); if (null === extractResult) { const err = new Error("Unable to extract IR for file with " + - `orig_file_id=${origFileId} at msg_ix=${sanitizedMsgIdx}`); + `origFileId=${origFileId} at logEventIdx=${sanitizedLogEventIdx}`); err.statusCode = 400; throw err; } - irMetadata = - await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + irMetadata = await fastify.dbManager.getExtractedIrFileMetadata( + origFileId, + sanitizedLogEventIdx + ); } return irMetadata; diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss index 6c24ec2da..db2f38117 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss @@ -27,6 +27,8 @@ } .search-results-content { + overflow: auto; + font-size: 0.875rem; line-height: var(--search-results-message-line-height); } diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 77d6af8a8..28a331bb8 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -1,3 +1,4 @@ +import {Meteor} from "meteor/meteor"; import {useEffect} from "react"; import Table from "react-bootstrap/Table"; @@ -7,6 +8,7 @@ import { faSort, faSortDown, faSortUp, + faSquareUpRight, } from "@fortawesome/free-solid-svg-icons"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; @@ -35,7 +37,7 @@ const SEARCH_RESULT_MESSAGE_LINE_HEIGHT = 1.5; * @param {boolean} props.hasMoreResultsInTotal * @param {number} props.maxLinesPerResult * @param {Function} props.onLoadMoreResults - * @param {object} props.searchResults + * @param {object[]} props.searchResults * @param {Function} props.setFieldToSortBy * @return {React.ReactElement} */ @@ -91,24 +93,9 @@ const SearchResultsTable = ({ ); }, [maxLinesPerResult]); - const rows = []; - for (let i = 0; i < searchResults.length; ++i) { - const searchResult = searchResults[i]; - rows.push( - - - {searchResult.timestamp ? - dayjs.utc(searchResult.timestamp).format(DATETIME_FORMAT_TEMPLATE) : - "N/A"} - - -
-                        {searchResult.message}
-                    
- - - ); - } + // eslint-disable-next-line no-warning-comments + // TODO: remove this flag once "Extract IR" support is added for ClpStorageEngine "clp-s" + const isExtractIrSupported = ("clp" === Meteor.settings.public.ClpStorageEngine); return (
@@ -123,7 +110,6 @@ const SearchResultsTable = ({
@@ -134,16 +120,45 @@ const SearchResultsTable = ({
Log message
+ {isExtractIrSupported && + +
 
+ } - {rows} + {searchResults.map((result) => ( + + + {result.timestamp ? + dayjs.utc(result.timestamp).format(DATETIME_FORMAT_TEMPLATE) : + "N/A"} + + +
+                                    {result.message}
+                                
+ + {isExtractIrSupported && + + + + + } + + ))} Date: Sun, 28 Jul 2024 14:30:18 -0400 Subject: [PATCH 040/114] Taskfile: Remove container OS name and version from built package name. (#497) --- Taskfile.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index f0c466e31..2eb353559 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -542,9 +542,7 @@ tasks: internal: true vars: VERSIONED_PACKAGE_NAME: - sh: | - source /etc/os-release - echo "clp-{{.FLAVOUR}}-${ID}-${VERSION_CODENAME}-$(arch)-v{{.G_PACKAGE_VERSION}}" + sh: "echo clp-{{.FLAVOUR}}-$(arch)-v{{.G_PACKAGE_VERSION}}" OUTPUT_DIR: "{{.G_BUILD_DIR}}/{{.VERSIONED_PACKAGE_NAME}}" OUTPUT_FILE: "{{.OUTPUT_DIR}}.tar.gz" requires: From c2d1e402191ba63c2f3db60724bf11ba913004d2 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Sun, 28 Jul 2024 16:53:18 -0400 Subject: [PATCH 041/114] webui: Optimize Meteor bundle size (fixes #498). (#499) --- components/webui/.meteor/packages | 26 ++++++++++------------- components/webui/.meteor/release | 2 +- components/webui/.meteor/versions | 34 ++++++++++++++----------------- components/webui/.meteorignore | 1 + 4 files changed, 28 insertions(+), 35 deletions(-) create mode 100644 components/webui/.meteorignore diff --git a/components/webui/.meteor/packages b/components/webui/.meteor/packages index 367584235..88d4b182a 100644 --- a/components/webui/.meteor/packages +++ b/components/webui/.meteor/packages @@ -4,20 +4,16 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -meteor-base@1.5.1 # Packages every Meteor app needs to have -mobile-experience@1.1.1 # Packages for a great mobile UX -mongo@1.16.8 # The database Meteor supports right now -reactive-var@1.0.12 # Reactive variable for tracker +meteor-base@1.5.1 # Packages every Meteor app needs to have +mongo@1.16.10 # The database Meteor supports right now +reactive-var@1.0.12 # Reactive variable for tracker -standard-minifier-css@1.9.2 # CSS minifier run for production mode -standard-minifier-js@2.8.1 # JS minifier run for production mode -es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers -ecmascript@0.16.8 # Enable ECMAScript2015+ syntax in app code -typescript@4.9.5 # Enable TypeScript syntax in .ts and .tsx modules -shell-server@0.5.0 # Server-side component of the `meteor shell` command -hot-module-replacement@0.5.3 # Update client in development without reloading the page +standard-minifier-css@1.9.2 # CSS minifier run for production mode +standard-minifier-js@2.8.1 # JS minifier run for production mode +ecmascript@0.16.8 # Enable ECMAScript2015+ syntax in app code +hot-module-replacement@0.5.3 # Update client in development without reloading the page -static-html@1.3.2 # Define static page content in .html files -react-meteor-data # React higher-order component for reactively tracking Meteor data -fourseven:scss -meteortesting:mocha +static-html@1.3.2 # Define static page content in .html files +react-meteor-data@2.7.2 # React higher-order component for reactively tracking Meteor data +fourseven:scss@4.16.0 # Compile Sass files with node-sass +meteortesting:mocha@2.1.0 # Testing framework diff --git a/components/webui/.meteor/release b/components/webui/.meteor/release index 966586ce5..5152abe9d 100644 --- a/components/webui/.meteor/release +++ b/components/webui/.meteor/release @@ -1 +1 @@ -METEOR@2.15 +METEOR@2.16 diff --git a/components/webui/.meteor/versions b/components/webui/.meteor/versions index 036863b05..d568e975c 100644 --- a/components/webui/.meteor/versions +++ b/components/webui/.meteor/versions @@ -4,16 +4,16 @@ babel-compiler@7.10.5 babel-runtime@1.5.1 base64@1.0.12 binary-heap@1.0.11 -blaze-tools@1.1.4 +blaze-tools@1.1.3 boilerplate-generator@1.7.2 caching-compiler@1.2.2 -caching-html-compiler@1.2.2 +caching-html-compiler@1.2.1 callback-hook@1.5.1 -check@1.3.2 +check@1.4.1 ddp@1.4.1 -ddp-client@2.6.1 -ddp-common@1.4.0 -ddp-server@2.7.0 +ddp-client@2.6.2 +ddp-common@1.4.1 +ddp-server@2.7.1 diff-sequence@1.1.2 dynamic-import@0.7.3 ecmascript@0.16.8 @@ -27,28 +27,25 @@ fourseven:scss@4.16.0 geojson-utils@1.0.11 hot-code-push@1.0.4 hot-module-replacement@0.5.3 -html-tools@1.1.4 -htmljs@1.2.1 +html-tools@1.1.3 +htmljs@1.1.1 http@1.0.10 id-map@1.1.1 inter-process-messaging@0.1.1 -launch-screen@2.0.0 -logging@1.3.3 +logging@1.3.4 meteor@1.11.5 meteor-base@1.5.1 meteortesting:browser-tests@1.4.2 meteortesting:mocha@2.1.0 meteortesting:mocha-core@8.0.1 minifier-css@1.6.4 -minifier-js@2.7.5 -minimongo@1.9.3 -mobile-experience@1.1.1 -mobile-status-bar@1.1.0 +minifier-js@2.8.0 +minimongo@1.9.4 modern-browsers@0.1.10 modules@0.20.0 modules-runtime@0.13.1 modules-runtime-hot@0.14.2 -mongo@1.16.9 +mongo@1.16.10 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 @@ -62,16 +59,15 @@ reactive-var@1.0.12 reload@1.3.1 retry@1.1.0 routepolicy@1.1.1 -shell-server@0.5.0 socket-stream-client@0.5.2 -spacebars-compiler@1.3.2 +spacebars-compiler@1.3.1 standard-minifier-css@1.9.2 standard-minifier-js@2.8.1 static-html@1.3.2 -templating-tools@1.2.3 +templating-tools@1.2.2 tracker@1.3.3 typescript@4.9.5 -underscore@1.6.1 +underscore@1.6.2 url@1.3.2 webapp@1.13.8 webapp-hashing@1.1.1 diff --git a/components/webui/.meteorignore b/components/webui/.meteorignore new file mode 100644 index 000000000..48357e9f1 --- /dev/null +++ b/components/webui/.meteorignore @@ -0,0 +1 @@ +linter From bca4c2710edc780eeb40c76fa7a922bfeff3f0e6 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Mon, 29 Jul 2024 13:32:10 -0400 Subject: [PATCH 042/114] clp-package: Add support for running package as root (fixes #500). (#464) --- .../clp_package_utils/scripts/start_clp.py | 75 ++++++++++++++++++- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 4d0d461ba..7c6de0200 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -89,6 +89,21 @@ def append_docker_port_settings_for_host_ips( cmd.append(f"{ip}:{host_port}:{container_port}") +def chown_recursively( + path: pathlib.Path, + user_id: int, + group_id: int, +): + """ + Recursively changes the owner of the given path to the given user ID and group ID. + :param path: + :param user_id: + :param group_id: + """ + chown_cmd = ["chown", "--recursive", f"{user_id}:{group_id}", str(path)] + subprocess.run(chown_cmd, stdout=subprocess.DEVNULL, check=True) + + def wait_for_container_cmd(container_name: str, cmd_to_run: [str], timeout: int): container_exec_cmd = ["docker", "exec", container_name] cmd = container_exec_cmd + cmd_to_run @@ -318,6 +333,19 @@ def start_queue(instance_id: str, clp_config: CLPConfig): DockerMount(DockerMountType.BIND, queue_logs_dir, rabbitmq_logs_dir), ] rabbitmq_pid_file_path = pathlib.Path("/") / "tmp" / "rabbitmq.pid" + + host_user_id = os.getuid() + if 0 != host_user_id: + container_user = f"{host_user_id}:{os.getgid()}" + else: + # The host user is `root` so use the container's default user and make this component's + # directories writable by that user. + # NOTE: This doesn't affect the host user's access to the directories since they're `root`. + container_user = "rabbitmq" + default_container_user_id = 999 + default_container_group_id = 999 + chown_recursively(queue_logs_dir, default_container_user_id, default_container_group_id) + # fmt: off cmd = [ "docker", "run", @@ -327,7 +355,7 @@ def start_queue(instance_id: str, clp_config: CLPConfig): # Override RABBITMQ_LOGS since the image sets it to *only* log to stdout "-e", f"RABBITMQ_LOGS={rabbitmq_logs_dir / log_filename}", "-e", f"RABBITMQ_PID_FILE={rabbitmq_pid_file_path}", - "-u", f"{os.getuid()}:{os.getgid()}", + "-u", container_user ] # fmt: on append_docker_port_settings_for_host_ips( @@ -380,13 +408,27 @@ def start_redis(instance_id: str, clp_config: CLPConfig, conf_dir: pathlib.Path) ), DockerMount(DockerMountType.BIND, redis_data_dir, pathlib.Path("/") / "data"), ] + + host_user_id = os.getuid() + if 0 != host_user_id: + container_user = f"{host_user_id}:{os.getgid()}" + else: + # The host user is `root` so use the container's default user and make this component's + # directories writable by that user. + # NOTE: This doesn't affect the host user's access to the directories since they're `root`. + container_user = "redis" + default_container_user_id = 999 + default_container_group_id = 999 + chown_recursively(redis_data_dir, default_container_user_id, default_container_group_id) + chown_recursively(redis_logs_dir, default_container_user_id, default_container_group_id) + # fmt: off cmd = [ "docker", "run", "-d", "--name", container_name, "--log-driver", "local", - "-u", f"{os.getuid()}:{os.getgid()}", + "-u", container_user, ] # fmt: on for mount in mounts: @@ -400,6 +442,19 @@ def start_redis(instance_id: str, clp_config: CLPConfig, conf_dir: pathlib.Path) cmd.append(str(config_file_path)) subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) + # fmt: off + redis_ping_cmd = [ + "redis-cli", + "-h", "127.0.0.1", + "-p", "6379", + "-a", clp_config.redis.password, + "PING" + ] + # fmt: on + + if not wait_for_container_cmd(container_name, redis_ping_cmd, 30): + raise EnvironmentError(f"{component_name} did not initialize in time") + logger.info(f"Started {component_name}.") @@ -426,13 +481,27 @@ def start_results_cache(instance_id: str, clp_config: CLPConfig, conf_dir: pathl DockerMount(DockerMountType.BIND, data_dir, pathlib.Path("/") / "data" / "db"), DockerMount(DockerMountType.BIND, logs_dir, pathlib.Path("/") / "var" / "log" / "mongodb"), ] + + host_user_id = os.getuid() + if 0 != host_user_id: + container_user = f"{host_user_id}:{os.getgid()}" + else: + # The host user is `root` so use the container's default user and make this component's + # directories writable by that user. + # NOTE: This doesn't affect the host user's access to the directories since they're `root`. + container_user = "mongodb" + default_container_user_id = 999 + default_container_group_id = 999 + chown_recursively(data_dir, default_container_user_id, default_container_group_id) + chown_recursively(logs_dir, default_container_user_id, default_container_group_id) + # fmt: off cmd = [ "docker", "run", "-d", "--name", container_name, "--log-driver", "local", - "-u", f"{os.getuid()}:{os.getgid()}", + "-u", container_user, ] # fmt: on for mount in mounts: From 09fb0b7d5fca3622523c7eadeef0bd0e2316694b Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Tue, 30 Jul 2024 01:12:55 -0400 Subject: [PATCH 043/114] regex-utils: Add support for translating regex character sets into wildcards when possible. (#493) --- .../core/src/clp/regex_utils/ErrorCode.cpp | 7 + .../core/src/clp/regex_utils/ErrorCode.hpp | 2 + .../core/src/clp/regex_utils/constants.hpp | 3 + .../regex_utils/regex_translation_utils.cpp | 154 +++++++++++++++++- components/core/tests/test-regex_utils.cpp | 43 ++++- .../dev-guide/components-core/regex-utils.md | 17 +- 6 files changed, 215 insertions(+), 11 deletions(-) diff --git a/components/core/src/clp/regex_utils/ErrorCode.cpp b/components/core/src/clp/regex_utils/ErrorCode.cpp index 112ede242..4e24e9a8b 100644 --- a/components/core/src/clp/regex_utils/ErrorCode.cpp +++ b/components/core/src/clp/regex_utils/ErrorCode.cpp @@ -72,6 +72,13 @@ auto ErrorCodeCategory::message(int ev) const -> string { case ErrorCode::UnmatchedParenthesis: return "Unmatched opening `(` or closing `)`."; + case ErrorCode::IncompleteCharsetStructure: + return "Unmatched closing `]` at the end of the string."; + + case ErrorCode::UnsupportedCharsetPattern: + return "Currently only supports character set that can be reduced to a single " + "character."; + default: return "(unrecognized error)"; } diff --git a/components/core/src/clp/regex_utils/ErrorCode.hpp b/components/core/src/clp/regex_utils/ErrorCode.hpp index 77a52cf58..9b4fbf8f2 100644 --- a/components/core/src/clp/regex_utils/ErrorCode.hpp +++ b/components/core/src/clp/regex_utils/ErrorCode.hpp @@ -21,6 +21,8 @@ enum class ErrorCode : uint8_t { IllegalDollarSign, IllegalEscapeSequence, UnmatchedParenthesis, + IncompleteCharsetStructure, + UnsupportedCharsetPattern, }; /** diff --git a/components/core/src/clp/regex_utils/constants.hpp b/components/core/src/clp/regex_utils/constants.hpp index 9833543fc..ff2eb5b10 100644 --- a/components/core/src/clp/regex_utils/constants.hpp +++ b/components/core/src/clp/regex_utils/constants.hpp @@ -44,6 +44,9 @@ constexpr auto cRegexEscapeSeqMetaCharsLut = create_char_bit_array("*+?|^$.{}[]( // The set of wildcard metacharacters that must remain escaped in the translated string to be // treated as a literal. constexpr auto cWildcardMetaCharsLut = create_char_bit_array("?*\\"); +// The set of metacharacters that can be preceded with an escape backslash in the regex character +// set to be treated as a literal. +constexpr auto cRegexCharsetEscapeSeqMetaCharsLut = create_char_bit_array("^-]\\"); } // namespace clp::regex_utils #endif // CLP_REGEX_UTILS_CONSTANTS_HPP diff --git a/components/core/src/clp/regex_utils/regex_translation_utils.cpp b/components/core/src/clp/regex_utils/regex_translation_utils.cpp index f26d70521..f1a987006 100644 --- a/components/core/src/clp/regex_utils/regex_translation_utils.cpp +++ b/components/core/src/clp/regex_utils/regex_translation_utils.cpp @@ -1,18 +1,22 @@ #include "regex_utils/regex_translation_utils.hpp" #include +#include #include #include #include #include +#include #include "regex_utils/constants.hpp" #include "regex_utils/ErrorCode.hpp" #include "regex_utils/RegexToWildcardTranslatorConfig.hpp" namespace clp::regex_utils { +using clp::string_utils::is_alphabet; using std::error_code; +using std::optional; using std::string; using std::string_view; @@ -31,6 +35,8 @@ class TranslatorState { * literally. *
  • Dot: Encountered a period `.`. Expecting wildcard expression.
  • *
  • Escaped: Encountered a backslash `\`. Expecting an escape sequence.
  • + *
  • Charset: Encountered an opening square bracket `[`. Expecting a character set.
  • + *
  • CharsetEscaped: Encountered an escape backslash in the character set.
  • *
  • End: Encountered a dollar sign `$`, meaning the regex string has reached the end * anchor.
  • * @@ -39,6 +45,8 @@ class TranslatorState { Normal = 0, Dot, Escaped, + Charset, + CharsetEscaped, End, }; @@ -48,12 +56,23 @@ class TranslatorState { // Getters [[nodiscard]] auto get_state() const -> RegexPatternState { return m_state; } + [[nodiscard]] auto get_charset_begin_it() const -> optional { + return m_charset_begin_it; + } + // Setters auto set_next_state(RegexPatternState const& state) -> void { m_state = state; } + auto set_charset_begin_it(string_view::const_iterator charset_begin_it) -> void { + m_charset_begin_it = charset_begin_it; + } + + auto invalidate_charset_begin_it() -> void { m_charset_begin_it.reset(); } + private: // Members RegexPatternState m_state{RegexPatternState::Normal}; + optional m_charset_begin_it; }; /** @@ -65,7 +84,7 @@ class TranslatorState { * @param[in, out] it The iterator that represents the current regex string scan position. May be * updated to advance or backtrack the scan position. * @param[out] wildcard_str The translated wildcard string. May or may not be updated. - * @param[in] config The translator config. + * @param[in] config The translator config predefined by the user. * @return clp::regex_utils::ErrorCode */ using StateTransitionFuncSig @@ -103,6 +122,24 @@ using StateTransitionFuncSig */ [[nodiscard]] StateTransitionFuncSig escaped_state_transition; +/** + * Reduces a regex character set into a single character so that the regex string is still + * translatable into a wildcard string. + * + * In most cases, only a trival character set containing a single character is reducable. However, + * if the output wildcard query will be analyzed in case-insensitive mode, character set patterns + * such as [aA] [Bb] are also reducable. Does not support empty charsets. + * On error, returns IncompleteCharsetStructure, UnsupportedCharsetPattern, or IllegalState. + */ +[[nodiscard]] StateTransitionFuncSig charset_state_transition; + +/** + * A transient state used to defer handling of escape sequences in a charset pattern. + * + * Allows the charset state to accurately capture the appearance of a closing bracket `]`. + */ +[[nodiscard]] StateTransitionFuncSig charset_escaped_state_transition; + /** * Disallows the appearances of other characters after encountering an end anchor in the string. */ @@ -114,6 +151,23 @@ using StateTransitionFuncSig */ [[nodiscard]] StateTransitionFuncSig final_state_cleanup; +/** + * Appends a single character as a literal to the wildcard string. + * + * If the literal is a metacharacter in the wildcard syntax, prepend the literal with an escape + * backslash. + * @param ch The literal to be appended. + * @param wildcard_str The wildcard string to be updated. + */ +auto append_char_to_wildcard(char ch, string& wildcard_str) -> void; + +/** + * @param ch0 + * @param ch1 + * @return Whether the given chars are the same, but with opposing letter cases, e.g. 'A' vs. 'a'. + */ +[[nodiscard]] auto is_same_char_opposite_case(char ch0, char ch1) -> bool; + auto normal_state_transition( TranslatorState& state, string_view::const_iterator& it, @@ -128,6 +182,10 @@ auto normal_state_transition( case cEscapeChar: state.set_next_state(TranslatorState::RegexPatternState::Escaped); break; + case '[': + state.set_charset_begin_it(it + 1); + state.set_next_state(TranslatorState::RegexPatternState::Charset); + break; case cRegexEndAnchor: state.set_next_state(TranslatorState::RegexPatternState::End); break; @@ -183,14 +241,72 @@ auto escaped_state_transition( if (false == cRegexEscapeSeqMetaCharsLut.at(ch)) { return ErrorCode::IllegalEscapeSequence; } - if (cWildcardMetaCharsLut.at(ch)) { - wildcard_str += cEscapeChar; + append_char_to_wildcard(ch, wildcard_str); + state.set_next_state(TranslatorState::RegexPatternState::Normal); + return ErrorCode::Success; +} + +auto charset_state_transition( + TranslatorState& state, + string_view::const_iterator& it, + string& wildcard_str, + RegexToWildcardTranslatorConfig const& config +) -> error_code { + auto const charset_begin_it_opt{state.get_charset_begin_it()}; + if (false == charset_begin_it_opt.has_value()) { + return ErrorCode::IllegalState; } - wildcard_str += ch; + string_view::const_iterator const charset_begin_it = charset_begin_it_opt.value(); + + auto const ch{*it}; + if (cEscapeChar == ch) { + state.set_next_state(TranslatorState::RegexPatternState::CharsetEscaped); + return ErrorCode::Success; + } + if (']' != ch) { + return ErrorCode::Success; + } + + auto const charset_len{it - charset_begin_it}; + if (0 == charset_len || charset_len > 2) { + return ErrorCode::UnsupportedCharsetPattern; + } + + auto const ch0{*charset_begin_it}; + auto const ch1{*(charset_begin_it + 1)}; + char parsed_char{}; + + if (1 == charset_len) { + if (cCharsetNegate == ch0 || cEscapeChar == ch0) { + return ErrorCode::UnsupportedCharsetPattern; + } + parsed_char = ch0; + } else { // 2 == charset_len + if (cEscapeChar == ch0 && cRegexCharsetEscapeSeqMetaCharsLut.at(ch1)) { + parsed_char = ch1; + } else if (config.case_insensitive_wildcard() && is_same_char_opposite_case(ch0, ch1)) { + parsed_char = ch0 > ch1 ? ch0 : ch1; // choose the lower case character + } else { + return ErrorCode::UnsupportedCharsetPattern; + } + } + + append_char_to_wildcard(parsed_char, wildcard_str); + state.invalidate_charset_begin_it(); state.set_next_state(TranslatorState::RegexPatternState::Normal); return ErrorCode::Success; } +auto charset_escaped_state_transition( + TranslatorState& state, + [[maybe_unused]] string_view::const_iterator& it, + [[maybe_unused]] string& wildcard_str, + [[maybe_unused]] RegexToWildcardTranslatorConfig const& config +) -> error_code { + state.set_next_state(TranslatorState::RegexPatternState::Charset); + return ErrorCode::Success; +} + auto end_state_transition( [[maybe_unused]] TranslatorState& state, string_view::const_iterator& it, @@ -215,6 +331,9 @@ auto final_state_cleanup( // multichar wildcard wildcard_str += cSingleCharWildcard; break; + case TranslatorState::RegexPatternState::Charset: + case TranslatorState::RegexPatternState::CharsetEscaped: + return ErrorCode::IncompleteCharsetStructure; default: break; } @@ -226,10 +345,27 @@ auto final_state_cleanup( } return ErrorCode::Success; } + +auto append_char_to_wildcard(char ch, string& wildcard_str) -> void { + if (cWildcardMetaCharsLut.at(ch)) { + wildcard_str += cEscapeChar; + } + wildcard_str += ch; +} + +auto is_same_char_opposite_case(char ch0, char ch1) -> bool { + int const upper_lower_case_ascii_offset{'a' - 'A'}; + return (is_alphabet(ch0) && is_alphabet(ch1) + && (((ch0 - ch1) == upper_lower_case_ascii_offset) + || ((ch1 - ch0) == upper_lower_case_ascii_offset))); +} } // namespace auto regex_to_wildcard(string_view regex_str) -> OUTCOME_V2_NAMESPACE::std_result { - return regex_to_wildcard(regex_str, {false, false}); + return regex_to_wildcard( + regex_str, + {/*case_insensitive_wildcard=*/false, /*add_prefix_suffix_wildcards=*/false} + ); } auto regex_to_wildcard(string_view regex_str, RegexToWildcardTranslatorConfig const& config) @@ -238,9 +374,9 @@ auto regex_to_wildcard(string_view regex_str, RegexToWildcardTranslatorConfig co return string{}; } - TranslatorState state; string_view::const_iterator it{regex_str.cbegin()}; string wildcard_str; + TranslatorState state; // If there is no starting anchor character, append multichar wildcard prefix if (cRegexStartAnchor == *it) { @@ -261,6 +397,12 @@ auto regex_to_wildcard(string_view regex_str, RegexToWildcardTranslatorConfig co case TranslatorState::RegexPatternState::Escaped: ec = escaped_state_transition(state, it, wildcard_str, config); break; + case TranslatorState::RegexPatternState::Charset: + ec = charset_state_transition(state, it, wildcard_str, config); + break; + case TranslatorState::RegexPatternState::CharsetEscaped: + ec = charset_escaped_state_transition(state, it, wildcard_str, config); + break; case TranslatorState::RegexPatternState::End: ec = end_state_transition(state, it, wildcard_str, config); break; diff --git a/components/core/tests/test-regex_utils.cpp b/components/core/tests/test-regex_utils.cpp index 9defd7d08..64af60318 100644 --- a/components/core/tests/test-regex_utils.cpp +++ b/components/core/tests/test-regex_utils.cpp @@ -41,9 +41,50 @@ TEST_CASE("regex_to_wildcard_escaped_metachar", "[regex_utils][re2wc][escaped_me ); } +TEST_CASE("regex_to_wildcard_charset", "[regex_utils][re2wc][charset]") { + REQUIRE((regex_to_wildcard("x[y]z").value() == "xyz")); + REQUIRE((regex_to_wildcard("x[\\^]z").value() == "x^z")); + REQUIRE((regex_to_wildcard("x[\\]]z").value() == "x]z")); + REQUIRE((regex_to_wildcard("x[-]z").value() == "x-z")); + REQUIRE((regex_to_wildcard("x[\\-]z").value() == "x-z")); + REQUIRE((regex_to_wildcard("x[\\\\]z").value() == "x\\\\z")); + REQUIRE((regex_to_wildcard("[a][b][\\^][-][\\-][\\]][\\\\][c][d]").value() == "ab^--]\\\\cd")); + + REQUIRE((regex_to_wildcard("x[]y").error() == ErrorCode::UnsupportedCharsetPattern)); + REQUIRE((regex_to_wildcard("x[a-z]y").error() == ErrorCode::UnsupportedCharsetPattern)); + REQUIRE((regex_to_wildcard("x[^^]y").error() == ErrorCode::UnsupportedCharsetPattern)); + REQUIRE((regex_to_wildcard("x[^0-9]y").error() == ErrorCode::UnsupportedCharsetPattern)); + REQUIRE((regex_to_wildcard("[xX][yY]").error() == ErrorCode::UnsupportedCharsetPattern)); + REQUIRE((regex_to_wildcard("ch:[a-zA-Z0-9]").error() == ErrorCode::UnsupportedCharsetPattern)); + + REQUIRE((regex_to_wildcard("[\\").error() == ErrorCode::IncompleteCharsetStructure)); + REQUIRE((regex_to_wildcard("[\\\\").error() == ErrorCode::IncompleteCharsetStructure)); + REQUIRE((regex_to_wildcard("[xX").error() == ErrorCode::IncompleteCharsetStructure)); + REQUIRE((regex_to_wildcard("ch:[a-zA-Z0-9").error() == ErrorCode::IncompleteCharsetStructure)); +} + +TEST_CASE("regex_to_wildcard_case_insensitive_config", "[regex_utils][re2wc][case_insensitive]") { + RegexToWildcardTranslatorConfig const config{/*case_insensitive_wildcard=*/true, false}; + REQUIRE((regex_to_wildcard("[xX][yY]", config).value() == "xy")); + REQUIRE((regex_to_wildcard("[Yy][Xx]", config).value() == "yx")); + REQUIRE((regex_to_wildcard("[aA][Bb][Cc]", config).value() == "abc")); + REQUIRE((regex_to_wildcard("[aA][Bb][\\^][-][\\]][Cc][dD]", config).value() == "ab^-]cd")); + + REQUIRE((regex_to_wildcard("[xX").error() == ErrorCode::IncompleteCharsetStructure)); + REQUIRE( + (regex_to_wildcard("[aA][Bb][^[-[\\[Cc[dD", config).error() + == ErrorCode::IncompleteCharsetStructure) + ); + REQUIRE((regex_to_wildcard("ch:[a-zA-Z0-9]").error() == ErrorCode::UnsupportedCharsetPattern)); + REQUIRE( + (regex_to_wildcard("[aA][Bb][^[-[\\[Cc[dD]", config).error() + == ErrorCode::UnsupportedCharsetPattern) + ); +} + TEST_CASE("regex_to_wildcard_anchor_config", "[regex_utils][re2wc][anchor_config]") { // Test anchors and prefix/suffix wildcards - RegexToWildcardTranslatorConfig const config{false, true}; + RegexToWildcardTranslatorConfig const config{false, /*add_prefix_suffix_wildcards=*/true}; REQUIRE(((regex_to_wildcard("^", config).value() == "*"))); REQUIRE((regex_to_wildcard("$", config).value() == "*")); REQUIRE((regex_to_wildcard("^xyz$", config).value() == "xyz")); diff --git a/docs/src/dev-guide/components-core/regex-utils.md b/docs/src/dev-guide/components-core/regex-utils.md index f7af037df..b79f0a729 100644 --- a/docs/src/dev-guide/components-core/regex-utils.md +++ b/docs/src/dev-guide/components-core/regex-utils.md @@ -77,14 +77,23 @@ For a detailed description on the options order and usage, see the * Escape sequences with alphanumeric characters are disallowed. * E.g. Special utility escape sequences `\Q`, `\E`, `\A` etc. and back references `\1` `\2` etc. cannot be translated. +* Character set + * Reduces a character set into a single character if possible. + * A trivial character set containing a single character or a single escaped metacharacter. + * E.g. `[a]` into `a`, `[\^]` into `^` + * If the `case_insensitive_wildcard` config is turned on, the translator can also reduce the + case-insensitive style character set patterns into a single lowercase character: + * E.g. `[aA]` into `a`, `[Bb]` into `b`, `[xX][Yy][zZ]` into `xyz` ### Custom configuration -The `RegexToWildcardTranslatorConfig` class objects are currently immutable once instantiated. The -constructor takes the following arguments in order: +The `RegexToWildcardTranslatorConfig` class objects are currently immutable once instantiated. By +default, all of the options are set to `false`. -* `case_insensitive_wildcard`: to be added later along with the character set translation - implementation. +The constructor takes the following option arguments in order: + +* `case_insensitive_wildcard`: see **Character set** bullet point in the + [Functionalities](#functionalities) section. * `add_prefix_suffix_wildcards`: in the absence of regex anchors, add prefix or suffix wildcards so the query becomes a substring query. From b37bcd5a13dd31e76c3f6db822250396a8c949e2 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Tue, 30 Jul 2024 18:39:13 -0400 Subject: [PATCH 044/114] core-clp: Add `EncodedTextAst` class to represent parsed and encoded unstructured text strings. (#495) --- components/core/CMakeLists.txt | 1 + .../src/clp/EncodedVariableInterpreter.cpp | 9 +-- components/core/src/clp/clg/CMakeLists.txt | 1 + components/core/src/clp/clo/CMakeLists.txt | 1 + components/core/src/clp/clp/CMakeLists.txt | 1 + components/core/src/clp/ir/EncodedTextAst.hpp | 61 +++++++++++++++++++ components/core/src/clp/ir/LogEvent.hpp | 25 +++----- .../core/src/clp/ir/LogEventDeserializer.cpp | 7 ++- .../core/tests/test-ir_encoding_methods.cpp | 2 +- 9 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 components/core/src/clp/ir/EncodedTextAst.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 19c9151bf..32dfa4d99 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -347,6 +347,7 @@ set(SOURCE_FILES_unitTest src/clp/Grep.cpp src/clp/Grep.hpp src/clp/ir/constants.hpp + src/clp/ir/EncodedTextAst.hpp src/clp/ir/LogEvent.hpp src/clp/ir/LogEventDeserializer.cpp src/clp/ir/LogEventDeserializer.hpp diff --git a/components/core/src/clp/EncodedVariableInterpreter.cpp b/components/core/src/clp/EncodedVariableInterpreter.cpp index ad7116bfe..8170f2ddc 100644 --- a/components/core/src/clp/EncodedVariableInterpreter.cpp +++ b/components/core/src/clp/EncodedVariableInterpreter.cpp @@ -234,7 +234,8 @@ void EncodedVariableInterpreter::encode_and_add_to_dictionary( size_t& raw_num_bytes ) { logtype_dict_entry.clear(); - logtype_dict_entry.reserve_constant_length(log_event.get_logtype().length()); + auto const& log_message = log_event.get_message(); + logtype_dict_entry.reserve_constant_length(log_message.get_logtype().length()); raw_num_bytes = 0; @@ -284,9 +285,9 @@ void EncodedVariableInterpreter::encode_and_add_to_dictionary( }; ffi::ir_stream::generic_decode_message( - log_event.get_logtype(), - log_event.get_encoded_vars(), - log_event.get_dict_vars(), + log_message.get_logtype(), + log_message.get_encoded_vars(), + log_message.get_dict_vars(), constant_handler, encoded_int_handler, encoded_float_handler, diff --git a/components/core/src/clp/clg/CMakeLists.txt b/components/core/src/clp/clg/CMakeLists.txt index bed6c11fc..29b805e87 100644 --- a/components/core/src/clp/clg/CMakeLists.txt +++ b/components/core/src/clp/clg/CMakeLists.txt @@ -33,6 +33,7 @@ set( ../GlobalSQLiteMetadataDB.hpp ../Grep.cpp ../Grep.hpp + ../ir/EncodedTextAst.hpp ../ir/LogEvent.hpp ../ir/parsing.cpp ../ir/parsing.hpp diff --git a/components/core/src/clp/clo/CMakeLists.txt b/components/core/src/clp/clo/CMakeLists.txt index 1eea2b5bb..d8c3fcac1 100644 --- a/components/core/src/clp/clo/CMakeLists.txt +++ b/components/core/src/clp/clo/CMakeLists.txt @@ -34,6 +34,7 @@ set( ../FileWriter.hpp ../Grep.cpp ../Grep.hpp + ../ir/EncodedTextAst.hpp ../ir/LogEvent.hpp ../ir/LogEventSerializer.cpp ../ir/LogEventSerializer.hpp diff --git a/components/core/src/clp/clp/CMakeLists.txt b/components/core/src/clp/clp/CMakeLists.txt index 0f18777d9..ada6680bd 100644 --- a/components/core/src/clp/clp/CMakeLists.txt +++ b/components/core/src/clp/clp/CMakeLists.txt @@ -41,6 +41,7 @@ set( ../GlobalSQLiteMetadataDB.cpp ../GlobalSQLiteMetadataDB.hpp ../ir/constants.hpp + ../ir/EncodedTextAst.hpp ../ir/LogEvent.hpp ../ir/LogEventDeserializer.cpp ../ir/LogEventDeserializer.hpp diff --git a/components/core/src/clp/ir/EncodedTextAst.hpp b/components/core/src/clp/ir/EncodedTextAst.hpp new file mode 100644 index 000000000..2bbf30b4d --- /dev/null +++ b/components/core/src/clp/ir/EncodedTextAst.hpp @@ -0,0 +1,61 @@ +#ifndef CLP_IR_ENCODEDTEXTAST_HPP +#define CLP_IR_ENCODEDTEXTAST_HPP + +#include +#include +#include + +#include "types.hpp" + +namespace clp::ir { +/** + * A parsed and encoded unstructured text string. + * @tparam encoded_variable_t The type of encoded variables in the string. + */ +template +class EncodedTextAst { +public: + // Constructor + explicit EncodedTextAst( + std::string logtype, + std::vector dict_vars, + std::vector encoded_vars + ) + : m_logtype{std::move(logtype)}, + m_dict_vars{std::move(dict_vars)}, + m_encoded_vars{std::move(encoded_vars)} {} + + // Disable copy constructor and assignment operator + EncodedTextAst(EncodedTextAst const&) = delete; + auto operator=(EncodedTextAst const&) -> EncodedTextAst& = delete; + + // Default move constructor and assignment operator + EncodedTextAst(EncodedTextAst&&) = default; + auto operator=(EncodedTextAst&&) -> EncodedTextAst& = default; + + // Destructor + ~EncodedTextAst() = default; + + // Methods + [[nodiscard]] auto get_logtype() const -> std::string const& { return m_logtype; } + + [[nodiscard]] auto get_dict_vars() const -> std::vector const& { + return m_dict_vars; + } + + [[nodiscard]] auto get_encoded_vars() const -> std::vector const& { + return m_encoded_vars; + } + +private: + // Variables + std::string m_logtype; + std::vector m_dict_vars; + std::vector m_encoded_vars; +}; + +using EightByteEncodedTextAst = EncodedTextAst; +using FourByteEncodedTextAst = EncodedTextAst; +} // namespace clp::ir + +#endif // CLP_IR_ENCODEDTEXTAST_HPP diff --git a/components/core/src/clp/ir/LogEvent.hpp b/components/core/src/clp/ir/LogEvent.hpp index d32aabb41..4a3ef7567 100644 --- a/components/core/src/clp/ir/LogEvent.hpp +++ b/components/core/src/clp/ir/LogEvent.hpp @@ -2,9 +2,10 @@ #define CLP_IR_LOGEVENT_HPP #include +#include #include -#include "../Defs.h" +#include "EncodedTextAst.hpp" #include "time_types.hpp" #include "types.hpp" @@ -20,38 +21,26 @@ class LogEvent { LogEvent( epoch_time_ms_t timestamp, UtcOffset utc_offset, - std::string logtype, - std::vector dict_vars, - std::vector encoded_vars + EncodedTextAst message ) : m_timestamp{timestamp}, m_utc_offset{utc_offset}, - m_logtype{std::move(logtype)}, - m_dict_vars{std::move(dict_vars)}, - m_encoded_vars{std::move(encoded_vars)} {} + m_message{std::move(message)} {} // Methods [[nodiscard]] auto get_timestamp() const -> epoch_time_ms_t { return m_timestamp; } [[nodiscard]] auto get_utc_offset() const -> UtcOffset { return m_utc_offset; } - [[nodiscard]] auto get_logtype() const -> std::string const& { return m_logtype; } - - [[nodiscard]] auto get_dict_vars() const -> std::vector const& { - return m_dict_vars; - } - - [[nodiscard]] auto get_encoded_vars() const -> std::vector const& { - return m_encoded_vars; + [[nodiscard]] auto get_message() const -> EncodedTextAst const& { + return m_message; } private: // Variables epoch_time_ms_t m_timestamp{0}; UtcOffset m_utc_offset{0}; - std::string m_logtype; - std::vector m_dict_vars; - std::vector m_encoded_vars; + EncodedTextAst m_message; }; } // namespace clp::ir diff --git a/components/core/src/clp/ir/LogEventDeserializer.cpp b/components/core/src/clp/ir/LogEventDeserializer.cpp index 9e0bf1723..6106568dd 100644 --- a/components/core/src/clp/ir/LogEventDeserializer.cpp +++ b/components/core/src/clp/ir/LogEventDeserializer.cpp @@ -8,6 +8,7 @@ #include "../ffi/ir_stream/decoding_methods.hpp" #include "../ffi/ir_stream/protocol_constants.hpp" +#include "EncodedTextAst.hpp" #include "types.hpp" namespace clp::ir { @@ -124,7 +125,11 @@ auto LogEventDeserializer::deserialize_log_event( timestamp = m_prev_msg_timestamp; } - return LogEvent{timestamp, m_utc_offset, logtype, dict_vars, encoded_vars}; + return LogEvent{ + timestamp, + m_utc_offset, + EncodedTextAst{logtype, dict_vars, encoded_vars} + }; } // Explicitly declare template specializations so that we can define the template methods in this diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index 4199428ff..e9b161b8a 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -912,7 +912,7 @@ TEMPLATE_TEST_CASE( REQUIRE(log_event.get_utc_offset() == ref_log_event.get_utc_offset()); // We only compare the logtype since decoding messages from logtype + variables is not yet // supported by our public interfaces - REQUIRE(log_event.get_logtype() == encoded_logtypes.at(log_event_idx)); + REQUIRE(log_event.get_message().get_logtype() == encoded_logtypes.at(log_event_idx)); ++log_event_idx; } auto result = log_event_deserializer.deserialize_log_event(); From a6a21852176bdfd3f5b25a1cc31349b31f933006 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:23:09 -0400 Subject: [PATCH 045/114] core: Add utilities for generating SHA256 hashes. (#491) Co-authored-by: wraymo Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/.clang-format | 2 +- components/core/CMakeLists.txt | 14 +- .../core/cmake/Modules/FindOpenSSL.cmake | 534 ------------------ components/core/src/clp/hash_utils.cpp | 223 ++++++++ components/core/src/clp/hash_utils.hpp | 77 +++ components/core/tests/test-hash_utils.cpp | 51 ++ 6 files changed, 365 insertions(+), 536 deletions(-) delete mode 100644 components/core/cmake/Modules/FindOpenSSL.cmake create mode 100644 components/core/src/clp/hash_utils.cpp create mode 100644 components/core/src/clp/hash_utils.hpp create mode 100644 components/core/tests/test-hash_utils.cpp diff --git a/components/core/.clang-format b/components/core/.clang-format index 35934f594..99a0d74ce 100644 --- a/components/core/.clang-format +++ b/components/core/.clang-format @@ -75,7 +75,7 @@ IncludeCategories: # Library headers. Update when adding new libraries. # NOTE: clang-format retains leading white-space on a line in violation of the YAML spec. - Regex: "<(absl|antlr4|archive|boost|bsoncxx|catch2|curl|date|fmt|json|log_surgeon|mariadb\ -|mongocxx|msgpack|outcome|regex_utils|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" +|mongocxx|msgpack|openssl|outcome|regex_utils|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" Priority: 3 # C system headers - Regex: "^<.+\\.h>" diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 32dfa4d99..cdc00ede3 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5.1) +cmake_minimum_required(VERSION 3.16.3) project(CLP LANGUAGES CXX C) if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) @@ -146,6 +146,14 @@ else() message(FATAL_ERROR "Could not find ${CLP_LIBS_STRING} libraries for CURL") endif() +# Find OpenSSL +find_package(OpenSSL REQUIRED) +if (OPENSSL_FOUND) + message(STATUS "Found OpenSSL (${OPENSSL_VERSION})") +else () + message(FATAL_ERROR "OpenSSL not found") +endif () + # Add log surgeon add_subdirectory(submodules/log-surgeon EXCLUDE_FROM_ALL) @@ -346,6 +354,8 @@ set(SOURCE_FILES_unitTest src/clp/GlobalSQLiteMetadataDB.hpp src/clp/Grep.cpp src/clp/Grep.hpp + src/clp/hash_utils.cpp + src/clp/hash_utils.hpp src/clp/ir/constants.hpp src/clp/ir/EncodedTextAst.hpp src/clp/ir/LogEvent.hpp @@ -465,6 +475,7 @@ set(SOURCE_FILES_unitTest tests/test-encoding_methods.cpp tests/test-ffi_SchemaTree.cpp tests/test-Grep.cpp + tests/test-hash_utils.cpp tests/test-ir_encoding_methods.cpp tests/test-ir_parsing.cpp tests/test-kql.cpp @@ -500,6 +511,7 @@ target_link_libraries(unitTest LibArchive::LibArchive MariaDBClient::MariaDBClient spdlog::spdlog + OpenSSL::Crypto ${sqlite_LIBRARY_DEPENDENCIES} ${STD_FS_LIBS} clp::regex_utils diff --git a/components/core/cmake/Modules/FindOpenSSL.cmake b/components/core/cmake/Modules/FindOpenSSL.cmake deleted file mode 100644 index 79c3b044b..000000000 --- a/components/core/cmake/Modules/FindOpenSSL.cmake +++ /dev/null @@ -1,534 +0,0 @@ -# NOTE: This is FindOpenSSL.cmake from cmake-3.16.0-rc3. It fixes issues with missing dependencies for the OpenSSL static library. -# This file should be deleted when cmake-3.16 is released. - -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -FindOpenSSL ------------ - -Find the OpenSSL encryption library. - -Optional COMPONENTS -^^^^^^^^^^^^^^^^^^^ - -This module supports two optional COMPONENTS: ``Crypto`` and ``SSL``. Both -components have associated imported targets, as described below. - -Imported Targets -^^^^^^^^^^^^^^^^ - -This module defines the following :prop_tgt:`IMPORTED` targets: - -``OpenSSL::SSL`` - The OpenSSL ``ssl`` library, if found. -``OpenSSL::Crypto`` - The OpenSSL ``crypto`` library, if found. - -Result Variables -^^^^^^^^^^^^^^^^ - -This module will set the following variables in your project: - -``OPENSSL_FOUND`` - System has the OpenSSL library. If no components are requested it only - requires the crypto library. -``OPENSSL_INCLUDE_DIR`` - The OpenSSL include directory. -``OPENSSL_CRYPTO_LIBRARY`` - The OpenSSL crypto library. -``OPENSSL_CRYPTO_LIBRARIES`` - The OpenSSL crypto library and its dependencies. -``OPENSSL_SSL_LIBRARY`` - The OpenSSL SSL library. -``OPENSSL_SSL_LIBRARIES`` - The OpenSSL SSL library and its dependencies. -``OPENSSL_LIBRARIES`` - All OpenSSL libraries and their dependencies. -``OPENSSL_VERSION`` - This is set to ``$major.$minor.$revision$patch`` (e.g. ``0.9.8s``). - -Hints -^^^^^ - -Set ``OPENSSL_ROOT_DIR`` to the root directory of an OpenSSL installation. -Set ``OPENSSL_USE_STATIC_LIBS`` to ``TRUE`` to look for static libraries. -Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib. -#]=======================================================================] - -macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library) - if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND - (("${ssl_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$") OR - ("${crypto_library}" MATCHES "\\${CMAKE_STATIC_LIBRARY_SUFFIX}$"))) - set(_OpenSSL_has_dependencies TRUE) - find_package(Threads) - else() - set(_OpenSSL_has_dependencies FALSE) - endif() -endmacro() - -function(_OpenSSL_add_dependencies libraries_var library) - if(CMAKE_THREAD_LIBS_INIT) - list(APPEND ${libraries_var} ${CMAKE_THREAD_LIBS_INIT}) - endif() - list(APPEND ${libraries_var} ${CMAKE_DL_LIBS}) - set(${libraries_var} ${${libraries_var}} PARENT_SCOPE) -endfunction() - -function(_OpenSSL_target_add_dependencies target) - if(_OpenSSL_has_dependencies) - set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads ) - set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} ) - endif() -endfunction() - -if (UNIX) - find_package(PkgConfig QUIET) - pkg_check_modules(_OPENSSL QUIET openssl) -endif () - -# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES -if(OPENSSL_USE_STATIC_LIBS) - set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) - endif() -endif() - -if (WIN32) - # http://www.slproweb.com/products/Win32OpenSSL.html - set(_OPENSSL_ROOT_HINTS - ${OPENSSL_ROOT_DIR} - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]" - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" - ENV OPENSSL_ROOT_DIR - ) - file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) - set(_OPENSSL_ROOT_PATHS - "${_programfiles}/OpenSSL" - "${_programfiles}/OpenSSL-Win32" - "${_programfiles}/OpenSSL-Win64" - "C:/OpenSSL/" - "C:/OpenSSL-Win32/" - "C:/OpenSSL-Win64/" - ) - unset(_programfiles) -else () - set(_OPENSSL_ROOT_HINTS - ${OPENSSL_ROOT_DIR} - ENV OPENSSL_ROOT_DIR - ) -endif () - -set(_OPENSSL_ROOT_HINTS_AND_PATHS - HINTS ${_OPENSSL_ROOT_HINTS} - PATHS ${_OPENSSL_ROOT_PATHS} - ) - -find_path(OPENSSL_INCLUDE_DIR - NAMES - openssl/ssl.h - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - HINTS - ${_OPENSSL_INCLUDEDIR} - PATH_SUFFIXES - include -) - -if(WIN32 AND NOT CYGWIN) - if(MSVC) - # /MD and /MDd are the standard values - if someone wants to use - # others, the libnames have to change here too - # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b - # enable OPENSSL_MSVC_STATIC_RT to get the libs build /MT (Multithreaded no-DLL) - # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix: - # * MD for dynamic-release - # * MDd for dynamic-debug - # * MT for static-release - # * MTd for static-debug - - # Implementation details: - # We are using the libraries located in the VC subdir instead of the parent directory even though : - # libeay32MD.lib is identical to ../libeay32.lib, and - # ssleay32MD.lib is identical to ../ssleay32.lib - # enable OPENSSL_USE_STATIC_LIBS to use the static libs located in lib/VC/static - - if (OPENSSL_MSVC_STATIC_RT) - set(_OPENSSL_MSVC_RT_MODE "MT") - else () - set(_OPENSSL_MSVC_RT_MODE "MD") - endif () - - # Since OpenSSL 1.1, lib names are like libcrypto32MTd.lib and libssl32MTd.lib - if( "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8" ) - set(_OPENSSL_MSVC_ARCH_SUFFIX "64") - else() - set(_OPENSSL_MSVC_ARCH_SUFFIX "32") - endif() - - if(OPENSSL_USE_STATIC_LIBS) - set(_OPENSSL_PATH_SUFFIXES - "lib/VC/static" - "VC/static" - "lib" - ) - else() - set(_OPENSSL_PATH_SUFFIXES - "lib/VC" - "VC" - "lib" - ) - endif () - - find_library(LIB_EAY_DEBUG - NAMES - libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d - libcrypto${_OPENSSL_MSVC_RT_MODE}d - libcryptod - libeay32${_OPENSSL_MSVC_RT_MODE}d - libeay32d - cryptod - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - ${_OPENSSL_PATH_SUFFIXES} - ) - - find_library(LIB_EAY_RELEASE - NAMES - libcrypto${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} - libcrypto${_OPENSSL_MSVC_RT_MODE} - libcrypto - libeay32${_OPENSSL_MSVC_RT_MODE} - libeay32 - crypto - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - ${_OPENSSL_PATH_SUFFIXES} - ) - - find_library(SSL_EAY_DEBUG - NAMES - libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE}d - libssl${_OPENSSL_MSVC_RT_MODE}d - libssld - ssleay32${_OPENSSL_MSVC_RT_MODE}d - ssleay32d - ssld - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - ${_OPENSSL_PATH_SUFFIXES} - ) - - find_library(SSL_EAY_RELEASE - NAMES - libssl${_OPENSSL_MSVC_ARCH_SUFFIX}${_OPENSSL_MSVC_RT_MODE} - libssl${_OPENSSL_MSVC_RT_MODE} - libssl - ssleay32${_OPENSSL_MSVC_RT_MODE} - ssleay32 - ssl - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - ${_OPENSSL_PATH_SUFFIXES} - ) - - set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}") - set(LIB_EAY_LIBRARY_RELEASE "${LIB_EAY_RELEASE}") - set(SSL_EAY_LIBRARY_DEBUG "${SSL_EAY_DEBUG}") - set(SSL_EAY_LIBRARY_RELEASE "${SSL_EAY_RELEASE}") - - include(SelectLibraryConfigurations) - select_library_configurations(LIB_EAY) - select_library_configurations(SSL_EAY) - - mark_as_advanced(LIB_EAY_LIBRARY_DEBUG LIB_EAY_LIBRARY_RELEASE - SSL_EAY_LIBRARY_DEBUG SSL_EAY_LIBRARY_RELEASE) - set(OPENSSL_SSL_LIBRARY ${SSL_EAY_LIBRARY} ) - set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY_LIBRARY} ) - elseif(MINGW) - # same player, for MinGW - set(LIB_EAY_NAMES crypto libeay32) - set(SSL_EAY_NAMES ssl ssleay32) - find_library(LIB_EAY - NAMES - ${LIB_EAY_NAMES} - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib/MinGW" - "lib" - ) - - find_library(SSL_EAY - NAMES - ${SSL_EAY_NAMES} - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - PATH_SUFFIXES - "lib/MinGW" - "lib" - ) - - mark_as_advanced(SSL_EAY LIB_EAY) - set(OPENSSL_SSL_LIBRARY ${SSL_EAY} ) - set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} ) - unset(LIB_EAY_NAMES) - unset(SSL_EAY_NAMES) - else() - # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues: - find_library(LIB_EAY - NAMES - libcrypto - libeay32 - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - HINTS - ${_OPENSSL_LIBDIR} - PATH_SUFFIXES - lib - ) - - find_library(SSL_EAY - NAMES - libssl - ssleay32 - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - HINTS - ${_OPENSSL_LIBDIR} - PATH_SUFFIXES - lib - ) - - mark_as_advanced(SSL_EAY LIB_EAY) - set(OPENSSL_SSL_LIBRARY ${SSL_EAY} ) - set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} ) - endif() -else() - - find_library(OPENSSL_SSL_LIBRARY - NAMES - ssl - ssleay32 - ssleay32MD - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - HINTS - ${_OPENSSL_LIBDIR} - PATH_SUFFIXES - lib - ) - - find_library(OPENSSL_CRYPTO_LIBRARY - NAMES - crypto - NAMES_PER_DIR - ${_OPENSSL_ROOT_HINTS_AND_PATHS} - HINTS - ${_OPENSSL_LIBDIR} - PATH_SUFFIXES - lib - ) - - mark_as_advanced(OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY) - -endif() - -# compat defines -set(OPENSSL_SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY}) -set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) -_OpenSSL_test_and_find_dependencies("${OPENSSL_SSL_LIBRARY}" "${OPENSSL_CRYPTO_LIBRARY}") -if(_OpenSSL_has_dependencies) - _OpenSSL_add_dependencies( OPENSSL_SSL_LIBRARIES "${OPENSSL_SSL_LIBRARY}" ) - _OpenSSL_add_dependencies( OPENSSL_CRYPTO_LIBRARIES "${OPENSSL_CRYPTO_LIBRARY}" ) -endif() - -function(from_hex HEX DEC) - string(TOUPPER "${HEX}" HEX) - set(_res 0) - string(LENGTH "${HEX}" _strlen) - - while (_strlen GREATER 0) - math(EXPR _res "${_res} * 16") - string(SUBSTRING "${HEX}" 0 1 NIBBLE) - string(SUBSTRING "${HEX}" 1 -1 HEX) - if (NIBBLE STREQUAL "A") - math(EXPR _res "${_res} + 10") - elseif (NIBBLE STREQUAL "B") - math(EXPR _res "${_res} + 11") - elseif (NIBBLE STREQUAL "C") - math(EXPR _res "${_res} + 12") - elseif (NIBBLE STREQUAL "D") - math(EXPR _res "${_res} + 13") - elseif (NIBBLE STREQUAL "E") - math(EXPR _res "${_res} + 14") - elseif (NIBBLE STREQUAL "F") - math(EXPR _res "${_res} + 15") - else() - math(EXPR _res "${_res} + ${NIBBLE}") - endif() - - string(LENGTH "${HEX}" _strlen) - endwhile() - - set(${DEC} ${_res} PARENT_SCOPE) -endfunction() - -if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h") - file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str - REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*") - - if(openssl_version_str) - # The version number is encoded as 0xMNNFFPPS: major minor fix patch status - # The status gives if this is a developer or prerelease and is ignored here. - # Major, minor, and fix directly translate into the version numbers shown in - # the string. The patch field translates to the single character suffix that - # indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so - # on. - - string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$" - "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}") - list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR) - list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR) - from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR) - list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX) - from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX) - list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH) - - if (NOT OPENSSL_VERSION_PATCH STREQUAL "00") - from_hex("${OPENSSL_VERSION_PATCH}" _tmp) - # 96 is the ASCII code of 'a' minus 1 - math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96") - unset(_tmp) - # Once anyone knows how OpenSSL would call the patch versions beyond 'z' - # this should be updated to handle that, too. This has not happened yet - # so it is simply ignored here for now. - string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING) - endif () - - set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}") - endif () -endif () - -set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARIES} ) -list(REMOVE_DUPLICATES OPENSSL_LIBRARIES) - -foreach(_comp IN LISTS OpenSSL_FIND_COMPONENTS) - if(_comp STREQUAL "Crypto") - if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND - (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR - EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR - EXISTS "${LIB_EAY_LIBRARY_RELEASE}") - ) - set(OpenSSL_${_comp}_FOUND TRUE) - else() - set(OpenSSL_${_comp}_FOUND FALSE) - endif() - elseif(_comp STREQUAL "SSL") - if(EXISTS "${OPENSSL_INCLUDE_DIR}" AND - (EXISTS "${OPENSSL_SSL_LIBRARY}" OR - EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR - EXISTS "${SSL_EAY_LIBRARY_RELEASE}") - ) - set(OpenSSL_${_comp}_FOUND TRUE) - else() - set(OpenSSL_${_comp}_FOUND FALSE) - endif() - else() - message(WARNING "${_comp} is not a valid OpenSSL component") - set(OpenSSL_${_comp}_FOUND FALSE) - endif() -endforeach() -unset(_comp) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(OpenSSL - REQUIRED_VARS - OPENSSL_CRYPTO_LIBRARY - OPENSSL_INCLUDE_DIR - VERSION_VAR - OPENSSL_VERSION - HANDLE_COMPONENTS - FAIL_MESSAGE - "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR" -) - -mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) - -if(OPENSSL_FOUND) - if(NOT TARGET OpenSSL::Crypto AND - (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR - EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR - EXISTS "${LIB_EAY_LIBRARY_RELEASE}") - ) - add_library(OpenSSL::Crypto UNKNOWN IMPORTED) - set_target_properties(OpenSSL::Crypto PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}") - if(EXISTS "${OPENSSL_CRYPTO_LIBRARY}") - set_target_properties(OpenSSL::Crypto PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}") - endif() - if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}") - set_property(TARGET OpenSSL::Crypto APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(OpenSSL::Crypto PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" - IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}") - endif() - if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}") - set_property(TARGET OpenSSL::Crypto APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(OpenSSL::Crypto PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}") - endif() - _OpenSSL_target_add_dependencies(OpenSSL::Crypto) - endif() - - if(NOT TARGET OpenSSL::SSL AND - (EXISTS "${OPENSSL_SSL_LIBRARY}" OR - EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR - EXISTS "${SSL_EAY_LIBRARY_RELEASE}") - ) - add_library(OpenSSL::SSL UNKNOWN IMPORTED) - set_target_properties(OpenSSL::SSL PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}") - if(EXISTS "${OPENSSL_SSL_LIBRARY}") - set_target_properties(OpenSSL::SSL PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}") - endif() - if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}") - set_property(TARGET OpenSSL::SSL APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(OpenSSL::SSL PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" - IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}") - endif() - if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}") - set_property(TARGET OpenSSL::SSL APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(OpenSSL::SSL PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}") - endif() - if(TARGET OpenSSL::Crypto) - set_target_properties(OpenSSL::SSL PROPERTIES - INTERFACE_LINK_LIBRARIES OpenSSL::Crypto) - endif() - _OpenSSL_target_add_dependencies(OpenSSL::SSL) - endif() -endif() - -# Restore the original find library ordering -if(OPENSSL_USE_STATIC_LIBS) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -endif() diff --git a/components/core/src/clp/hash_utils.cpp b/components/core/src/clp/hash_utils.cpp new file mode 100644 index 000000000..a70cd8ff6 --- /dev/null +++ b/components/core/src/clp/hash_utils.cpp @@ -0,0 +1,223 @@ +#include "hash_utils.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ErrorCode.hpp" +#include "TraceableException.hpp" + +using std::make_unique; +using std::span; +using std::string; +using std::unique_ptr; +using std::vector; + +namespace clp { +namespace { +/** + * Pops the first OpenSSL error from its error queue and gets its string representation. + * @return The string representing the first OpenSSL error from its error queue. + */ +auto get_openssl_error_string() -> string { + auto const openssl_err = ERR_get_error(); + if (0 == openssl_err) { + return {}; + } + auto* openssl_err_str = ERR_error_string(openssl_err, nullptr); + if (nullptr == openssl_err_str) { + return {"Error has no string representation, error_code: " + std::to_string(openssl_err)}; + } + return {openssl_err_str}; +} + +/** + * A C++ wrapper for OpenSSL's EVP message digest context (EVP_MD_CTX). + */ +class EvpDigestContext { +public: + // Types + class OperationFailed : public clp::TraceableException { + public: + // Constructors + OperationFailed(ErrorCode error_code, char const* const filename, int line_number) + : OperationFailed( + error_code, + filename, + line_number, + "EvpDigestContext operation failed" + ) {} + + OperationFailed( + ErrorCode error_code, + char const* const filename, + int line_number, + string message + ) + : TraceableException(error_code, filename, line_number), + m_message(std::move(message)) {} + + // Methods + [[nodiscard]] auto what() const noexcept -> char const* override { + return m_message.c_str(); + } + + private: + string m_message; + }; + + // Constructors + /** + * @param type The type of digest (hash algorithm). + * @throw EvpDigestContext::OperationFailed with ErrorCode_NoMem if `EVP_MD_CTX_create` fails. + * @throw EvpDigestContext::OperationFailed with ErrorCode_Failure if `EVP_DigestInit_ex` fails. + */ + explicit EvpDigestContext(EVP_MD const* type) + : m_md_ctx{EVP_MD_CTX_create()}, + m_digest_nid{EVP_MD_type(type)} { + if (nullptr == m_md_ctx) { + throw OperationFailed(ErrorCode_NoMem, __FILENAME__, __LINE__); + } + // Set impl to nullptr to use the default implementation of digest type + if (1 != EVP_DigestInit_ex(m_md_ctx, type, nullptr)) { + throw OperationFailed( + ErrorCode_Failure, + __FILENAME__, + __LINE__, + get_openssl_error_string() + ); + } + } + + // Disable copy constructor and assignment operator + EvpDigestContext(EvpDigestContext const&) = delete; + auto operator=(EvpDigestContext const&) -> EvpDigestContext& = delete; + + // Disable move constructor and assignment operator + EvpDigestContext(EvpDigestContext&&) = delete; + auto operator=(EvpDigestContext&&) -> EvpDigestContext& = delete; + + // Destructor + ~EvpDigestContext() { EVP_MD_CTX_destroy(m_md_ctx); } + + // Methods + /** + * Hashes `input` into the digest. + * @param input + * @return Whether `EVP_DigestUpdate` succeeded. + */ + [[nodiscard]] auto digest_update(span input) -> bool; + + /** + * Writes the digest into `hash` and clears the digest. + * @param hash Returns the hashing result. + * @return ErrorCode_Success on success. + * @return ErrorCode_Corrupt if `hash` has an unexpected length. + * @return ErrorCode_Failure if `EVP_DigestFinal_ex` fails. + * @throw EvpDigestContext::OperationFailed with ErrorCode_Failure if `EVP_DigestInit_ex` fails. + */ + [[nodiscard]] auto digest_final(vector& hash) -> ErrorCode; + +private: + EVP_MD_CTX* m_md_ctx{nullptr}; + int m_digest_nid{}; +}; + +auto EvpDigestContext::digest_update(span input) -> bool { + if (1 != EVP_DigestUpdate(m_md_ctx, input.data(), input.size())) { + return false; + } + return true; +} + +auto EvpDigestContext::digest_final(vector& hash) -> ErrorCode { + hash.resize(EVP_MD_CTX_size(m_md_ctx)); + unsigned int length{}; + if (1 != EVP_DigestFinal_ex(m_md_ctx, hash.data(), &length)) { + return ErrorCode_Failure; + } + if (hash.size() != length) { + return ErrorCode_Corrupt; + } + + if (1 != EVP_DigestInit_ex(m_md_ctx, EVP_get_digestbynid(m_digest_nid), nullptr)) { + throw OperationFailed( + ErrorCode_Failure, + __FILENAME__, + __LINE__, + get_openssl_error_string() + ); + } + return ErrorCode_Success; +} +} // namespace + +auto convert_to_hex_string(span input) -> string { + string hex_string; + for (auto const c : input) { + hex_string += fmt::format("{:02x}", c); + } + return hex_string; +} + +auto get_hmac_sha256_hash( + span input, + span key, + vector& hash +) -> ErrorCode { + if (key.size() > INT32_MAX) { + return ErrorCode_BadParam; + } + + hash.resize(SHA256_DIGEST_LENGTH); + unsigned int hash_length{0}; + auto const key_length{static_cast(key.size())}; + if (nullptr + == HMAC(EVP_sha256(), + key.data(), + key_length, + input.data(), + input.size(), + hash.data(), + &hash_length)) + { + return ErrorCode_Failure; + } + + if (hash.size() != hash_length) { + return ErrorCode_Corrupt; + } + + return ErrorCode_Success; +} + +auto get_sha256_hash(span input, vector& hash) -> ErrorCode { + unique_ptr evp_ctx_manager; + try { + evp_ctx_manager = make_unique(EVP_sha256()); + } catch (EvpDigestContext::OperationFailed const& err) { + throw HashUtilsOperationFailed(err.get_error_code(), __FILENAME__, __LINE__, err.what()); + } + + if (false == evp_ctx_manager->digest_update(input)) { + return ErrorCode_Failure; + } + + if (auto const error_code = evp_ctx_manager->digest_final(hash); + ErrorCode_Success != error_code) + { + return error_code; + } + + return ErrorCode_Success; +} +} // namespace clp diff --git a/components/core/src/clp/hash_utils.hpp b/components/core/src/clp/hash_utils.hpp new file mode 100644 index 000000000..4606aed23 --- /dev/null +++ b/components/core/src/clp/hash_utils.hpp @@ -0,0 +1,77 @@ +#ifndef CLP_HASH_UTILS_HPP +#define CLP_HASH_UTILS_HPP + +#include +#include +#include +#include + +#include "ErrorCode.hpp" +#include "TraceableException.hpp" + +namespace clp { +// Types +class HashUtilsOperationFailed : public TraceableException { +public: + // Constructors + HashUtilsOperationFailed(ErrorCode error_code, char const* const filename, int line_number) + : HashUtilsOperationFailed( + error_code, + filename, + line_number, + "clp::hash_utils operation failed" + ) {} + + HashUtilsOperationFailed( + ErrorCode error_code, + char const* const filename, + int line_number, + std::string message + ) + : TraceableException(error_code, filename, line_number), + m_message(std::move(message)) {} + + // Methods + [[nodiscard]] auto what() const noexcept -> char const* override { return m_message.c_str(); } + +private: + std::string m_message; +}; + +/** + * @param input + * @return `input` as a hex string (without the "0x" prefix). + */ +[[nodiscard]] auto convert_to_hex_string(std::span input) -> std::string; + +/** + * Gets the HMAC-SHA256 hash of `input` with `key`. + * @param input + * @param key + * @param hash Returns the HMAC. + * @return ErrorCode_Success on success. + * @return ErrorCode_BadParam if `key` is longer than `INT32_MAX`. + * @return ErrorCode_Failure if hash generation fails. + * @return ErrorCode_Corrupt if `hash` has an unexpected length. + */ +[[nodiscard]] auto get_hmac_sha256_hash( + std::span input, + std::span key, + std::vector& hash +) -> ErrorCode; + +/** + * Gets the SHA256 hash of `input`. + * @param input + * @param hash Returns the hash. + * @return ErrorCode_Success on success. + * @return ErrorCode_Failure if `EvpDigestContext::digest_update` fails. + * @return Same as `EvpDigestContext::digest_final` if `EvpDigestContext::digest_final` fails. + * @throw HashUtilsOperationFailed if an OpenSSL EVP digest couldn't be created. + */ +[[nodiscard]] auto get_sha256_hash( + std::span input, + std::vector& hash +) -> ErrorCode; +} // namespace clp +#endif // CLP_HASH_UTILS_HPP diff --git a/components/core/tests/test-hash_utils.cpp b/components/core/tests/test-hash_utils.cpp new file mode 100644 index 000000000..9e5aacd47 --- /dev/null +++ b/components/core/tests/test-hash_utils.cpp @@ -0,0 +1,51 @@ +#include +#include + +#include + +#include "../src/clp/ErrorCode.hpp" +#include "../src/clp/hash_utils.hpp" +#include "../src/clp/type_utils.hpp" + +using clp::convert_to_hex_string; +using clp::ErrorCode_Success; +using clp::get_hmac_sha256_hash; +using clp::get_sha256_hash; +using clp::size_checked_pointer_cast; +using std::string_view; +using std::vector; + +TEST_CASE("test_sha256", "[hash_utils]") { + constexpr string_view cInputString{"ThisIsARandomTestInput"}; + constexpr string_view cReferenceSha256{ + "c3a1d9f04ada1198c4c63bf51d9933fc2cc216429275cadabdcb2178775add0c" + }; + vector hash; + + REQUIRE(ErrorCode_Success + == get_sha256_hash( + {size_checked_pointer_cast(cInputString.data()), + cInputString.size()}, + hash + )); + REQUIRE(convert_to_hex_string(hash) == cReferenceSha256); +} + +TEST_CASE("test_hmac", "[hash_utils]") { + constexpr string_view cInputString{"ThisIsARandomTestInput"}; + constexpr string_view cInputKey{"ThisIsATestKey"}; + constexpr string_view cReferenceHmacSha256{ + "38373057694c1038a6895212bea46849eb7a59b73a2ec175883ae095fb91ffda" + }; + vector hmac_hash; + + REQUIRE(ErrorCode_Success + == get_hmac_sha256_hash( + {size_checked_pointer_cast(cInputString.data()), + cInputString.size()}, + {size_checked_pointer_cast(cInputKey.data()), + cInputKey.size()}, + hmac_hash + )); + REQUIRE(convert_to_hex_string(hmac_hash) == cReferenceHmacSha256); +} From 9d2e94d2b67d7668c30c95e8e247309a90b60ddb Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Wed, 31 Jul 2024 20:21:00 -0400 Subject: [PATCH 046/114] Taskfile: Upgrade Meteor.js version to 2.16 (fixes #505). (#506) --- Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index 2eb353559..5b818c6e1 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -498,7 +498,7 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" METEOR_ARCH: "{{ if eq ARCH \"arm64\" }}arm64{{ else }}x86_64{{ end }}" METEOR_PLATFORM: "{{ if eq OS \"darwin\" }}osx{{ else }}linux{{ end }}" - METEOR_RELEASE: "2.15" + METEOR_RELEASE: "2.16" run: "once" preconditions: - sh: >- From f38eee92b150aaac8846b302c318c6831ffa086b Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:21:30 -0400 Subject: [PATCH 047/114] core: Add unit test for LogEventSerializer. (#431) --- components/core/CMakeLists.txt | 2 + components/core/src/clp/clg/CMakeLists.txt | 1 + components/core/src/clp/clo/CMakeLists.txt | 1 + components/core/src/clp/clp/CMakeLists.txt | 1 + components/core/src/clp/ir/EncodedTextAst.cpp | 57 +++++++++ components/core/src/clp/ir/EncodedTextAst.hpp | 8 ++ components/core/tests/test-ir_serializer.cpp | 120 ++++++++++++++++++ components/core/tests/test-query_methods.cpp | 1 + 8 files changed, 191 insertions(+) create mode 100644 components/core/src/clp/ir/EncodedTextAst.cpp create mode 100644 components/core/tests/test-ir_serializer.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index cdc00ede3..70090ba30 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -357,6 +357,7 @@ set(SOURCE_FILES_unitTest src/clp/hash_utils.cpp src/clp/hash_utils.hpp src/clp/ir/constants.hpp + src/clp/ir/EncodedTextAst.cpp src/clp/ir/EncodedTextAst.hpp src/clp/ir/LogEvent.hpp src/clp/ir/LogEventDeserializer.cpp @@ -478,6 +479,7 @@ set(SOURCE_FILES_unitTest tests/test-hash_utils.cpp tests/test-ir_encoding_methods.cpp tests/test-ir_parsing.cpp + tests/test-ir_serializer.cpp tests/test-kql.cpp tests/test-main.cpp tests/test-math_utils.cpp diff --git a/components/core/src/clp/clg/CMakeLists.txt b/components/core/src/clp/clg/CMakeLists.txt index 29b805e87..a0ca5e9d0 100644 --- a/components/core/src/clp/clg/CMakeLists.txt +++ b/components/core/src/clp/clg/CMakeLists.txt @@ -33,6 +33,7 @@ set( ../GlobalSQLiteMetadataDB.hpp ../Grep.cpp ../Grep.hpp + ../ir/EncodedTextAst.cpp ../ir/EncodedTextAst.hpp ../ir/LogEvent.hpp ../ir/parsing.cpp diff --git a/components/core/src/clp/clo/CMakeLists.txt b/components/core/src/clp/clo/CMakeLists.txt index d8c3fcac1..931bffeaf 100644 --- a/components/core/src/clp/clo/CMakeLists.txt +++ b/components/core/src/clp/clo/CMakeLists.txt @@ -34,6 +34,7 @@ set( ../FileWriter.hpp ../Grep.cpp ../Grep.hpp + ../ir/EncodedTextAst.cpp ../ir/EncodedTextAst.hpp ../ir/LogEvent.hpp ../ir/LogEventSerializer.cpp diff --git a/components/core/src/clp/clp/CMakeLists.txt b/components/core/src/clp/clp/CMakeLists.txt index ada6680bd..53342f3a9 100644 --- a/components/core/src/clp/clp/CMakeLists.txt +++ b/components/core/src/clp/clp/CMakeLists.txt @@ -41,6 +41,7 @@ set( ../GlobalSQLiteMetadataDB.cpp ../GlobalSQLiteMetadataDB.hpp ../ir/constants.hpp + ../ir/EncodedTextAst.cpp ../ir/EncodedTextAst.hpp ../ir/LogEvent.hpp ../ir/LogEventDeserializer.cpp diff --git a/components/core/src/clp/ir/EncodedTextAst.cpp b/components/core/src/clp/ir/EncodedTextAst.cpp new file mode 100644 index 000000000..f0ee4d493 --- /dev/null +++ b/components/core/src/clp/ir/EncodedTextAst.cpp @@ -0,0 +1,57 @@ +#include "EncodedTextAst.hpp" + +#include +#include +#include + +#include "../ffi/encoding_methods.hpp" +#include "ffi/ir_stream/decoding_methods.hpp" + +using clp::ffi::decode_float_var; +using clp::ffi::decode_integer_var; +using clp::ffi::ir_stream::DecodingException; +using clp::ffi::ir_stream::generic_decode_message; +using std::optional; +using std::string; + +namespace clp::ir { +template +auto EncodedTextAst::decode_and_unparse() const -> optional { + string decoded_string; + + auto constant_handler = [&](string const& value, size_t begin_pos, size_t length) { + decoded_string.append(value, begin_pos, length); + }; + + auto encoded_int_handler + = [&](encoded_variable_t value) { decoded_string.append(decode_integer_var(value)); }; + + auto encoded_float_handler = [&](encoded_variable_t encoded_float) { + decoded_string.append(decode_float_var(encoded_float)); + }; + + auto dict_var_handler = [&](string const& dict_var) { decoded_string.append(dict_var); }; + + try { + generic_decode_message( + m_logtype, + m_encoded_vars, + m_dict_vars, + constant_handler, + encoded_int_handler, + encoded_float_handler, + dict_var_handler + ); + } catch (DecodingException const& e) { + return std::nullopt; + } + return std::make_optional(decoded_string); +} + +// Explicitly declare template specializations so that we can define the template methods in this +// file +template auto EncodedTextAst::decode_and_unparse( +) const -> optional; +template auto EncodedTextAst::decode_and_unparse( +) const -> optional; +} // namespace clp::ir diff --git a/components/core/src/clp/ir/EncodedTextAst.hpp b/components/core/src/clp/ir/EncodedTextAst.hpp index 2bbf30b4d..a3795ceea 100644 --- a/components/core/src/clp/ir/EncodedTextAst.hpp +++ b/components/core/src/clp/ir/EncodedTextAst.hpp @@ -1,6 +1,7 @@ #ifndef CLP_IR_ENCODEDTEXTAST_HPP #define CLP_IR_ENCODEDTEXTAST_HPP +#include #include #include #include @@ -47,6 +48,13 @@ class EncodedTextAst { return m_encoded_vars; } + /** + * Decodes and un-parses the EncodedTextAst into its string form. + * @return The string corresponding to the EncodedTextAst on success. + * @return std::nullopt if decoding fails. + */ + [[nodiscard]] auto decode_and_unparse() const -> std::optional; + private: // Variables std::string m_logtype; diff --git a/components/core/tests/test-ir_serializer.cpp b/components/core/tests/test-ir_serializer.cpp new file mode 100644 index 000000000..488f91d36 --- /dev/null +++ b/components/core/tests/test-ir_serializer.cpp @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "../src/clp/ffi/ir_stream/decoding_methods.hpp" +#include "../src/clp/ir/constants.hpp" +#include "../src/clp/ir/LogEventDeserializer.hpp" +#include "../src/clp/ir/LogEventSerializer.hpp" +#include "../src/clp/ir/types.hpp" +#include "../src/clp/streaming_compression/zstd/Decompressor.hpp" + +using clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success; +using clp::ir::cIrFileExtension; +using clp::ir::eight_byte_encoded_variable_t; +using clp::ir::epoch_time_ms_t; +using clp::ir::four_byte_encoded_variable_t; +using clp::ir::LogEventDeserializer; +using clp::ir::LogEventSerializer; +using clp::streaming_compression::zstd::Decompressor; +using std::chrono::milliseconds; +using std::chrono::system_clock; +using std::is_same_v; +using std::string; +using std::vector; + +namespace { +struct TestLogEvent { + epoch_time_ms_t timestamp; + string msg; +}; +} // namespace + +TEMPLATE_TEST_CASE( + "Encode and serialize log events", + "[ir][serialize-log-event]", + four_byte_encoded_variable_t, + eight_byte_encoded_variable_t +) { + vector test_log_events; + + auto const ts_1 = duration_cast(system_clock::now().time_since_epoch()).count(); + vector const log_event_1_tokens + = {"Here is the first string with a small int ", + "4938", + " and a medium int ", + std::to_string(INT32_MAX), + " and a very large int ", + std::to_string(INT64_MAX), + " and a small float ", + "0.1", + "\n"}; + auto const log_event_1 + = std::accumulate(log_event_1_tokens.begin(), log_event_1_tokens.end(), string("")); + test_log_events.push_back({ts_1, log_event_1}); + + auto const ts_2 = duration_cast(system_clock::now().time_since_epoch()).count(); + vector const log_event_2_tokens + = {"Here is the second string with a medium float ", + "-25.519686", + " and a high precision float ", + "-25.5196868642755", + " and a weird float ", + "-00.00", + " and a string with numbers ", + "bin/python2.7.3", + " and another string with numbers ", + "abc123", + "\n"}; + auto const log_event_2 + = std::accumulate(log_event_2_tokens.begin(), log_event_2_tokens.end(), string("")); + test_log_events.push_back({ts_2, log_event_2}); + + string ir_test_file = "ir_serializer_test"; + ir_test_file += cIrFileExtension; + + LogEventSerializer serializer; + REQUIRE(serializer.open(ir_test_file)); + // Test serializing log events + for (auto const& test_log_event : test_log_events) { + REQUIRE(serializer.serialize_log_event(test_log_event.timestamp, test_log_event.msg)); + } + serializer.close(); + + Decompressor ir_reader; + ir_reader.open(ir_test_file); + + bool uses_four_byte_encoding{false}; + REQUIRE( + (IRErrorCode_Success + == clp::ffi::ir_stream::get_encoding_type(ir_reader, uses_four_byte_encoding)) + ); + REQUIRE((is_same_v == uses_four_byte_encoding)); + + auto result = LogEventDeserializer::create(ir_reader); + REQUIRE((false == result.has_error())); + auto& deserializer = result.value(); + + // Decode and deserialize all expected log events + for (auto const& test_log_event : test_log_events) { + auto deserialized_result = deserializer.deserialize_log_event(); + REQUIRE((false == deserialized_result.has_error())); + + auto& log_event = deserialized_result.value(); + auto const decoded_message = log_event.get_message().decode_and_unparse(); + REQUIRE(decoded_message.has_value()); + + REQUIRE((decoded_message.value() == test_log_event.msg)); + REQUIRE((log_event.get_timestamp() == test_log_event.timestamp)); + } + // Try decoding a nonexistent log event + auto deserialized_result = deserializer.deserialize_log_event(); + REQUIRE(deserialized_result.has_error()); + + std::filesystem::remove(ir_test_file); +} diff --git a/components/core/tests/test-query_methods.cpp b/components/core/tests/test-query_methods.cpp index d4555ac0b..b9b54a35e 100644 --- a/components/core/tests/test-query_methods.cpp +++ b/components/core/tests/test-query_methods.cpp @@ -165,6 +165,7 @@ TEMPLATE_TEST_CASE( message += " and a very large int " + var_strs[var_ix++]; message += " and a small double " + var_strs[var_ix++]; message += " and a medium double " + var_strs[var_ix++]; + message += " and a high precison double " + var_strs[var_ix++]; message += " and a weird double " + var_strs[var_ix++]; message += " and a string with numbers " + var_strs[var_ix++]; message += " and another string with numbers " + var_strs[var_ix++]; From c3cdf669192eaab7c946ea7bff771bce27a74fb3 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:36:25 -0400 Subject: [PATCH 048/114] ffi: Add `Value` class to represent all supported primitive values for the key-value pair IR format. (#502) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 2 + components/core/src/clp/ffi/Value.hpp | 204 ++++++++++++++++++ components/core/src/clp/ir/EncodedTextAst.hpp | 2 + components/core/src/clp/type_utils.hpp | 26 +++ components/core/tests/test-ffi_Value.cpp | 187 ++++++++++++++++ 5 files changed, 421 insertions(+) create mode 100644 components/core/src/clp/ffi/Value.hpp create mode 100644 components/core/tests/test-ffi_Value.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 70090ba30..4d7eab5c4 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -339,6 +339,7 @@ set(SOURCE_FILES_unitTest src/clp/ffi/search/WildcardToken.hpp src/clp/ffi/utils.cpp src/clp/ffi/utils.hpp + src/clp/ffi/Value.hpp src/clp/FileDescriptor.cpp src/clp/FileDescriptor.hpp src/clp/FileReader.cpp @@ -475,6 +476,7 @@ set(SOURCE_FILES_unitTest tests/test-EncodedVariableInterpreter.cpp tests/test-encoding_methods.cpp tests/test-ffi_SchemaTree.cpp + tests/test-ffi_Value.cpp tests/test-Grep.cpp tests/test-hash_utils.cpp tests/test-ir_encoding_methods.cpp diff --git a/components/core/src/clp/ffi/Value.hpp b/components/core/src/clp/ffi/Value.hpp new file mode 100644 index 000000000..db719a1fb --- /dev/null +++ b/components/core/src/clp/ffi/Value.hpp @@ -0,0 +1,204 @@ +#ifndef CLP_FFI_VALUE_HPP +#define CLP_FFI_VALUE_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include "../ErrorCode.hpp" +#include "../ir/EncodedTextAst.hpp" +#include "../TraceableException.hpp" +#include "../type_utils.hpp" + +// NOTE: In this file, "primitive" doesn't refer to a C++ fundamental type (e.g. int) but instead +// refers to a value in a kv-pair that has no children (i.e. not an object/array). + +namespace clp::ffi { +using value_int_t = int64_t; +using value_float_t = double; +using value_bool_t = bool; + +/** + * Tuple of all primitive value types. + */ +using PrimitiveValueTypes = std::tuple< + value_int_t, + value_float_t, + value_bool_t, + std::string, + clp::ir::EightByteEncodedTextAst, + clp::ir::FourByteEncodedTextAst>; + +/** + * Variant for all primitive value types. + */ +using PrimitiveValueVariant = tuple_to_variant::Type; + +/** + * Template to validate whether the given type is a primitive value type. + * @tparam T + */ +template +constexpr bool cIsPrimitiveValueType = is_in_type_tuple::value; + +/** + * Concept that defines primitive value types. + */ +template +concept PrimitiveValueType = cIsPrimitiveValueType; + +/** + * Concept that defines primitive value types that are also C++ fundamental types. + */ +template +concept FundamentalPrimitiveValueType = cIsPrimitiveValueType && std::is_fundamental_v; + +/** + * Concept that defines move-constructable primitive value types. + */ +template +concept MoveConstructablePrimitiveValueType + = cIsPrimitiveValueType && std::is_move_constructible_v + && (false == std::is_fundamental_v); + +/** + * Template struct that converts a given type into an immutable view type. By default, the immutable + * view type is the given type itself, meaning that the immutable view is a copy. Specialization is + * needed when the immutable view type is a const reference or some other types. + * @tparam T + */ +template +struct ImmutableViewTypeConverter { + using Type = T; +}; + +/** + * Specializes `std::string`'s immutable view type as a `std::string_view`. + */ +template <> +struct ImmutableViewTypeConverter { + using Type = std::string_view; +}; + +/** + * Specializes `clp::ir::EightByteEncodedTextAst`'s immutable view type as its const reference. + */ +template <> +struct ImmutableViewTypeConverter { + using Type = clp::ir::EightByteEncodedTextAst const&; +}; + +/** + * Specializes `clp::ir::FourByteEncodedTextAst`'s immutable view type as its const reference. + */ +template <> +struct ImmutableViewTypeConverter { + using Type = clp::ir::FourByteEncodedTextAst const&; +}; + +/** + * Template alias to the underlying typename of `ImmutableViewTypeConverter`. + * @tparam T + */ +template +using ImmutableViewType = typename ImmutableViewTypeConverter::Type; + +class Value { +public: + // Types + class OperationFailed : public TraceableException { + public: + OperationFailed( + ErrorCode error_code, + char const* const filename, + int line_number, + std::string message + ) + : TraceableException{error_code, filename, line_number}, + m_message{std::move(message)} {} + + [[nodiscard]] auto what() const noexcept -> char const* override { + return m_message.c_str(); + } + + private: + std::string m_message; + }; + + // Constructors + Value() = default; + + /** + * Constructs a `Value` by moving the given primitive value. + * @tparam T The type of the value, which must be an rvalue to a move-constructable primitive + * value type. + * @param value + */ + template + explicit Value(T&& value) : m_value{std::forward(value)} { + static_assert(std::is_rvalue_reference_v); + } + + /** + * @tparam T The type of the given value, which must be a fundamental primitive value type. + * @param value + */ + template + explicit Value(T value) : m_value{value} {} + + // Disable copy constructor and assignment operator + Value(Value const&) = delete; + auto operator=(Value const&) -> Value& = delete; + + // Default move constructor and assignment operator + Value(Value&&) = default; + auto operator=(Value&&) -> Value& = default; + + // Destructor + ~Value() = default; + + // Methods + /** + * @tparam T + * @return Whether the underlying value is the given type. + */ + template + [[nodiscard]] auto is() const -> bool { + return std::holds_alternative(m_value); + } + + /** + * @tparam T + * @return An immutable view of the underlying value if its type matches the given type. + * @throw OperationFailed if the given type doesn't match the underlying value's type. + */ + template + [[nodiscard]] auto get_immutable_view() const -> ImmutableViewType { + if (false == is()) { + throw OperationFailed( + clp::ErrorCode_BadParam, + __FILE__, + __LINE__, + "The underlying value does not match the given type." + ); + } + return std::get(m_value); + } + + /** + * @return Whether the underlying value is null. + */ + [[nodiscard]] auto is_null() const -> bool { + return std::holds_alternative(m_value); + } + +private: + PrimitiveValueVariant m_value{std::monostate{}}; +}; +} // namespace clp::ffi + +#endif // CLP_FFI_VALUE_HPP diff --git a/components/core/src/clp/ir/EncodedTextAst.hpp b/components/core/src/clp/ir/EncodedTextAst.hpp index a3795ceea..48adb100a 100644 --- a/components/core/src/clp/ir/EncodedTextAst.hpp +++ b/components/core/src/clp/ir/EncodedTextAst.hpp @@ -38,6 +38,8 @@ class EncodedTextAst { ~EncodedTextAst() = default; // Methods + auto operator==(EncodedTextAst const&) const -> bool = default; + [[nodiscard]] auto get_logtype() const -> std::string const& { return m_logtype; } [[nodiscard]] auto get_dict_vars() const -> std::vector const& { diff --git a/components/core/src/clp/type_utils.hpp b/components/core/src/clp/type_utils.hpp index 11a3b784e..e8934490c 100644 --- a/components/core/src/clp/type_utils.hpp +++ b/components/core/src/clp/type_utils.hpp @@ -2,7 +2,9 @@ #define CLP_TYPE_UTILS_HPP #include +#include #include +#include namespace clp { /** @@ -67,6 +69,30 @@ std::enable_if_t size_checked_pointer_cast(Source* src) { return reinterpret_cast(src); } + +/** + * Template that converts a tuple of types into a variant. + * @tparam Tuple A tuple of types + */ +template +struct tuple_to_variant; + +template +struct tuple_to_variant> { + using Type = std::variant; +}; + +/** + * Template to validate if the given type is in the given tuple of types. + * @tparam Type + * @tparam Tuple + */ +template +struct is_in_type_tuple; + +template +struct is_in_type_tuple> + : std::disjunction...> {}; } // namespace clp #endif // CLP_TYPE_UTILS_HPP diff --git a/components/core/tests/test-ffi_Value.cpp b/components/core/tests/test-ffi_Value.cpp new file mode 100644 index 000000000..33764c4ff --- /dev/null +++ b/components/core/tests/test-ffi_Value.cpp @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../src/clp/ffi/encoding_methods.hpp" +#include "../src/clp/ffi/Value.hpp" +#include "../src/clp/ir/EncodedTextAst.hpp" +#include "../src/clp/ir/types.hpp" + +using clp::ffi::Value; +using clp::ffi::value_bool_t; +using clp::ffi::value_float_t; +using clp::ffi::value_int_t; +using clp::ir::eight_byte_encoded_variable_t; +using clp::ir::EightByteEncodedTextAst; +using clp::ir::four_byte_encoded_variable_t; +using clp::ir::FourByteEncodedTextAst; +using std::string; +using std::vector; + +namespace { +/** + * Parses and encodes the given string as an instance of `EncodedTextAst`. + * @tparam encoded_variable_t + * @param text + * @return The encoded result. + */ +template +requires(std::is_same_v + || std::is_same_v) +[[nodiscard]] auto get_encoded_text_ast(std::string_view text +) -> clp::ir::EncodedTextAst; + +/** + * Tests that `Value::is` returns true for the given type and false for all others. + * @tparam Type The type to query. + * @param value The value to test against. + */ +template +auto test_value_is(Value const& value) -> void; + +/** + * Tests `Value::get_immutable_view` either: + * 1. returns the expected value with the expected type for the given type and value; + * 2. throws for any other type. + * @tparam Type The type to query. + * @param value The value to test against. + * @param typed_value The typed value to compare with. + */ +template +auto test_value_get_immutable_view(Value const& value, Type const& typed_value) -> void; + +// Implementation + +template +requires(std::is_same_v + || std::is_same_v) +auto get_encoded_text_ast(std::string_view text) -> clp::ir::EncodedTextAst { + string logtype; + vector encoded_vars; + vector dict_var_bounds; + REQUIRE(clp::ffi::encode_message(text, logtype, encoded_vars, dict_var_bounds)); + REQUIRE(((dict_var_bounds.size() % 2) == 0)); + + vector dict_vars; + for (size_t i{0}; i < dict_var_bounds.size(); i += 2) { + auto const begin_pos{static_cast(dict_var_bounds[i])}; + auto const end_pos{static_cast(dict_var_bounds[i + 1])}; + dict_vars.emplace_back(text.cbegin() + begin_pos, text.cbegin() + end_pos); + } + + return clp::ir::EncodedTextAst{logtype, dict_vars, encoded_vars}; +} + +template +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +auto test_value_is(Value const& value) -> void { + REQUIRE((std::is_same_v == value.is_null())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); +} + +template +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +auto test_value_get_immutable_view(Value const& value, Type const& typed_value) -> void { + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v< + EightByteEncodedTextAst const&, + decltype(value.get_immutable_view())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v< + FourByteEncodedTextAst const&, + decltype(value.get_immutable_view())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } +} +} // namespace + +TEST_CASE("ffi_Value_basic", "[ffi][Value]") { + Value const null_value; + test_value_is(null_value); + test_value_get_immutable_view(null_value, std::monostate{}); + + constexpr value_int_t cIntVal{1000}; + Value const int_value{cIntVal}; + test_value_is(int_value); + test_value_get_immutable_view(int_value, cIntVal); + + constexpr value_float_t cFloatValue{1000.0001}; + Value const float_value{cFloatValue}; + test_value_is(float_value); + test_value_get_immutable_view(float_value, cFloatValue); + + constexpr value_bool_t cBoolVal{false}; + Value const bool_value{cBoolVal}; + test_value_is(bool_value); + test_value_get_immutable_view(bool_value, cBoolVal); + + constexpr std::string_view cStringVal{"This is a test string message"}; + Value const string_value{string{cStringVal}}; + test_value_is(string_value); + test_value_get_immutable_view(string_value, string{cStringVal}); + + constexpr std::string_view cStringToEncode{"uid=0, CPU usage: 99.99%, \"user_name\"=YScope"}; + Value const eight_byte_encoded_text_ast_value{ + get_encoded_text_ast(cStringToEncode) + }; + test_value_is(eight_byte_encoded_text_ast_value); + test_value_get_immutable_view( + eight_byte_encoded_text_ast_value, + get_encoded_text_ast(cStringToEncode) + ); + + Value const four_byte_encoded_text_ast_value{ + get_encoded_text_ast(cStringToEncode) + }; + test_value_is(four_byte_encoded_text_ast_value); + test_value_get_immutable_view( + four_byte_encoded_text_ast_value, + get_encoded_text_ast(cStringToEncode) + ); +} From f05264e88cf69735c0fbb2b173b72821df856b35 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Mon, 12 Aug 2024 10:39:36 -0400 Subject: [PATCH 049/114] clp-s: Report exactly where parsing error occurs when parsing JSON (fixes #514). (#503) --- components/core/src/clp_s/JsonParser.cpp | 42 ++++++++++++++++++------ components/core/src/clp_s/JsonParser.hpp | 1 + 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index 26ec3d7b4..a68062958 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -428,7 +428,7 @@ bool JsonParser::parse() { if (simdjson::error_code::SUCCESS != json_file_iterator.get_error()) { SPDLOG_ERROR( - "Encountered error - {} - while trying to parse {}", + "Encountered error - {} - while trying to parse {} after parsing 0 bytes", simdjson::error_message(json_file_iterator.get_error()), file_path ); @@ -439,7 +439,8 @@ bool JsonParser::parse() { simdjson::ondemand::document_stream::iterator json_it; m_num_messages = 0; - size_t last_num_bytes_consumed = 0; + size_t bytes_consumed_up_to_prev_archive = 0; + size_t bytes_consumed_up_to_prev_record = 0; while (json_file_iterator.get_json(json_it)) { m_current_schema.clear(); @@ -450,11 +451,31 @@ bool JsonParser::parse() { // that this isn't a valid JSON document but they get set in different situations so we // need to check both here. if (is_scalar_result.error() || true == is_scalar_result.value()) { - SPDLOG_ERROR("Encountered non-json-object while trying to parse {}", file_path); + SPDLOG_ERROR( + "Encountered non-json-object while trying to parse {} after parsing {} " + "bytes", + file_path, + bytes_consumed_up_to_prev_record + ); + m_archive_writer->close(); + return false; + } + + // Some errors from simdjson are latent until trying to access invalid JSON fields. + // Instead of checking for an error every time we access a JSON field in parse_line we + // just catch simdjson_error here instead. + try { + parse_line(ref.value(), -1, ""); + } catch (simdjson::simdjson_error& error) { + SPDLOG_ERROR( + "Encountered error - {} - while trying to parse {} after parsing {} bytes", + error.what(), + file_path, + bytes_consumed_up_to_prev_record + ); m_archive_writer->close(); return false; } - parse_line(ref.value(), -1, ""); m_num_messages++; int32_t current_schema_id = m_archive_writer->add_schema(m_current_schema); @@ -462,12 +483,12 @@ bool JsonParser::parse() { m_archive_writer ->append_message(current_schema_id, m_current_schema, m_current_parsed_message); + bytes_consumed_up_to_prev_record = json_file_iterator.get_num_bytes_consumed(); if (m_archive_writer->get_data_size() >= m_target_encoded_size) { - size_t num_bytes_read = json_file_iterator.get_num_bytes_consumed(); m_archive_writer->increment_uncompressed_size( - num_bytes_read - last_num_bytes_consumed + bytes_consumed_up_to_prev_record - bytes_consumed_up_to_prev_archive ); - last_num_bytes_consumed = num_bytes_read; + bytes_consumed_up_to_prev_archive = bytes_consumed_up_to_prev_record; split_archive(); } @@ -475,14 +496,15 @@ bool JsonParser::parse() { } m_archive_writer->increment_uncompressed_size( - json_file_iterator.get_num_bytes_read() - last_num_bytes_consumed + json_file_iterator.get_num_bytes_read() - bytes_consumed_up_to_prev_archive ); if (simdjson::error_code::SUCCESS != json_file_iterator.get_error()) { SPDLOG_ERROR( - "Encountered error - {} - while trying to parse {}", + "Encountered error - {} - while trying to parse {} after parsing {} bytes", simdjson::error_message(json_file_iterator.get_error()), - file_path + file_path, + bytes_consumed_up_to_prev_record ); m_archive_writer->close(); return false; diff --git a/components/core/src/clp_s/JsonParser.hpp b/components/core/src/clp_s/JsonParser.hpp index f65f4c4b1..84aa27fef 100644 --- a/components/core/src/clp_s/JsonParser.hpp +++ b/components/core/src/clp_s/JsonParser.hpp @@ -70,6 +70,7 @@ class JsonParser { * @param line the JSON line * @param parent_node_id the parent node id * @param key the key of the node + * @throw simdjson::simdjson_error when encountering invalid fields while parsing line */ void parse_line(ondemand::value line, int32_t parent_node_id, std::string const& key); From a89ff1446ef95b8d70e00e82e913e393cab91e83 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Wed, 14 Aug 2024 01:06:05 -0400 Subject: [PATCH 050/114] clp-core: Refactor FileReader to use RAII. (#496) --- components/core/src/clp/DictionaryReader.hpp | 33 ++++--- components/core/src/clp/DictionaryWriter.hpp | 94 ------------------- components/core/src/clp/FileReader.cpp | 72 ++++---------- components/core/src/clp/FileReader.hpp | 33 +------ components/core/src/clp/Utils.cpp | 68 ++++++-------- components/core/src/clp/clg/clg.cpp | 7 +- components/core/src/clp/clp/compression.cpp | 27 +++--- components/core/src/clp/dictionary_utils.cpp | 31 +----- components/core/src/clp/dictionary_utils.hpp | 12 --- .../clp/streaming_archive/reader/Archive.cpp | 4 +- .../core/tests/test-BufferedFileReader.cpp | 4 +- .../core/tests/test-MemoryMappedFile.cpp | 4 +- components/core/tests/test-NetworkReader.cpp | 8 +- .../core/tests/test-ParserWithUserSchema.cpp | 6 +- 14 files changed, 101 insertions(+), 302 deletions(-) diff --git a/components/core/src/clp/DictionaryReader.hpp b/components/core/src/clp/DictionaryReader.hpp index 0499e50eb..694240ad5 100644 --- a/components/core/src/clp/DictionaryReader.hpp +++ b/components/core/src/clp/DictionaryReader.hpp @@ -107,8 +107,8 @@ class DictionaryReader { // Variables bool m_is_open; - FileReader m_dictionary_file_reader; - FileReader m_segment_index_file_reader; + std::unique_ptr m_dictionary_file_reader; + std::unique_ptr m_segment_index_file_reader; #if USE_PASSTHROUGH_COMPRESSION streaming_compression::passthrough::Decompressor m_dictionary_decompressor; streaming_compression::passthrough::Decompressor m_segment_index_decompressor; @@ -133,14 +133,19 @@ void DictionaryReader::open( constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB - open_dictionary_for_reading( - dictionary_path, - segment_index_path, - cDecompressorFileReadBufferCapacity, - m_dictionary_file_reader, - m_dictionary_decompressor, - m_segment_index_file_reader, - m_segment_index_decompressor + m_dictionary_file_reader = make_unique(dictionary_path); + + // Skip header and then open the decompressor + m_dictionary_file_reader->seek_from_begin(sizeof(uint64_t)); + m_dictionary_decompressor.open(*m_dictionary_file_reader, cDecompressorFileReadBufferCapacity); + + m_segment_index_file_reader = make_unique(segment_index_path); + + // Skip header and then open the decompressor + m_segment_index_file_reader->seek_from_begin(sizeof(uint64_t)); + m_segment_index_decompressor.open( + *m_segment_index_file_reader, + cDecompressorFileReadBufferCapacity ); m_is_open = true; @@ -153,9 +158,9 @@ void DictionaryReader::close() { } m_segment_index_decompressor.close(); - m_segment_index_file_reader.close(); + m_segment_index_file_reader.reset(); m_dictionary_decompressor.close(); - m_dictionary_file_reader.close(); + m_dictionary_file_reader.reset(); m_num_segments_read_from_index = 0; m_entries.clear(); @@ -170,7 +175,7 @@ void DictionaryReader::read_new_entries() { } // Read dictionary header - auto num_dictionary_entries = read_dictionary_header(m_dictionary_file_reader); + auto num_dictionary_entries = read_dictionary_header(*m_dictionary_file_reader); // Validate dictionary header if (num_dictionary_entries < m_entries.size()) { @@ -190,7 +195,7 @@ void DictionaryReader::read_new_entries() { } // Read segment index header - auto num_segments = read_segment_index_header(m_segment_index_file_reader); + auto num_segments = read_segment_index_header(*m_segment_index_file_reader); // Validate segment index header if (num_segments < m_num_segments_read_from_index) { diff --git a/components/core/src/clp/DictionaryWriter.hpp b/components/core/src/clp/DictionaryWriter.hpp index e9b6f623c..9e3541913 100644 --- a/components/core/src/clp/DictionaryWriter.hpp +++ b/components/core/src/clp/DictionaryWriter.hpp @@ -3,12 +3,9 @@ #include #include -#include -#include #include "ArrayBackedPosIntSet.hpp" #include "Defs.h" -#include "dictionary_utils.hpp" #include "FileWriter.hpp" #include "spdlog_with_specializations.hpp" #include "streaming_compression/passthrough/Compressor.hpp" @@ -63,18 +60,6 @@ class DictionaryWriter { */ void write_header_and_flush_to_disk(); - /** - * Opens dictionary, loads entries, and then sets it up for writing - * @param dictionary_path - * @param segment_index_path - * @param max_id - */ - void open_and_preload( - std::string const& dictionary_path, - std::string const& segment_index_path, - variable_dictionary_id_t max_id - ); - /** * Adds the given segment and IDs to the segment index * @param segment_id @@ -191,85 +176,6 @@ void DictionaryWriter::write_header_and_flush_to_di m_dictionary_file_writer.flush(); } -template -void DictionaryWriter::open_and_preload( - std::string const& dictionary_path, - std::string const& segment_index_path, - variable_dictionary_id_t const max_id -) { - if (m_is_open) { - throw OperationFailed(ErrorCode_NotReady, __FILENAME__, __LINE__); - } - - m_max_id = max_id; - - FileReader dictionary_file_reader; - FileReader segment_index_file_reader; -#if USE_PASSTHROUGH_COMPRESSION - streaming_compression::passthrough::Decompressor dictionary_decompressor; - streaming_compression::passthrough::Decompressor segment_index_decompressor; -#elif USE_ZSTD_COMPRESSION - streaming_compression::zstd::Decompressor dictionary_decompressor; - streaming_compression::zstd::Decompressor segment_index_decompressor; -#else - static_assert(false, "Unsupported compression mode."); -#endif - constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB - open_dictionary_for_reading( - dictionary_path, - segment_index_path, - cDecompressorFileReadBufferCapacity, - dictionary_file_reader, - dictionary_decompressor, - segment_index_file_reader, - segment_index_decompressor - ); - - auto num_dictionary_entries = read_dictionary_header(dictionary_file_reader); - if (num_dictionary_entries > m_max_id) { - SPDLOG_ERROR("DictionaryWriter ran out of IDs."); - throw OperationFailed(ErrorCode_OutOfBounds, __FILENAME__, __LINE__); - } - // Loads entries from the given dictionary file - EntryType entry; - for (size_t i = 0; i < num_dictionary_entries; ++i) { - entry.clear(); - entry.read_from_file(dictionary_decompressor); - auto const& str_value = entry.get_value(); - if (m_value_to_id.count(str_value)) { - SPDLOG_ERROR("Entry's value already exists in dictionary"); - throw OperationFailed(ErrorCode_Corrupt, __FILENAME__, __LINE__); - } - - m_value_to_id[str_value] = entry.get_id(); - ; - m_data_size += entry.get_data_size(); - } - - m_next_id = num_dictionary_entries; - - segment_index_decompressor.close(); - segment_index_file_reader.close(); - dictionary_decompressor.close(); - dictionary_file_reader.close(); - - m_dictionary_file_writer.open( - dictionary_path, - FileWriter::OpenMode::CREATE_IF_NONEXISTENT_FOR_SEEKABLE_WRITING - ); - // Open compressor - m_dictionary_compressor.open(m_dictionary_file_writer); - - m_segment_index_file_writer.open( - segment_index_path, - FileWriter::OpenMode::CREATE_IF_NONEXISTENT_FOR_SEEKABLE_WRITING - ); - // Open compressor - m_segment_index_compressor.open(m_segment_index_file_writer); - - m_is_open = true; -} - template void DictionaryWriter::index_segment( segment_id_t segment_id, diff --git a/components/core/src/clp/FileReader.cpp b/components/core/src/clp/FileReader.cpp index 06a986383..8a51b1827 100644 --- a/components/core/src/clp/FileReader.cpp +++ b/components/core/src/clp/FileReader.cpp @@ -12,15 +12,26 @@ using std::string; namespace clp { +FileReader::FileReader(string const& path) : m_file{fopen(path.c_str(), "rb")} { + if (nullptr == m_file) { + if (ENOENT == errno) { + throw OperationFailed(ErrorCode_FileNotFound, __FILE__, __LINE__); + } + throw OperationFailed(ErrorCode_errno, __FILE__, __LINE__); + } + m_path = path; +} + FileReader::~FileReader() { - close(); + if (nullptr != m_file) { + // NOTE: We don't check errors for fclose since it seems the only reason it could fail is + // if it was interrupted by a signal + fclose(m_file); + } free(m_getdelim_buf); } ErrorCode FileReader::try_read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) { - if (nullptr == m_file) { - return ErrorCode_NotInit; - } if (nullptr == buf) { return ErrorCode_BadParam; } @@ -40,10 +51,6 @@ ErrorCode FileReader::try_read(char* buf, size_t num_bytes_to_read, size_t& num_ } ErrorCode FileReader::try_seek_from_begin(size_t pos) { - if (nullptr == m_file) { - return ErrorCode_NotInit; - } - int retval = fseeko(m_file, pos, SEEK_SET); if (0 != retval) { return ErrorCode_errno; @@ -53,10 +60,6 @@ ErrorCode FileReader::try_seek_from_begin(size_t pos) { } ErrorCode FileReader::try_get_pos(size_t& pos) { - if (nullptr == m_file) { - return ErrorCode_NotInit; - } - pos = ftello(m_file); if ((off_t)-1 == pos) { return ErrorCode_errno; @@ -65,49 +68,14 @@ ErrorCode FileReader::try_get_pos(size_t& pos) { return ErrorCode_Success; } -ErrorCode FileReader::try_open(string const& path) { - // Cleanup in case caller forgot to call close before calling this function - close(); - - m_file = fopen(path.c_str(), "rb"); - if (nullptr == m_file) { - if (ENOENT == errno) { - return ErrorCode_FileNotFound; - } - return ErrorCode_errno; - } - m_path = path; - - return ErrorCode_Success; -} - -void FileReader::open(string const& path) { - ErrorCode error_code = try_open(path); - if (ErrorCode_Success != error_code) { - if (ErrorCode_FileNotFound == error_code) { - throw "File not found: " + boost::filesystem::weakly_canonical(path).string() + "\n"; - } else { - throw OperationFailed(error_code, __FILENAME__, __LINE__); - } - } -} - -void FileReader::close() { - if (m_file != nullptr) { - // NOTE: We don't check errors for fclose since it seems the only reason it could fail is if - // it was interrupted by a signal - fclose(m_file); - m_file = nullptr; - } -} - ErrorCode FileReader::try_read_to_delimiter(char delim, bool keep_delimiter, bool append, string& str) { - assert(nullptr != m_file); - if (false == append) { str.clear(); } + + // NOTE: If `m_getdelim_buf` is a null pointer or if `m_getdelim_buf_len` is insufficient in + // size, `getdelim` will malloc or realloc enough memory, respectively, to hold the characters. ssize_t num_bytes_read = getdelim(&m_getdelim_buf, &m_getdelim_buf_len, delim, m_file); if (num_bytes_read < 1) { if (ferror(m_file)) { @@ -125,10 +93,6 @@ FileReader::try_read_to_delimiter(char delim, bool keep_delimiter, bool append, } ErrorCode FileReader::try_fstat(struct stat& stat_buffer) { - if (nullptr == m_file) { - throw OperationFailed(ErrorCode_NotInit, __FILENAME__, __LINE__); - } - auto return_value = fstat(fileno(m_file), &stat_buffer); if (0 != return_value) { return ErrorCode_errno; diff --git a/components/core/src/clp/FileReader.hpp b/components/core/src/clp/FileReader.hpp index 56e376af6..269297cf3 100644 --- a/components/core/src/clp/FileReader.hpp +++ b/components/core/src/clp/FileReader.hpp @@ -25,7 +25,7 @@ class FileReader : public ReaderInterface { char const* what() const noexcept override { return "FileReader operation failed"; } }; - FileReader() : m_file(nullptr), m_getdelim_buf_len(0), m_getdelim_buf(nullptr) {} + FileReader(std::string const& path); ~FileReader(); @@ -33,7 +33,6 @@ class FileReader : public ReaderInterface { /** * Tries to get the current position of the read head in the file * @param pos Position of the read head in the file - * @return ErrorCode_NotInit if the file is not open * @return ErrorCode_errno on error * @return ErrorCode_Success on success */ @@ -41,7 +40,6 @@ class FileReader : public ReaderInterface { /** * Tries to seek from the beginning of the file to the given position * @param pos - * @return ErrorCode_NotInit if the file is not open * @return ErrorCode_errno on error * @return ErrorCode_Success on success */ @@ -52,7 +50,6 @@ class FileReader : public ReaderInterface { * @param buf * @param num_bytes_to_read The number of bytes to try and read * @param num_bytes_read The actual number of bytes read - * @return ErrorCode_NotInit if the file is not open * @return ErrorCode_BadParam if buf is invalid * @return ErrorCode_errno on error * @return ErrorCode_EndOfFile on EOF @@ -73,28 +70,6 @@ class FileReader : public ReaderInterface { ErrorCode try_read_to_delimiter(char delim, bool keep_delimiter, bool append, std::string& str) override; - // Methods - bool is_open() const { return m_file != nullptr; } - - /** - * Tries to open a file - * @param path - * @return ErrorCode_Success on success - * @return ErrorCode_FileNotFound if the file was not found - * @return ErrorCode_errno otherwise - */ - ErrorCode try_open(std::string const& path); - /** - * Opens a file - * @param path - * @throw FileReader::OperationFailed on failure - */ - void open(std::string const& path); - /** - * Closes the file if it's open - */ - void close(); - [[nodiscard]] std::string const& get_path() const { return m_path; } /** @@ -106,9 +81,9 @@ class FileReader : public ReaderInterface { ErrorCode try_fstat(struct stat& stat_buffer); private: - FILE* m_file; - size_t m_getdelim_buf_len; - char* m_getdelim_buf; + FILE* m_file{nullptr}; + size_t m_getdelim_buf_len{0}; + char* m_getdelim_buf{nullptr}; std::string m_path; }; } // namespace clp diff --git a/components/core/src/clp/Utils.cpp b/components/core/src/clp/Utils.cpp index 1a45c5bf9..f487a3880 100644 --- a/components/core/src/clp/Utils.cpp +++ b/components/core/src/clp/Utils.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -17,7 +18,9 @@ #include "spdlog_with_specializations.hpp" using std::list; +using std::make_unique; using std::string; +using std::unique_ptr; using std::vector; namespace clp { @@ -137,16 +140,18 @@ string get_unambiguous_path(string const& path) { } ErrorCode read_list_of_paths(string const& list_path, vector& paths) { - FileReader file_reader; - ErrorCode error_code = file_reader.try_open(list_path); - if (ErrorCode_Success != error_code) { - return error_code; + unique_ptr file_reader; + try { + file_reader = make_unique(list_path); + } catch (FileReader::OperationFailed const& err) { + return err.get_error_code(); } // Read file string line; + ErrorCode error_code{ErrorCode_Success}; while (true) { - error_code = file_reader.try_read_to_delimiter('\n', false, false, line); + error_code = file_reader->try_read_to_delimiter('\n', false, false, line); if (ErrorCode_Success != error_code) { break; } @@ -160,8 +165,6 @@ ErrorCode read_list_of_paths(string const& list_path, vector& paths) { return error_code; } - file_reader.close(); - return ErrorCode_Success; } @@ -262,38 +265,29 @@ void load_lexer_from_file( } if (contains_delimiter) { - FileReader schema_reader; - ErrorCode error_code = schema_reader.try_open(schema_ast->m_file_path); - if (ErrorCode_Success != error_code) { - throw std::runtime_error( - schema_file_path + ":" + std::to_string(rule->m_line_num + 1) + ": error: '" - + rule->m_name + "' has regex pattern which contains delimiter '" - + char(delimiter_name) + "'.\n" - ); - } else { - // more detailed debugging based on looking at the file - string line; - for (uint32_t i = 0; i <= rule->m_line_num; i++) { - schema_reader.read_to_delimiter('\n', false, false, line); - } - int colon_pos = 0; - for (char i : line) { - colon_pos++; - if (i == ':') { - break; - } + FileReader schema_reader{schema_ast->m_file_path}; + // more detailed debugging based on looking at the file + string line; + for (uint32_t i = 0; i <= rule->m_line_num; i++) { + schema_reader.read_to_delimiter('\n', false, false, line); + } + int colon_pos = 0; + for (char i : line) { + colon_pos++; + if (i == ':') { + break; } - string indent(10, ' '); - string spaces(colon_pos, ' '); - string arrows(line.size() - colon_pos, '^'); - - throw std::runtime_error( - schema_file_path + ":" + std::to_string(rule->m_line_num + 1) + ": error: '" - + rule->m_name + "' has regex pattern which contains delimiter '" - + char(delimiter_name) + "'.\n" + indent + line + "\n" + indent + spaces - + arrows + "\n" - ); } + string indent(10, ' '); + string spaces(colon_pos, ' '); + string arrows(line.size() - colon_pos, '^'); + + throw std::runtime_error( + schema_file_path + ":" + std::to_string(rule->m_line_num + 1) + ": error: '" + + rule->m_name + "' has regex pattern which contains delimiter '" + + char(delimiter_name) + "'.\n" + indent + line + "\n" + indent + spaces + + arrows + "\n" + ); } lexer.add_rule(lexer.m_symbol_id[rule->m_name], std::move(rule->m_regex_ptr)); } diff --git a/components/core/src/clp/clg/clg.cpp b/components/core/src/clp/clg/clg.cpp index 4580358b7..dd35a3283 100644 --- a/components/core/src/clp/clg/clg.cpp +++ b/components/core/src/clp/clg/clg.cpp @@ -494,15 +494,13 @@ int main(int argc, char const* argv[]) { if (command_line_args.get_search_strings_file_path().empty()) { search_strings.push_back(command_line_args.get_search_string()); } else { - FileReader file_reader; - file_reader.open(command_line_args.get_search_strings_file_path()); + FileReader file_reader{command_line_args.get_search_strings_file_path()}; string line; while (file_reader.read_to_delimiter('\n', false, false, line)) { if (!line.empty()) { search_strings.push_back(line); } } - file_reader.close(); } // Validate archives directory @@ -589,8 +587,7 @@ int main(int argc, char const* argv[]) { use_heuristic = false; char buf[max_map_schema_length]; - FileReader file_reader; - file_reader.try_open(schema_file_path); + FileReader file_reader{schema_file_path}; size_t num_bytes_read; file_reader.read(buf, max_map_schema_length, num_bytes_read); diff --git a/components/core/src/clp/clp/compression.cpp b/components/core/src/clp/clp/compression.cpp index 1741557bc..a0d5bf276 100644 --- a/components/core/src/clp/clp/compression.cpp +++ b/components/core/src/clp/clp/compression.cpp @@ -1,6 +1,7 @@ #include "compression.hpp" #include +#include #include #include @@ -19,8 +20,10 @@ using clp::streaming_archive::writer::split_archive; using std::cerr; using std::cout; using std::endl; +using std::make_unique; using std::out_of_range; using std::string; +using std::unique_ptr; using std::vector; namespace clp::clp { @@ -192,9 +195,11 @@ bool read_and_validate_grouped_file_list( string const& list_path, vector& grouped_files ) { - FileReader grouped_file_path_reader; - ErrorCode error_code = grouped_file_path_reader.try_open(list_path); - if (ErrorCode_Success != error_code) { + unique_ptr grouped_file_path_reader; + try { + grouped_file_path_reader = make_unique(list_path); + } catch (FileReader::OperationFailed const& exception) { + auto const error_code = exception.get_error_code(); if (ErrorCode_FileNotFound == error_code) { SPDLOG_ERROR("'{}' does not exist.", list_path.c_str()); } else if (ErrorCode_errno == error_code) { @@ -205,10 +210,12 @@ bool read_and_validate_grouped_file_list( return false; } - FileReader grouped_file_id_reader; + unique_ptr grouped_file_id_reader; string grouped_file_ids_path = list_path.substr(0, list_path.length() - 4) + ".gid"; - error_code = grouped_file_id_reader.try_open(grouped_file_ids_path); - if (ErrorCode_Success != error_code) { + try { + grouped_file_id_reader = make_unique(grouped_file_ids_path); + } catch (FileReader::OperationFailed const& exception) { + auto const error_code = exception.get_error_code(); if (ErrorCode_FileNotFound == error_code) { SPDLOG_ERROR("'{}' does not exist.", grouped_file_ids_path.c_str()); } else if (ErrorCode_errno == error_code) { @@ -228,9 +235,10 @@ bool read_and_validate_grouped_file_list( string path; string path_without_prefix; group_id_t group_id; + ErrorCode error_code{ErrorCode_Success}; while (true) { // Read path - error_code = grouped_file_path_reader.try_read_to_delimiter('\n', false, false, path); + error_code = grouped_file_path_reader->try_read_to_delimiter('\n', false, false, path); if (ErrorCode_Success != error_code) { break; } @@ -242,7 +250,7 @@ bool read_and_validate_grouped_file_list( } // Read group ID - error_code = grouped_file_id_reader.try_read_numeric_value(group_id); + error_code = grouped_file_id_reader->try_read_numeric_value(group_id); if (ErrorCode_Success != error_code) { if (ErrorCode_EndOfFile == error_code) { SPDLOG_ERROR("There are more grouped file paths than IDs."); @@ -294,9 +302,6 @@ bool read_and_validate_grouped_file_list( return false; } - grouped_file_path_reader.close(); - grouped_file_id_reader.close(); - // Validate the list contained at least one file if (grouped_files.empty()) { SPDLOG_ERROR("'{}' did not contain any paths.", list_path.c_str()); diff --git a/components/core/src/clp/dictionary_utils.cpp b/components/core/src/clp/dictionary_utils.cpp index 2fecd7e04..d8bd20a9a 100644 --- a/components/core/src/clp/dictionary_utils.cpp +++ b/components/core/src/clp/dictionary_utils.cpp @@ -1,35 +1,12 @@ #include "dictionary_utils.hpp" -namespace clp { -void open_dictionary_for_reading( - std::string const& dictionary_path, - std::string const& segment_index_path, - size_t decompressor_file_read_buffer_capacity, - FileReader& dictionary_file_reader, - streaming_compression::Decompressor& dictionary_decompressor, - FileReader& segment_index_file_reader, - streaming_compression::Decompressor& segment_index_decompressor -) { - dictionary_file_reader.open(dictionary_path); - // Skip header - dictionary_file_reader.seek_from_begin(sizeof(uint64_t)); - // Open decompressor - dictionary_decompressor.open(dictionary_file_reader, decompressor_file_read_buffer_capacity); - - segment_index_file_reader.open(segment_index_path); - // Skip header - segment_index_file_reader.seek_from_begin(sizeof(uint64_t)); - // Open decompressor - segment_index_decompressor.open( - segment_index_file_reader, - decompressor_file_read_buffer_capacity - ); -} +#include "FileReader.hpp" +namespace clp { uint64_t read_dictionary_header(FileReader& file_reader) { auto dictionary_file_reader_pos = file_reader.get_pos(); file_reader.seek_from_begin(0); - uint64_t num_dictionary_entries; + uint64_t num_dictionary_entries{0}; file_reader.read_numeric_value(num_dictionary_entries, false); file_reader.seek_from_begin(dictionary_file_reader_pos); return num_dictionary_entries; @@ -39,7 +16,7 @@ uint64_t read_segment_index_header(FileReader& file_reader) { // Read segment index header auto segment_index_file_reader_pos = file_reader.get_pos(); file_reader.seek_from_begin(0); - uint64_t num_segments; + uint64_t num_segments{0}; file_reader.read_numeric_value(num_segments, false); file_reader.seek_from_begin(segment_index_file_reader_pos); return num_segments; diff --git a/components/core/src/clp/dictionary_utils.hpp b/components/core/src/clp/dictionary_utils.hpp index 42012964f..14509a4e9 100644 --- a/components/core/src/clp/dictionary_utils.hpp +++ b/components/core/src/clp/dictionary_utils.hpp @@ -1,22 +1,10 @@ #ifndef CLP_DICTIONARY_UTILS_HPP #define CLP_DICTIONARY_UTILS_HPP -#include - #include "FileReader.hpp" #include "streaming_compression/Decompressor.hpp" namespace clp { -void open_dictionary_for_reading( - std::string const& dictionary_path, - std::string const& segment_index_path, - size_t decompressor_file_read_buffer_capacity, - FileReader& dictionary_file_reader, - streaming_compression::Decompressor& dictionary_decompressor, - FileReader& segment_index_file_reader, - streaming_compression::Decompressor& segment_index_decompressor -); - uint64_t read_dictionary_header(FileReader& file_reader); uint64_t read_segment_index_header(FileReader& file_reader); diff --git a/components/core/src/clp/streaming_archive/reader/Archive.cpp b/components/core/src/clp/streaming_archive/reader/Archive.cpp index 05e42cac3..141e5fce5 100644 --- a/components/core/src/clp/streaming_archive/reader/Archive.cpp +++ b/components/core/src/clp/streaming_archive/reader/Archive.cpp @@ -37,11 +37,9 @@ void Archive::open(string const& path) { string metadata_file_path = path + '/' + cMetadataFileName; archive_format_version_t format_version{}; try { - FileReader file_reader; - file_reader.open(metadata_file_path); + FileReader file_reader{metadata_file_path}; ArchiveMetadata const metadata{file_reader}; format_version = metadata.get_archive_format_version(); - file_reader.close(); } catch (TraceableException& traceable_exception) { auto error_code = traceable_exception.get_error_code(); if (ErrorCode_errno == error_code) { diff --git a/components/core/tests/test-BufferedFileReader.cpp b/components/core/tests/test-BufferedFileReader.cpp index 734eca87b..f182a777c 100644 --- a/components/core/tests/test-BufferedFileReader.cpp +++ b/components/core/tests/test-BufferedFileReader.cpp @@ -277,8 +277,7 @@ TEST_CASE("Test delimiter", "[BufferedFileReader]") { file_reader.open(test_file_path); std::string test_string; - clp::FileReader ref_file_reader; - ref_file_reader.open(test_file_path); + clp::FileReader ref_file_reader{test_file_path}; std::string ref_string; // Validate that a FileReader and a BufferedFileReader return the same strings (split by @@ -292,7 +291,6 @@ TEST_CASE("Test delimiter", "[BufferedFileReader]") { REQUIRE(test_string == ref_string); } - ref_file_reader.close(); file_reader.close(); boost::filesystem::remove(test_file_path); } diff --git a/components/core/tests/test-MemoryMappedFile.cpp b/components/core/tests/test-MemoryMappedFile.cpp index 20d433f32..9cb855e0b 100644 --- a/components/core/tests/test-MemoryMappedFile.cpp +++ b/components/core/tests/test-MemoryMappedFile.cpp @@ -42,10 +42,8 @@ TEST_CASE("memory_mapped_file_view_basic", "[ReadOnlyMemoryMappedFile]") { auto const test_input_path{ get_test_dir() / std::filesystem::path{"test_network_reader_src"} / "random.log" }; - clp::FileReader file_reader; - file_reader.open(test_input_path.string()); + clp::FileReader file_reader{test_input_path.string()}; auto const expected{read_content(file_reader)}; - file_reader.close(); clp::ReadOnlyMemoryMappedFile const mmap_file{test_input_path.string()}; auto const view{mmap_file.get_view()}; diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index d06876f5f..38172507d 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -67,10 +67,8 @@ auto get_content(clp::ReaderInterface& reader, size_t read_buf_size) -> std::vec } // namespace TEST_CASE("network_reader_basic", "[NetworkReader]") { - clp::FileReader ref_reader; - ref_reader.open(get_test_input_local_path()); + clp::FileReader ref_reader{get_test_input_local_path()}; auto const expected{get_content(ref_reader)}; - ref_reader.close(); clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url()}; @@ -84,12 +82,10 @@ TEST_CASE("network_reader_basic", "[NetworkReader]") { TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { constexpr size_t cOffset{319}; - clp::FileReader ref_reader; - ref_reader.open(get_test_input_local_path()); + clp::FileReader ref_reader{get_test_input_local_path()}; ref_reader.seek_from_begin(cOffset); auto const expected{get_content(ref_reader)}; auto const ref_end_pos{ref_reader.get_pos()}; - ref_reader.close(); // Read from an offset onwards by starting the download from that offset. { diff --git a/components/core/tests/test-ParserWithUserSchema.cpp b/components/core/tests/test-ParserWithUserSchema.cpp index d69a94958..3689c69e8 100644 --- a/components/core/tests/test-ParserWithUserSchema.cpp +++ b/components/core/tests/test-ParserWithUserSchema.cpp @@ -162,9 +162,8 @@ TEST_CASE("Test forward lexer", "[Search]") { std::string schema_file_name = "../tests/test_schema_files/search_schema.txt"; std::string schema_file_path = boost::filesystem::weakly_canonical(schema_file_name).string(); load_lexer_from_file(schema_file_path, false, forward_lexer); - FileReader file_reader; + FileReader file_reader{"../tests/test_search_queries/easy.txt"}; LogSurgeonReader reader_wrapper(file_reader); - file_reader.open("../tests/test_search_queries/easy.txt"); log_surgeon::ParserInputBuffer parser_input_buffer; parser_input_buffer.read_if_safe(reader_wrapper); forward_lexer.reset(); @@ -187,9 +186,8 @@ TEST_CASE("Test reverse lexer", "[Search]") { std::string schema_file_name = "../tests/test_schema_files/search_schema.txt"; std::string schema_file_path = boost::filesystem::weakly_canonical(schema_file_name).string(); load_lexer_from_file(schema_file_path, false, reverse_lexer); - FileReader file_reader; + FileReader file_reader{"../tests/test_search_queries/easy.txt"}; LogSurgeonReader reader_wrapper(file_reader); - file_reader.open("../tests/test_search_queries/easy.txt"); log_surgeon::ParserInputBuffer parser_input_buffer; parser_input_buffer.read_if_safe(reader_wrapper); reverse_lexer.reset(); From 1b67fdb0ca836d7965c8770028c8b46e18a3c9c9 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:55:07 -0400 Subject: [PATCH 051/114] ffi: Add class for key-value pair log events. (#507) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 4 +- .../core/src/clp/ffi/KeyValuePairLogEvent.cpp | 170 +++++++ .../core/src/clp/ffi/KeyValuePairLogEvent.hpp | 81 ++++ components/core/src/clp/ffi/Value.hpp | 11 - components/core/src/clp/ir/EncodedTextAst.hpp | 11 - .../tests/test-ffi_KeyValuePairLogEvent.cpp | 453 ++++++++++++++++++ components/core/tests/test-ffi_Value.cpp | 187 -------- 7 files changed, 707 insertions(+), 210 deletions(-) create mode 100644 components/core/src/clp/ffi/KeyValuePairLogEvent.cpp create mode 100644 components/core/src/clp/ffi/KeyValuePairLogEvent.hpp create mode 100644 components/core/tests/test-ffi_KeyValuePairLogEvent.cpp delete mode 100644 components/core/tests/test-ffi_Value.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 4d7eab5c4..dba237ed1 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -320,6 +320,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/Serializer.hpp src/clp/ffi/ir_stream/utils.cpp src/clp/ffi/ir_stream/utils.hpp + src/clp/ffi/KeyValuePairLogEvent.cpp + src/clp/ffi/KeyValuePairLogEvent.hpp src/clp/ffi/SchemaTree.cpp src/clp/ffi/SchemaTree.hpp src/clp/ffi/SchemaTreeNode.hpp @@ -475,8 +477,8 @@ set(SOURCE_FILES_unitTest tests/test-BufferedFileReader.cpp tests/test-EncodedVariableInterpreter.cpp tests/test-encoding_methods.cpp + tests/test-ffi_KeyValuePairLogEvent.cpp tests/test-ffi_SchemaTree.cpp - tests/test-ffi_Value.cpp tests/test-Grep.cpp tests/test-hash_utils.cpp tests/test-ir_encoding_methods.cpp diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp new file mode 100644 index 000000000..d08803e08 --- /dev/null +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp @@ -0,0 +1,170 @@ +#include "KeyValuePairLogEvent.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../ir/EncodedTextAst.hpp" +#include "../time_types.hpp" +#include "SchemaTree.hpp" +#include "SchemaTreeNode.hpp" +#include "Value.hpp" + +using clp::ir::EightByteEncodedTextAst; +using clp::ir::FourByteEncodedTextAst; +using std::string; + +namespace clp::ffi { +namespace { +/** + * @param type + * @param value + * @return Whether the given schema tree node type matches the given value's type. + */ +[[nodiscard]] auto +node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> bool; + +/** + * Validates whether the given node-ID value pairs are leaf nodes in the `SchemaTree` forming a + * sub-tree of their own. + * @param schema_tree + * @param node_id_value_pairs + * @return success if the inputs are valid, or an error code indicating the failure: + * - std::errc::operation_not_permitted if a node ID doesn't represent a valid node in the + * schema tree, or a non-leaf node ID is paired with a value. + * - std::errc::protocol_error if the schema tree node type doesn't match the value's type. + * - std::errc::protocol_not_supported if the same key appears more than once under a parent + * node. + */ +[[nodiscard]] auto validate_node_id_value_pairs( + SchemaTree const& schema_tree, + KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs +) -> std::errc; + +/** + * @param schema_tree + * @param node_id + * @param node_id_value_pairs + * @return Whether the given node is a leaf node in the sub-tree of the `SchemaTree` defined by + * `node_id_value_pairs`. A node is considered a leaf if none of its descendants appear in + * `node_id_value_pairs`. + */ +[[nodiscard]] auto is_leaf_node( + SchemaTree const& schema_tree, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs +) -> bool; + +auto node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> bool { + switch (type) { + case SchemaTreeNode::Type::Obj: + return value.is_null(); + case SchemaTreeNode::Type::Int: + return value.is(); + case SchemaTreeNode::Type::Float: + return value.is(); + case SchemaTreeNode::Type::Bool: + return value.is(); + case SchemaTreeNode::Type::UnstructuredArray: + return value.is() || value.is(); + case SchemaTreeNode::Type::Str: + return value.is() || value.is() + || value.is(); + default: + return false; + } +} + +auto validate_node_id_value_pairs( + SchemaTree const& schema_tree, + KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs +) -> std::errc { + try { + std::unordered_map> + parent_node_id_to_key_names; + for (auto const& [node_id, value] : node_id_value_pairs) { + if (SchemaTree::cRootId == node_id) { + return std::errc::operation_not_permitted; + } + + auto const& node{schema_tree.get_node(node_id)}; + auto const node_type{node.get_type()}; + if (false == value.has_value()) { + // Value is an empty object (`{}`, which is not the same as `null`) + if (SchemaTreeNode::Type::Obj != node_type) { + return std::errc::protocol_error; + } + } else if (false == node_type_matches_value_type(node_type, value.value())) { + return std::errc::protocol_error; + } + + if (SchemaTreeNode::Type::Obj == node_type + && false == is_leaf_node(schema_tree, node_id, node_id_value_pairs)) + { + // The node's value is `null` or `{}` but its descendants appear in + // `node_id_value_pairs`. + return std::errc::operation_not_permitted; + } + + auto const parent_node_id{node.get_parent_id()}; + auto const key_name{node.get_key_name()}; + if (parent_node_id_to_key_names.contains(parent_node_id)) { + auto const [it, new_key_inserted]{ + parent_node_id_to_key_names.at(parent_node_id).emplace(key_name) + }; + if (false == new_key_inserted) { + // The key is duplicated under the same parent + return std::errc::protocol_not_supported; + } + } else { + parent_node_id_to_key_names.emplace(parent_node_id, std::unordered_set{key_name}); + } + } + } catch (SchemaTree::OperationFailed const& ex) { + return std::errc::operation_not_permitted; + } + return std::errc{}; +} + +auto is_leaf_node( + SchemaTree const& schema_tree, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs +) -> bool { + std::vector dfs_stack; + dfs_stack.reserve(schema_tree.get_size()); + dfs_stack.push_back(node_id); + while (false == dfs_stack.empty()) { + auto const curr_node_id{dfs_stack.back()}; + dfs_stack.pop_back(); + for (auto const child_node_id : schema_tree.get_node(curr_node_id).get_children_ids()) { + if (node_id_value_pairs.contains(child_node_id)) { + return false; + } + dfs_stack.push_back(child_node_id); + } + } + return true; +} +} // namespace + +auto KeyValuePairLogEvent::create( + std::shared_ptr schema_tree, + NodeIdValuePairs node_id_value_pairs, + UtcOffset utc_offset +) -> OUTCOME_V2_NAMESPACE::std_result { + if (auto const ret_val{validate_node_id_value_pairs(*schema_tree, node_id_value_pairs)}; + std::errc{} != ret_val) + { + return ret_val; + } + return KeyValuePairLogEvent{std::move(schema_tree), std::move(node_id_value_pairs), utc_offset}; +} +} // namespace clp::ffi diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp new file mode 100644 index 000000000..ad50ee41f --- /dev/null +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp @@ -0,0 +1,81 @@ +#ifndef CLP_FFI_KEYVALUEPAIRLOGEVENT_HPP +#define CLP_FFI_KEYVALUEPAIRLOGEVENT_HPP + +#include +#include +#include +#include + +#include + +#include "../time_types.hpp" +#include "SchemaTree.hpp" +#include "SchemaTreeNode.hpp" +#include "Value.hpp" + +namespace clp::ffi { +/** + * A log event containing key-value pairs. Each event contains: + * - A collection of node-ID & value pairs, where each pair represents a leaf `SchemaTreeNode` in + * the `SchemaTree`. + * - A reference to the `SchemaTree` + * - The UTC offset of the current log event + */ +class KeyValuePairLogEvent { +public: + // Types + using NodeIdValuePairs = std::unordered_map>; + + // Factory functions + /** + * @param schema_tree + * @param node_id_value_pairs + * @param utc_offset + * @return A result containing the key-value pair log event or an error code indicating the + * failure. See `valdiate_node_id_value_pairs` for the possible error codes. + */ + [[nodiscard]] static auto create( + std::shared_ptr schema_tree, + NodeIdValuePairs node_id_value_pairs, + UtcOffset utc_offset + ) -> OUTCOME_V2_NAMESPACE::std_result; + + // Disable copy constructor and assignment operator + KeyValuePairLogEvent(KeyValuePairLogEvent const&) = delete; + auto operator=(KeyValuePairLogEvent const&) -> KeyValuePairLogEvent& = delete; + + // Default move constructor and assignment operator + KeyValuePairLogEvent(KeyValuePairLogEvent&&) = default; + auto operator=(KeyValuePairLogEvent&&) -> KeyValuePairLogEvent& = default; + + // Destructor + ~KeyValuePairLogEvent() = default; + + // Methods + [[nodiscard]] auto get_schema_tree() const -> SchemaTree const& { return *m_schema_tree; } + + [[nodiscard]] auto get_node_id_value_pairs() const -> NodeIdValuePairs const& { + return m_node_id_value_pairs; + } + + [[nodiscard]] auto get_utc_offset() const -> UtcOffset { return m_utc_offset; } + +private: + // Constructor + KeyValuePairLogEvent( + std::shared_ptr schema_tree, + NodeIdValuePairs node_id_value_pairs, + UtcOffset utc_offset + ) + : m_schema_tree{std::move(schema_tree)}, + m_node_id_value_pairs{std::move(node_id_value_pairs)}, + m_utc_offset{utc_offset} {} + + // Variables + std::shared_ptr m_schema_tree; + NodeIdValuePairs m_node_id_value_pairs; + UtcOffset m_utc_offset{0}; +}; +} // namespace clp::ffi + +#endif // CLP_FFI_KEYVALUEPAIRLOGEVENT_HPP diff --git a/components/core/src/clp/ffi/Value.hpp b/components/core/src/clp/ffi/Value.hpp index db719a1fb..961d12366 100644 --- a/components/core/src/clp/ffi/Value.hpp +++ b/components/core/src/clp/ffi/Value.hpp @@ -150,17 +150,6 @@ class Value { template explicit Value(T value) : m_value{value} {} - // Disable copy constructor and assignment operator - Value(Value const&) = delete; - auto operator=(Value const&) -> Value& = delete; - - // Default move constructor and assignment operator - Value(Value&&) = default; - auto operator=(Value&&) -> Value& = default; - - // Destructor - ~Value() = default; - // Methods /** * @tparam T diff --git a/components/core/src/clp/ir/EncodedTextAst.hpp b/components/core/src/clp/ir/EncodedTextAst.hpp index 48adb100a..e18759780 100644 --- a/components/core/src/clp/ir/EncodedTextAst.hpp +++ b/components/core/src/clp/ir/EncodedTextAst.hpp @@ -26,17 +26,6 @@ class EncodedTextAst { m_dict_vars{std::move(dict_vars)}, m_encoded_vars{std::move(encoded_vars)} {} - // Disable copy constructor and assignment operator - EncodedTextAst(EncodedTextAst const&) = delete; - auto operator=(EncodedTextAst const&) -> EncodedTextAst& = delete; - - // Default move constructor and assignment operator - EncodedTextAst(EncodedTextAst&&) = default; - auto operator=(EncodedTextAst&&) -> EncodedTextAst& = default; - - // Destructor - ~EncodedTextAst() = default; - // Methods auto operator==(EncodedTextAst const&) const -> bool = default; diff --git a/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp b/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp new file mode 100644 index 000000000..4820a5af1 --- /dev/null +++ b/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp @@ -0,0 +1,453 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../src/clp/ffi/encoding_methods.hpp" +#include "../src/clp/ffi/KeyValuePairLogEvent.hpp" +#include "../src/clp/ffi/SchemaTree.hpp" +#include "../src/clp/ffi/SchemaTreeNode.hpp" +#include "../src/clp/ffi/Value.hpp" +#include "../src/clp/ir/EncodedTextAst.hpp" +#include "../src/clp/ir/types.hpp" +#include "../src/clp/time_types.hpp" + +using clp::ffi::KeyValuePairLogEvent; +using clp::ffi::SchemaTree; +using clp::ffi::SchemaTreeNode; +using clp::ffi::Value; +using clp::ffi::value_bool_t; +using clp::ffi::value_float_t; +using clp::ffi::value_int_t; +using clp::ir::eight_byte_encoded_variable_t; +using clp::ir::EightByteEncodedTextAst; +using clp::ir::four_byte_encoded_variable_t; +using clp::ir::FourByteEncodedTextAst; +using clp::UtcOffset; +using std::string; +using std::vector; + +namespace { +constexpr std::string_view cStringToEncode{"uid=0, CPU usage: 99.99%, \"user_name\"=YScope"}; + +/** + * Parses and encodes the given string as an instance of `EncodedTextAst`. + * @tparam encoded_variable_t + * @param text + * @return The encoded result. + */ +template +requires(std::is_same_v + || std::is_same_v) +[[nodiscard]] auto get_encoded_text_ast(std::string_view text +) -> clp::ir::EncodedTextAst; + +/** + * Tests that `Value::is` returns true for the given type and false for all others. + * @tparam Type The type to query. + * @param value The value to test against. + */ +template +auto test_value_is(Value const& value) -> void; + +/** + * Tests `Value::get_immutable_view` either: + * 1. returns the expected value with the expected type for the given type and value; + * 2. throws for any other type. + * @tparam Type The type to query. + * @param value The value to test against. + * @param typed_value The typed value to compare with. + */ +template +auto test_value_get_immutable_view(Value const& value, Type const& typed_value) -> void; + +/** + * Generates invalid node-ID value pairs with values that don't match the type of the schema tree + * node with the given ID. + * @param schema_tree + * @param node_id + * @param invalid_node_id_value_pairs Returns the pairs after insertion. + */ +auto insert_invalid_node_id_value_pairs_with_node_type_errors( + SchemaTree const& schema_tree, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& invalid_node_id_value_pairs +) -> void; + +template +requires(std::is_same_v + || std::is_same_v) +auto get_encoded_text_ast(std::string_view text) -> clp::ir::EncodedTextAst { + string logtype; + vector encoded_vars; + vector dict_var_bounds; + REQUIRE(clp::ffi::encode_message(text, logtype, encoded_vars, dict_var_bounds)); + REQUIRE(((dict_var_bounds.size() % 2) == 0)); + + vector dict_vars; + for (size_t i{0}; i < dict_var_bounds.size(); i += 2) { + auto const begin_pos{static_cast(dict_var_bounds[i])}; + auto const end_pos{static_cast(dict_var_bounds[i + 1])}; + dict_vars.emplace_back(text.cbegin() + begin_pos, text.cbegin() + end_pos); + } + + return clp::ir::EncodedTextAst{logtype, dict_vars, encoded_vars}; +} + +template +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +auto test_value_is(Value const& value) -> void { + REQUIRE((std::is_same_v == value.is_null())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); + REQUIRE((std::is_same_v == value.is())); +} + +template +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +auto test_value_get_immutable_view(Value const& value, Type const& typed_value) -> void { + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v< + EightByteEncodedTextAst const&, + decltype(value.get_immutable_view())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } + + if constexpr (std::is_same_v) { + REQUIRE((value.get_immutable_view() == typed_value)); + REQUIRE((std::is_same_v< + FourByteEncodedTextAst const&, + decltype(value.get_immutable_view())>)); + } else { + REQUIRE_THROWS(value.get_immutable_view()); + } +} + +auto insert_invalid_node_id_value_pairs_with_node_type_errors( + SchemaTree const& schema_tree, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& invalid_node_id_value_pairs +) -> void { + REQUIRE((node_id < schema_tree.get_size())); + auto const node_type{schema_tree.get_node(node_id).get_type()}; + if (SchemaTreeNode::Type::Int != node_type) { + invalid_node_id_value_pairs.emplace(node_id, Value{static_cast(0)}); + } + if (SchemaTreeNode::Type::Float != node_type) { + invalid_node_id_value_pairs.emplace(node_id, Value{static_cast(0.0)}); + } + if (SchemaTreeNode::Type::Bool != node_type) { + invalid_node_id_value_pairs.emplace(node_id, Value{static_cast(false)}); + } + if (SchemaTreeNode::Type::Str != node_type) { + invalid_node_id_value_pairs.emplace(node_id, Value{static_cast("Test")}); + if (SchemaTreeNode::Type::UnstructuredArray != node_type) { + invalid_node_id_value_pairs.emplace( + node_id, + Value{get_encoded_text_ast(cStringToEncode)} + ); + invalid_node_id_value_pairs.emplace( + node_id, + Value{get_encoded_text_ast(cStringToEncode)} + ); + } + } + if (SchemaTreeNode::Type::Obj != node_type) { + invalid_node_id_value_pairs.emplace(node_id, std::nullopt); + invalid_node_id_value_pairs.emplace(node_id, Value{}); + } +} +} // namespace + +TEST_CASE("ffi_Value_basic", "[ffi][Value]") { + Value const null_value; + test_value_is(null_value); + test_value_get_immutable_view(null_value, std::monostate{}); + + constexpr value_int_t cIntVal{1000}; + Value const int_value{cIntVal}; + test_value_is(int_value); + test_value_get_immutable_view(int_value, cIntVal); + + constexpr value_float_t cFloatValue{1000.0001}; + Value const float_value{cFloatValue}; + test_value_is(float_value); + test_value_get_immutable_view(float_value, cFloatValue); + + constexpr value_bool_t cBoolVal{false}; + Value const bool_value{cBoolVal}; + test_value_is(bool_value); + test_value_get_immutable_view(bool_value, cBoolVal); + + constexpr std::string_view cStringVal{"This is a test string message"}; + Value const string_value{string{cStringVal}}; + test_value_is(string_value); + test_value_get_immutable_view(string_value, string{cStringVal}); + + Value const eight_byte_encoded_text_ast_value{ + get_encoded_text_ast(cStringToEncode) + }; + test_value_is(eight_byte_encoded_text_ast_value); + test_value_get_immutable_view( + eight_byte_encoded_text_ast_value, + get_encoded_text_ast(cStringToEncode) + ); + + Value const four_byte_encoded_text_ast_value{ + get_encoded_text_ast(cStringToEncode) + }; + test_value_is(four_byte_encoded_text_ast_value); + test_value_get_immutable_view( + four_byte_encoded_text_ast_value, + get_encoded_text_ast(cStringToEncode) + ); +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +TEST_CASE("ffi_KeyValuePairLogEvent_create", "[ffi]") { + /* + * <0:root:Obj> + * | + * |------------> <1:a:Obj> + * | | + * |--> <2:a:Int> |--> <3:b:Obj> + * | + * |------------> <4:c:Obj> + * | | + * |--> <5:d:Str> |--> <7:a:UnstructuredArray> + * | | + * |--> <6:d:Bool> |--> <8:d:Str> + * | | + * |--> <10:e:Obj> |--> <9:d:Float> + * | + * |--> <11:f:Obj> + */ + auto const schema_tree{std::make_shared()}; + std::vector const locators{ + {SchemaTree::cRootId, "a", SchemaTreeNode::Type::Obj}, + {SchemaTree::cRootId, "a", SchemaTreeNode::Type::Int}, + {1, "b", SchemaTreeNode::Type::Obj}, + {3, "c", SchemaTreeNode::Type::Obj}, + {3, "d", SchemaTreeNode::Type::Str}, + {3, "d", SchemaTreeNode::Type::Bool}, + {4, "a", SchemaTreeNode::Type::UnstructuredArray}, + {4, "d", SchemaTreeNode::Type::Str}, + {4, "d", SchemaTreeNode::Type::Float}, + {3, "e", SchemaTreeNode::Type::Obj}, + {4, "f", SchemaTreeNode::Type::Obj} + }; + for (auto const& locator : locators) { + REQUIRE_NOTHROW(schema_tree->insert_node(locator)); + } + + SECTION("Test empty ID-value pairs") { + KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs; + auto const result{KeyValuePairLogEvent::create( + schema_tree, + std::move(node_id_value_pairs), + UtcOffset{0} + )}; + REQUIRE_FALSE(result.has_error()); + } + + SECTION("Test mismatched types") { + KeyValuePairLogEvent::NodeIdValuePairs invalid_node_id_value_pairs; + // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + // Int: + insert_invalid_node_id_value_pairs_with_node_type_errors( + *schema_tree, + 2, + invalid_node_id_value_pairs + ); + + // Float: + insert_invalid_node_id_value_pairs_with_node_type_errors( + *schema_tree, + 9, + invalid_node_id_value_pairs + ); + + // Bool: + insert_invalid_node_id_value_pairs_with_node_type_errors( + *schema_tree, + 6, + invalid_node_id_value_pairs + ); + + // Str: + insert_invalid_node_id_value_pairs_with_node_type_errors( + *schema_tree, + 5, + invalid_node_id_value_pairs + ); + + // UnstructuredArray: + insert_invalid_node_id_value_pairs_with_node_type_errors( + *schema_tree, + 7, + invalid_node_id_value_pairs + ); + + // Obj: + insert_invalid_node_id_value_pairs_with_node_type_errors( + *schema_tree, + 3, + invalid_node_id_value_pairs + ); + // NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + + for (auto const& [node_id, optional_value] : invalid_node_id_value_pairs) { + KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pair_to_test; + if (optional_value.has_value()) { + node_id_value_pair_to_test.emplace(node_id, optional_value.value()); + } else { + node_id_value_pair_to_test.emplace(node_id, std::nullopt); + } + auto const result{KeyValuePairLogEvent::create( + schema_tree, + std::move(node_id_value_pair_to_test), + UtcOffset{0} + )}; + REQUIRE(result.has_error()); + auto const& err{result.error()}; + REQUIRE((std::errc::protocol_error == err)); + } + } + + SECTION("Test valid ID-value pairs") { + KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs; + /* + * The sub schema tree of `node_id_value_pairs`: + * <0:root:Obj> + * | + * |------------> <1:a:Obj> + * | | + * |--> <2:a:Int> |--> <3:b:Obj> + * | + * |------------> <4:c:Obj> + * | | + * |--> <5:d:Str> |--> <7:a:UnstructuredArray> + * | | + * | |--> <8:d:Str> + * | | + * |--> <10:e:Obj> | + * | + * |--> <11:f:Obj> + */ + // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + node_id_value_pairs.emplace(2, Value{static_cast(0)}); + node_id_value_pairs.emplace(5, Value{string{"Test"}}); + node_id_value_pairs.emplace( + 8, + Value{get_encoded_text_ast(cStringToEncode)} + ); + node_id_value_pairs.emplace( + 7, + Value{get_encoded_text_ast(cStringToEncode)} + ); + node_id_value_pairs.emplace(10, Value{}); + node_id_value_pairs.emplace(11, std::nullopt); + // NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + auto const result{ + KeyValuePairLogEvent::create(schema_tree, node_id_value_pairs, UtcOffset{0}) + }; + REQUIRE_FALSE(result.has_error()); + + SECTION("Test duplicated key conflict on node #3") { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + node_id_value_pairs.emplace(6, Value{static_cast(false)}); + auto const result{ + KeyValuePairLogEvent::create(schema_tree, node_id_value_pairs, UtcOffset{0}) + }; + REQUIRE(result.has_error()); + REQUIRE((std::errc::protocol_not_supported == result.error())); + } + + SECTION("Test duplicated key conflict on node #4") { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + node_id_value_pairs.emplace(9, Value{static_cast(0.0)}); + auto const result{ + KeyValuePairLogEvent::create(schema_tree, node_id_value_pairs, UtcOffset{0}) + }; + REQUIRE(result.has_error()); + REQUIRE((std::errc::protocol_not_supported == result.error())); + } + + SECTION("Test invalid sub-tree on node #3") { + node_id_value_pairs.emplace(3, std::nullopt); + auto const result{ + KeyValuePairLogEvent::create(schema_tree, node_id_value_pairs, UtcOffset{0}) + }; + // Node #3 is empty, but its descendants appear in the sub schema tree (node #5 & #10) + REQUIRE(result.has_error()); + REQUIRE((std::errc::operation_not_permitted == result.error())); + } + + SECTION("Test invalid sub-tree on node #4") { + node_id_value_pairs.emplace(4, Value{}); + auto const result{ + KeyValuePairLogEvent::create(schema_tree, node_id_value_pairs, UtcOffset{0}) + }; + // Node #4 is null, but its descendants appear in the sub schema tree (node #5 & #10) + REQUIRE(result.has_error()); + REQUIRE((std::errc::operation_not_permitted == result.error())); + } + } + + SECTION("Test out-of-bound node ID") { + KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs_out_of_bound; + node_id_value_pairs_out_of_bound.emplace( + static_cast(schema_tree->get_size()), + Value{} + ); + auto const out_of_bound_result{KeyValuePairLogEvent::create( + schema_tree, + std::move(node_id_value_pairs_out_of_bound), + UtcOffset{0} + )}; + REQUIRE(out_of_bound_result.has_error()); + REQUIRE((std::errc::operation_not_permitted == out_of_bound_result.error())); + } +} diff --git a/components/core/tests/test-ffi_Value.cpp b/components/core/tests/test-ffi_Value.cpp deleted file mode 100644 index 33764c4ff..000000000 --- a/components/core/tests/test-ffi_Value.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../src/clp/ffi/encoding_methods.hpp" -#include "../src/clp/ffi/Value.hpp" -#include "../src/clp/ir/EncodedTextAst.hpp" -#include "../src/clp/ir/types.hpp" - -using clp::ffi::Value; -using clp::ffi::value_bool_t; -using clp::ffi::value_float_t; -using clp::ffi::value_int_t; -using clp::ir::eight_byte_encoded_variable_t; -using clp::ir::EightByteEncodedTextAst; -using clp::ir::four_byte_encoded_variable_t; -using clp::ir::FourByteEncodedTextAst; -using std::string; -using std::vector; - -namespace { -/** - * Parses and encodes the given string as an instance of `EncodedTextAst`. - * @tparam encoded_variable_t - * @param text - * @return The encoded result. - */ -template -requires(std::is_same_v - || std::is_same_v) -[[nodiscard]] auto get_encoded_text_ast(std::string_view text -) -> clp::ir::EncodedTextAst; - -/** - * Tests that `Value::is` returns true for the given type and false for all others. - * @tparam Type The type to query. - * @param value The value to test against. - */ -template -auto test_value_is(Value const& value) -> void; - -/** - * Tests `Value::get_immutable_view` either: - * 1. returns the expected value with the expected type for the given type and value; - * 2. throws for any other type. - * @tparam Type The type to query. - * @param value The value to test against. - * @param typed_value The typed value to compare with. - */ -template -auto test_value_get_immutable_view(Value const& value, Type const& typed_value) -> void; - -// Implementation - -template -requires(std::is_same_v - || std::is_same_v) -auto get_encoded_text_ast(std::string_view text) -> clp::ir::EncodedTextAst { - string logtype; - vector encoded_vars; - vector dict_var_bounds; - REQUIRE(clp::ffi::encode_message(text, logtype, encoded_vars, dict_var_bounds)); - REQUIRE(((dict_var_bounds.size() % 2) == 0)); - - vector dict_vars; - for (size_t i{0}; i < dict_var_bounds.size(); i += 2) { - auto const begin_pos{static_cast(dict_var_bounds[i])}; - auto const end_pos{static_cast(dict_var_bounds[i + 1])}; - dict_vars.emplace_back(text.cbegin() + begin_pos, text.cbegin() + end_pos); - } - - return clp::ir::EncodedTextAst{logtype, dict_vars, encoded_vars}; -} - -template -// NOLINTNEXTLINE(readability-function-cognitive-complexity) -auto test_value_is(Value const& value) -> void { - REQUIRE((std::is_same_v == value.is_null())); - REQUIRE((std::is_same_v == value.is())); - REQUIRE((std::is_same_v == value.is())); - REQUIRE((std::is_same_v == value.is())); - REQUIRE((std::is_same_v == value.is())); - REQUIRE((std::is_same_v == value.is())); - REQUIRE((std::is_same_v == value.is())); -} - -template -// NOLINTNEXTLINE(readability-function-cognitive-complexity) -auto test_value_get_immutable_view(Value const& value, Type const& typed_value) -> void { - if constexpr (std::is_same_v) { - REQUIRE((value.get_immutable_view() == typed_value)); - REQUIRE((std::is_same_v())>)); - } else { - REQUIRE_THROWS(value.get_immutable_view()); - } - - if constexpr (std::is_same_v) { - REQUIRE((value.get_immutable_view() == typed_value)); - REQUIRE((std::is_same_v())>)); - } else { - REQUIRE_THROWS(value.get_immutable_view()); - } - - if constexpr (std::is_same_v) { - REQUIRE((value.get_immutable_view() == typed_value)); - REQUIRE((std::is_same_v())>)); - } else { - REQUIRE_THROWS(value.get_immutable_view()); - } - - if constexpr (std::is_same_v) { - REQUIRE((value.get_immutable_view() == typed_value)); - REQUIRE((std::is_same_v())>)); - } else { - REQUIRE_THROWS(value.get_immutable_view()); - } - - if constexpr (std::is_same_v) { - REQUIRE((value.get_immutable_view() == typed_value)); - REQUIRE((std::is_same_v< - EightByteEncodedTextAst const&, - decltype(value.get_immutable_view())>)); - } else { - REQUIRE_THROWS(value.get_immutable_view()); - } - - if constexpr (std::is_same_v) { - REQUIRE((value.get_immutable_view() == typed_value)); - REQUIRE((std::is_same_v< - FourByteEncodedTextAst const&, - decltype(value.get_immutable_view())>)); - } else { - REQUIRE_THROWS(value.get_immutable_view()); - } -} -} // namespace - -TEST_CASE("ffi_Value_basic", "[ffi][Value]") { - Value const null_value; - test_value_is(null_value); - test_value_get_immutable_view(null_value, std::monostate{}); - - constexpr value_int_t cIntVal{1000}; - Value const int_value{cIntVal}; - test_value_is(int_value); - test_value_get_immutable_view(int_value, cIntVal); - - constexpr value_float_t cFloatValue{1000.0001}; - Value const float_value{cFloatValue}; - test_value_is(float_value); - test_value_get_immutable_view(float_value, cFloatValue); - - constexpr value_bool_t cBoolVal{false}; - Value const bool_value{cBoolVal}; - test_value_is(bool_value); - test_value_get_immutable_view(bool_value, cBoolVal); - - constexpr std::string_view cStringVal{"This is a test string message"}; - Value const string_value{string{cStringVal}}; - test_value_is(string_value); - test_value_get_immutable_view(string_value, string{cStringVal}); - - constexpr std::string_view cStringToEncode{"uid=0, CPU usage: 99.99%, \"user_name\"=YScope"}; - Value const eight_byte_encoded_text_ast_value{ - get_encoded_text_ast(cStringToEncode) - }; - test_value_is(eight_byte_encoded_text_ast_value); - test_value_get_immutable_view( - eight_byte_encoded_text_ast_value, - get_encoded_text_ast(cStringToEncode) - ); - - Value const four_byte_encoded_text_ast_value{ - get_encoded_text_ast(cStringToEncode) - }; - test_value_is(four_byte_encoded_text_ast_value); - test_value_get_immutable_view( - four_byte_encoded_text_ast_value, - get_encoded_text_ast(cStringToEncode) - ); -} From 86299ca2907565e09cb10c2ddd3661ad1ceb6cb0 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sun, 18 Aug 2024 00:25:47 -0400 Subject: [PATCH 052/114] core: Add `Array` template class to abstract a fixed-size contiguous buffer whose size is determined at runtime. (#513) --- components/core/CMakeLists.txt | 2 + components/core/src/clp/Array.hpp | 111 +++++++++++++++++++++++++++ components/core/tests/test-Array.cpp | 57 ++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 components/core/src/clp/Array.hpp create mode 100644 components/core/tests/test-Array.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index dba237ed1..c1a889de8 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -269,6 +269,7 @@ set(SOURCE_FILES_clp_s_unitTest ) set(SOURCE_FILES_unitTest + src/clp/Array.hpp src/clp/BufferedFileReader.cpp src/clp/BufferedFileReader.hpp src/clp/BufferReader.cpp @@ -474,6 +475,7 @@ set(SOURCE_FILES_unitTest submodules/sqlite3/sqlite3.h submodules/sqlite3/sqlite3ext.h tests/LogSuppressor.hpp + tests/test-Array.cpp tests/test-BufferedFileReader.cpp tests/test-EncodedVariableInterpreter.cpp tests/test-encoding_methods.cpp diff --git a/components/core/src/clp/Array.hpp b/components/core/src/clp/Array.hpp new file mode 100644 index 000000000..f94892493 --- /dev/null +++ b/components/core/src/clp/Array.hpp @@ -0,0 +1,111 @@ +#ifndef CLP_ARRAY_HPP +#define CLP_ARRAY_HPP + +#include +#include +#include +#include +#include +#include + +namespace clp { +/** + * Class for a runtime fix-sized array. + * @tparam T The type of elements in the array. The type must be default initializable so that this + * class doesn't need to implement a constructor which takes an initializer list. + */ +template +requires(std::is_fundamental_v || std::default_initializable) +class Array { +public: + // Types + using Iterator = T*; + using ConstIterator = T const*; + + // Constructors + // NOLINTNEXTLINE(*-avoid-c-arrays) + explicit Array(size_t size) : m_data{std::make_unique(size)}, m_size{size} { + if constexpr (std::is_fundamental_v) { + memset(m_data.get(), 0, m_size * sizeof(T)); + } + } + + // Disable copy constructor and assignment operator + Array(Array const&) = delete; + auto operator=(Array const&) -> Array& = delete; + + // Default move constructor and assignment operator + Array(Array&&) = default; + auto operator=(Array&&) -> Array& = default; + + // Destructor + ~Array() = default; + + // Methods + /** + * @return Whether the array is empty. + */ + [[nodiscard]] auto empty() const -> bool { return 0 == size(); } + + /** + * @return The size of the array. + */ + [[nodiscard]] auto size() const -> size_t { return m_size; } + + /** + * @return A pointer to the underlying data buffer. + */ + [[nodiscard]] auto data() -> T* { return m_data.get(); } + + /** + * @return A pointer to the underlying data buffer. + */ + [[nodiscard]] auto data() const -> T const* { return m_data.get(); } + + /** + * @param idx + * @return The element at the given index. + * @throw `OperationFailed` if the given index is out of bound. + */ + [[nodiscard]] auto at(size_t idx) -> T& { + assert_is_in_range(idx); + return m_data[idx]; + } + + /** + * @param idx + * @return The element at the given index. + * @throw `OperationFailed` if the given index is out of bound. + */ + [[nodiscard]] auto at(size_t idx) const -> T const& { + assert_is_in_range(idx); + return m_data[idx]; + } + + [[nodiscard]] auto begin() -> Iterator { return m_data.get(); } + + [[nodiscard]] auto end() -> Iterator { return m_data.get() + m_size; } + + [[nodiscard]] auto begin() const -> ConstIterator { return m_data.get(); } + + [[nodiscard]] auto end() const -> ConstIterator { return m_data.get() + m_size; } + +private: + /** + * @param idx + * @throw `std::out_of_range` if the given index is out of bound. + */ + auto assert_is_in_range(size_t idx) -> void { + if (idx >= m_size) { + throw std::out_of_range("clp::Array out-of-range access."); + } + } + + // Variables + // NOLINTNEXTLINE(*-avoid-c-arrays) + std::unique_ptr m_data; + size_t m_size; +}; +} // namespace clp + +#endif // CLP_ARRAY_HPP diff --git a/components/core/tests/test-Array.cpp b/components/core/tests/test-Array.cpp new file mode 100644 index 000000000..20b68fbd0 --- /dev/null +++ b/components/core/tests/test-Array.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +#include + +#include "../src/clp/Array.hpp" + +using clp::Array; +using std::vector; + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +TEST_CASE("array_fundamental", "[clp::Array]") { + Array clp_array_empty{0}; + REQUIRE(clp_array_empty.empty()); + // NOLINTNEXTLINE(readability-container-size-empty) + REQUIRE((0 == clp_array_empty.size())); + REQUIRE((clp_array_empty.begin() == clp_array_empty.end())); + + constexpr size_t cBufferSize{1024}; + + vector std_vector; + for (int i{0}; i < cBufferSize; ++i) { + std_vector.push_back(i); + } + + Array clp_array{cBufferSize}; + auto const& clp_array_const_ref = clp_array; + std::for_each(clp_array_const_ref.begin(), clp_array_const_ref.end(), [](int i) -> void { + REQUIRE((0 == i)); + }); + + std::copy(std_vector.cbegin(), std_vector.cend(), clp_array.begin()); + + size_t idx{0}; + for (auto const val : clp_array) { + REQUIRE((val == clp_array.at(idx))); + REQUIRE((val == std_vector.at(idx))); + ++idx; + } + REQUIRE((cBufferSize == idx)); + REQUIRE_THROWS(clp_array.at(idx)); +} + +TEST_CASE("array_default_initializable", "[clp::Array]") { + Array clp_array_empty{0}; + REQUIRE(clp_array_empty.empty()); + // NOLINTNEXTLINE(readability-container-size-empty) + REQUIRE((0 == clp_array_empty.size())); + REQUIRE((clp_array_empty.begin() == clp_array_empty.end())); + + vector const std_vector{"yscope", "clp", "clp::Array", "default_initializable"}; + Array clp_array{std_vector.size()}; + std::copy(std_vector.cbegin(), std_vector.cend(), clp_array.begin()); + REQUIRE(std::equal(std_vector.begin(), std_vector.end(), clp_array.begin(), clp_array.end())); +} From e1f3f2abe3473324b19d66e22c182ec3ac0d408f Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 19 Aug 2024 19:29:27 -0400 Subject: [PATCH 053/114] webui: Improve UI of links for viewing search results in context. (#515) --- .../SearchResultsTable.scss | 9 +++++ .../SearchResultsTable/index.jsx | 35 +++++++++---------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss index db2f38117..063900dfb 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss @@ -50,3 +50,12 @@ word-break: break-word; } +.search-results-file-link { + margin-top: 0.25rem; + + color: grey; + font-family: 'Roboto', sans-serif; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; +} diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 28a331bb8..83b251cca 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -5,10 +5,10 @@ import Table from "react-bootstrap/Table"; import dayjs from "dayjs"; import { + faFileLines, faSort, faSortDown, faSortUp, - faSquareUpRight, } from "@fortawesome/free-solid-svg-icons"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; @@ -125,10 +125,6 @@ const SearchResultsTable = ({ Log message
    - {isExtractIrSupported && - -
     
    - } @@ -143,20 +139,23 @@ const SearchResultsTable = ({
                                         {result.message}
                                     
    + {isExtractIrSupported && + } - {isExtractIrSupported && - - - - - } ))} From 1c72eaeca3c67981165c61d82de58914c13f9ca5 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Wed, 21 Aug 2024 00:34:16 -0400 Subject: [PATCH 054/114] core: Add signer class to generate presigned S3 URL. (#494) --- components/core/CMakeLists.txt | 7 +- .../src/clp/aws/AwsAuthenticationSigner.cpp | 351 ++++++++++++++++++ .../src/clp/aws/AwsAuthenticationSigner.hpp | 136 +++++++ components/core/src/clp/aws/constants.hpp | 28 ++ .../scripts/lib_install/install-boost.sh | 2 +- 5 files changed, 521 insertions(+), 3 deletions(-) create mode 100644 components/core/src/clp/aws/AwsAuthenticationSigner.cpp create mode 100644 components/core/src/clp/aws/AwsAuthenticationSigner.hpp create mode 100644 components/core/src/clp/aws/constants.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index c1a889de8..37baf9b39 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -88,7 +88,7 @@ endif() if(CLP_USE_STATIC_LIBS) set(Boost_USE_STATIC_LIBS ON) endif() -find_package(Boost 1.74 REQUIRED iostreams program_options filesystem system) +find_package(Boost 1.74 REQUIRED iostreams program_options filesystem system regex) if(Boost_FOUND) message(STATUS "Found Boost ${Boost_VERSION}") else() @@ -270,6 +270,9 @@ set(SOURCE_FILES_clp_s_unitTest set(SOURCE_FILES_unitTest src/clp/Array.hpp + src/clp/aws/AwsAuthenticationSigner.cpp + src/clp/aws/AwsAuthenticationSigner.hpp + src/clp/aws/constants.hpp src/clp/BufferedFileReader.cpp src/clp/BufferedFileReader.hpp src/clp/BufferReader.cpp @@ -511,7 +514,7 @@ target_include_directories(unitTest target_link_libraries(unitTest PRIVATE absl::flat_hash_map - Boost::filesystem Boost::iostreams Boost::program_options + Boost::filesystem Boost::iostreams Boost::program_options Boost::regex ${CURL_LIBRARIES} fmt::fmt kql diff --git a/components/core/src/clp/aws/AwsAuthenticationSigner.cpp b/components/core/src/clp/aws/AwsAuthenticationSigner.cpp new file mode 100644 index 000000000..ae4da33a2 --- /dev/null +++ b/components/core/src/clp/aws/AwsAuthenticationSigner.cpp @@ -0,0 +1,351 @@ +#include "AwsAuthenticationSigner.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../ErrorCode.hpp" +#include "../hash_utils.hpp" +#include "../type_utils.hpp" +#include "constants.hpp" + +using clp::string_utils::is_alphabet; +using clp::string_utils::is_decimal_digit; +using std::string; +using std::string_view; +using std::vector; + +namespace clp::aws { +namespace { +/** + * @param c + * @return Whether `c` is an unreserved character AWS Signature Version 4 protocol specifies. + */ +[[nodiscard]] auto is_unreserved_characters(char c) -> bool; + +/** + * Gets the formatted timestamp string specified by AWS Signature Version 4 format. + * @param timestamp + * @return The formatted timestamp string. + */ +[[nodiscard]] auto get_formatted_timestamp_string( + std::chrono::system_clock::time_point const& timestamp +) -> string; + +/** + * Gets the formatted date string specified by AWS Signature Version 4 format. + * @param timestamp + * @return The formatted date string. + */ +[[nodiscard]] auto get_formatted_date_string(std::chrono::system_clock::time_point const& timestamp +) -> string; + +/** + * Gets the string to sign required by AWS Signature Version 4 protocol. + * @param scope + * @param timestamp + * @param canonical_request + * @param string_to_sign Outputs the string to sign. + * @return ErrorCode_Success on success. + * @return Same as `get_sha256_hash` on failure. + */ +[[nodiscard]] auto get_string_to_sign( + string_view scope, + string_view timestamp, + string_view canonical_request, + string& string_to_sign +) -> ErrorCode; + +/** + * Encodes the Canonical URI as specified by AWS Signature Version 4's UriEncode. + * This method encodes the forward slash character, '/', everywhere except in the object key. + * @param uri + * @param is_object_key + * @return The encoded URI. + */ +[[nodiscard]] auto encode_uri(string_view uri, bool is_object_key) -> string; + +/** + * @param date + * @param region + * @return The formatted scope required by ASW Signature Version 4 protocol. + */ +[[nodiscard]] auto get_scope(string_view date, string_view region) -> string; + +/** + * @param url + * @param query_string + * @return Formatted canonical request string. + */ +[[nodiscard]] auto get_canonical_request(S3Url const& url, string_view query_string) -> string; + +auto is_unreserved_characters(char c) -> bool { + return is_alphabet(c) || is_decimal_digit(c) || c == '-' || c == '_' || c == '.' || c == '~'; +} + +auto get_formatted_timestamp_string(std::chrono::system_clock::time_point const& timestamp +) -> string { + return fmt::format("{:%Y%m%dT%H%M%SZ}", timestamp); +} + +auto get_formatted_date_string(std::chrono::system_clock::time_point const& timestamp) -> string { + return fmt::format("{:%Y%m%d}", timestamp); +} + +auto get_string_to_sign( + string_view scope, + string_view timestamp, + string_view canonical_request, + string& string_to_sign +) -> ErrorCode { + vector signed_canonical_request; + if (auto const error_code = get_sha256_hash( + {size_checked_pointer_cast(canonical_request.data()), + canonical_request.size()}, + signed_canonical_request + ); + ErrorCode_Success != error_code) + { + return error_code; + } + auto const signed_canonical_request_str = convert_to_hex_string( + {signed_canonical_request.data(), signed_canonical_request.size()} + ); + string_to_sign = fmt::format( + "{}\n{}\n{}\n{}", + cAws4HmacSha256, + timestamp, + scope, + signed_canonical_request_str + ); + return ErrorCode_Success; +} + +auto encode_uri(string_view uri, bool is_object_key) -> string { + string encoded_uri; + + for (auto const c : uri) { + if (is_unreserved_characters(c) || ('/' == c) && is_object_key) { + encoded_uri += c; + } else { + encoded_uri += fmt::format("%{:02X}", c); + } + } + + return encoded_uri; +} + +auto get_scope(string_view date, string_view region) -> string { + return fmt::format("{}/{}/{}/{}", date, region, cS3Service, cAws4Request); +} + +auto get_canonical_request(S3Url const& url, string_view query_string) -> string { + auto const uri_to_encode = fmt::format("/{}", url.get_key()); + return fmt::format( + "{}\n{}\n{}\n{}:{}\n\n{}\n{}", + AwsAuthenticationSigner::cHttpGetMethod, + encode_uri(uri_to_encode, true), + query_string, + cDefaultSignedHeaders, + url.get_host(), + cDefaultSignedHeaders, + cUnsignedPayload + ); +} +} // namespace + +S3Url::S3Url(string const& url) { + // Virtual-hosted-style HTTP URL format: https://[bucket].s3.[region].[endpoint]/[key] + boost::regex const host_style_url_regex{ + R"(https://(?[a-z0-9.-]+)\.s3(\.(?[a-z0-9-]+))?)" + R"(\.(?[a-z0-9.-]+)/(?[^?]+).*)" + }; + // Path-style HTTP URL format: https://s3.[region].[endpoint]/[bucket]/[key] + boost::regex const path_style_url_regex{ + R"(https://s3(\.(?[a-z0-9-]+))?)" + R"(\.(?[a-z0-9.-]+)/(?[a-z0-9.-]+)/(?[^?]+).*)" + }; + + if (boost::smatch match; boost::regex_match(url, match, host_style_url_regex) + || boost::regex_match(url, match, path_style_url_regex)) + { + m_region = match["region"]; + m_bucket = match["bucket"]; + m_key = match["key"]; + m_end_point = match["endpoint"]; + } else { + throw OperationFailed( + ErrorCode_BadParam, + __FILENAME__, + __LINE__, + "Invalid S3 HTTP URL format: " + url + ); + } + + if (cAwsEndpoint != m_end_point) { + throw OperationFailed( + ErrorCode_BadParam, + __FILENAME__, + __LINE__, + "Invalid S3 endpoint: " + m_end_point + ); + } + + if (m_region.empty()) { + m_region = cDefaultRegion; + } + m_host = fmt::format("{}.s3.{}.{}", m_bucket, m_region, m_end_point); +} + +auto AwsAuthenticationSigner::generate_presigned_url( + S3Url const& s3_url, + string& presigned_url +) const -> ErrorCode { + auto const s3_region = s3_url.get_region(); + + auto const now = std::chrono::system_clock::now(); + auto const timestamp = get_formatted_timestamp_string(now); + auto const date = get_formatted_date_string(now); + + auto const scope = get_scope(date, s3_region); + auto const canonical_query_string = get_canonical_query_string(scope, timestamp); + + auto const canonical_request = get_canonical_request(s3_url, canonical_query_string); + + string string_to_sign; + if (auto const error_code + = get_string_to_sign(scope, timestamp, canonical_request, string_to_sign); + ErrorCode_Success != error_code) + { + return error_code; + } + + vector signature; + if (auto const error_code = get_signature(s3_region, date, string_to_sign, signature); + ErrorCode_Success != error_code) + { + return error_code; + } + auto const signature_str = convert_to_hex_string({signature.data(), signature.size()}); + + presigned_url = fmt::format( + "https://{}/{}?{}&{}={}", + s3_url.get_host(), + s3_url.get_key(), + canonical_query_string, + cXAmzSignature, + signature_str + ); + return ErrorCode_Success; +} + +auto AwsAuthenticationSigner::get_canonical_query_string( + string_view scope, + string_view timestamp +) const -> string { + auto const uri = fmt::format("{}/{}", m_access_key_id, scope); + return fmt::format( + "{}={}&{}={}&{}={}&{}={}&{}={}", + cXAmzAlgorithm, + cAws4HmacSha256, + cXAmzCredential, + encode_uri(uri, false), + cXAmzDate, + timestamp, + cXAmzExpires, + cDefaultExpireTime.count(), + cXAmzSignedHeaders, + cDefaultSignedHeaders + ); +} + +auto AwsAuthenticationSigner::get_signing_key( + string_view region, + string_view date, + vector& signing_key +) const -> ErrorCode { + auto const key = fmt::format("{}{}", cAws4, m_secret_access_key); + + vector date_key; + if (auto const error_code = get_hmac_sha256_hash( + {size_checked_pointer_cast(date.data()), date.size()}, + {size_checked_pointer_cast(key.data()), key.size()}, + date_key + ); + error_code != ErrorCode_Success) + { + return error_code; + } + + vector date_region_key; + if (auto const error_code = get_hmac_sha256_hash( + {size_checked_pointer_cast(region.data()), region.size()}, + {size_checked_pointer_cast(date_key.data()), date_key.size()}, + date_region_key + ); + error_code != ErrorCode_Success) + { + return error_code; + } + + vector date_region_service_key; + if (auto const error_code = get_hmac_sha256_hash( + {size_checked_pointer_cast(cS3Service.data()), + cS3Service.size()}, + {size_checked_pointer_cast(date_region_key.data()), + date_region_key.size()}, + date_region_service_key + ); + error_code != ErrorCode_Success) + { + return error_code; + } + + if (auto const error_code = get_hmac_sha256_hash( + {size_checked_pointer_cast(cAws4Request.data()), + cAws4Request.size()}, + {size_checked_pointer_cast(date_region_service_key.data()), + date_region_service_key.size()}, + signing_key + ); + error_code != ErrorCode_Success) + { + return error_code; + } + + return ErrorCode_Success; +} + +auto AwsAuthenticationSigner::get_signature( + string_view region, + string_view date, + string_view string_to_sign, + vector& signature +) const -> ErrorCode { + vector signing_key; + if (auto const error_code = get_signing_key(region, date, signing_key); + ErrorCode_Success != error_code) + { + return error_code; + } + + if (auto const error_code = get_hmac_sha256_hash( + {size_checked_pointer_cast(string_to_sign.data()), + string_to_sign.size()}, + {size_checked_pointer_cast(signing_key.data()), + signing_key.size()}, + signature + ); + ErrorCode_Success != error_code) + { + return error_code; + } + return ErrorCode_Success; +} +} // namespace clp::aws diff --git a/components/core/src/clp/aws/AwsAuthenticationSigner.hpp b/components/core/src/clp/aws/AwsAuthenticationSigner.hpp new file mode 100644 index 000000000..a0a82eb2a --- /dev/null +++ b/components/core/src/clp/aws/AwsAuthenticationSigner.hpp @@ -0,0 +1,136 @@ +#ifndef CLP_AWS_AWSAUTHENTICATIONSIGNER_HPP +#define CLP_AWS_AWSAUTHENTICATIONSIGNER_HPP + +#include +#include +#include +#include +#include + +#include "../ErrorCode.hpp" +#include "../TraceableException.hpp" + +namespace clp::aws { +/** + * Class for a parsed S3 URL. + */ +class S3Url { +public: + // Types + class OperationFailed : public TraceableException { + public: + // Constructors + OperationFailed( + ErrorCode error_code, + char const* const filename, + int line_number, + std::string message = "S3Url operation failed" + ) + : TraceableException{error_code, filename, line_number}, + m_message{std::move(message)} {} + + // Methods + [[nodiscard]] auto what() const noexcept -> char const* override { + return m_message.c_str(); + } + + private: + std::string m_message; + }; + + // Constructor + explicit S3Url(std::string const& url); + + // Methods + [[nodiscard]] auto get_region() const -> std::string_view { return m_region; } + + [[nodiscard]] auto get_bucket() const -> std::string_view { return m_bucket; } + + [[nodiscard]] auto get_key() const -> std::string_view { return m_key; } + + [[nodiscard]] auto get_host() const -> std::string_view { return m_host; } + +private: + std::string m_region; + std::string m_end_point; + std::string m_bucket; + std::string m_key; + std::string m_host; +}; + +/** + * Class for signing AWS requests based on AWS Signature Version 4. + */ +class AwsAuthenticationSigner { +public: + // Constants + // Default expire time of presigned URL in seconds + static constexpr std::chrono::seconds cDefaultExpireTime{86'400}; + static constexpr std::string_view cHttpGetMethod{"GET"}; + + // Constructors + AwsAuthenticationSigner(std::string access_key_id, std::string secret_access_key) + : m_access_key_id{std::move(access_key_id)}, + m_secret_access_key{std::move(secret_access_key)} {} + + // Methods + /** + * Generates a presigned S3 URL using AWS Signature Version 4 protocol. + * NOTE: the current implementation only supports generating URLs for HTTP GET operations. + * @param s3_url + * @param presigned_url Returns the generated presigned URL. + * @return ErrorCode_Success on success. + * @return Same as `get_sha256_hash` and `AwsAuthenticationSigner::get_signature` on failure. + */ + [[nodiscard]] auto + generate_presigned_url(S3Url const& s3_url, std::string& presigned_url) const -> ErrorCode; + +private: + /** + * Generates the canonical query string. + * @param scope + * @param timestamp + * @return The canonical query string. + */ + [[nodiscard]] auto get_canonical_query_string( + std::string_view scope, + std::string_view timestamp + ) const -> std::string; + + /** + * Gets the signature signing key for the request. + * @param region + * @param date + * @param signing_key Returns the signing key. + * @return ErrorCode_Success on success. + * @return Same as `get_hmac_sha256_hash` on Failure. + */ + [[nodiscard]] auto get_signing_key( + std::string_view region, + std::string_view date, + std::vector& signing_key + ) const -> ErrorCode; + + /** + * Signs the `string_to_sign` with a generated signing key. + * @param region + * @param date + * @param string_to_sign `StringToSign` required by AWS Signature Version 4 protocol. + * @param signature Returns the signature. + * @return ErrorCode_Success on success. + * @return Same as `get_hmac_sha256_hash` on Failure. + */ + [[nodiscard]] auto get_signature( + std::string_view region, + std::string_view date, + std::string_view string_to_sign, + std::vector& signature + ) const -> ErrorCode; + + // Variables + std::string m_access_key_id; + std::string m_secret_access_key; +}; +} // namespace clp::aws + +#endif // CLP_AWS_AWSAUTHENTICATIONSIGNER_HPP diff --git a/components/core/src/clp/aws/constants.hpp b/components/core/src/clp/aws/constants.hpp new file mode 100644 index 000000000..caebe92a1 --- /dev/null +++ b/components/core/src/clp/aws/constants.hpp @@ -0,0 +1,28 @@ +#ifndef CLP_AWS_CONSTANTS_HPP +#define CLP_AWS_CONSTANTS_HPP + +#include + +namespace clp::aws { +// Endpoint +constexpr std::string_view cAwsEndpoint{"amazonaws.com"}; + +// Query String Parameter Names +constexpr std::string_view cXAmzAlgorithm{"X-Amz-Algorithm"}; +constexpr std::string_view cXAmzCredential{"X-Amz-Credential"}; +constexpr std::string_view cXAmzDate{"X-Amz-Date"}; +constexpr std::string_view cXAmzExpires{"X-Amz-Expires"}; +constexpr std::string_view cXAmzSignature{"X-Amz-Signature"}; +constexpr std::string_view cXAmzSignedHeaders{"X-Amz-SignedHeaders"}; + +// Other Constants +constexpr std::string_view cAws4{"AWS4"}; +constexpr std::string_view cAws4Request{"aws4_request"}; +constexpr std::string_view cAws4HmacSha256{"AWS4-HMAC-SHA256"}; +constexpr std::string_view cDefaultSignedHeaders{"host"}; +constexpr std::string_view cDefaultRegion{"us-east-1"}; +constexpr std::string_view cS3Service{"s3"}; +constexpr std::string_view cUnsignedPayload{"UNSIGNED-PAYLOAD"}; +} // namespace clp::aws + +#endif // CLP_AWS_CONSTANTS_HPP diff --git a/components/core/tools/scripts/lib_install/install-boost.sh b/components/core/tools/scripts/lib_install/install-boost.sh index 064368725..9e5f9a1c5 100755 --- a/components/core/tools/scripts/lib_install/install-boost.sh +++ b/components/core/tools/scripts/lib_install/install-boost.sh @@ -34,7 +34,7 @@ tar xzf ${tar_filename} cd boost_${version_with_underscores} # Build -./bootstrap.sh --with-libraries=filesystem,iostreams,program_options,system +./bootstrap.sh --with-libraries=filesystem,iostreams,program_options,regex,system ./b2 -j${num_cpus} # Install From 4df670154bf0e5365d93d1e3bbca16eb95113c75 Mon Sep 17 00:00:00 2001 From: Abigail Matthews Date: Wed, 21 Aug 2024 17:05:39 -0400 Subject: [PATCH 055/114] core: Replace `typedef`s with type aliases. (#520) --- components/core/src/clp/Defs.h | 14 +++++------ components/core/src/clp/DictionaryWriter.hpp | 2 +- components/core/src/clp/Grep.hpp | 2 +- components/core/src/clp_s/Defs.hpp | 14 +++++------ .../core/src/clp_s/DictionaryWriter.hpp | 2 +- components/core/src/clp_s/ReaderUtils.hpp | 2 +- .../src/clp_s/TimestampDictionaryReader.hpp | 6 ++--- .../src/clp_s/TimestampDictionaryWriter.hpp | 2 +- .../src/clp_s/search/ColumnDescriptor.hpp | 2 +- .../core/src/clp_s/search/Expression.hpp | 2 +- components/core/src/clp_s/search/Integral.hpp | 2 +- components/core/src/clp_s/search/Literal.hpp | 2 +- .../core/src/clp_s/search/OrOfAndForm.hpp | 4 ++-- components/core/src/glt/Defs.h | 24 +++++++++---------- components/core/src/glt/DictionaryWriter.hpp | 2 +- components/core/src/glt/Grep.hpp | 2 +- .../glt/streaming_archive/reader/Archive.hpp | 2 +- 17 files changed, 43 insertions(+), 43 deletions(-) diff --git a/components/core/src/clp/Defs.h b/components/core/src/clp/Defs.h index f4a96ef9b..02eb34258 100644 --- a/components/core/src/clp/Defs.h +++ b/components/core/src/clp/Defs.h @@ -7,19 +7,19 @@ namespace clp { // Types -typedef int64_t epochtime_t; +using epochtime_t = int64_t; constexpr epochtime_t cEpochTimeMin = std::numeric_limits::min(); constexpr epochtime_t cEpochTimeMax = std::numeric_limits::max(); -typedef uint64_t variable_dictionary_id_t; +using variable_dictionary_id_t = uint64_t; constexpr variable_dictionary_id_t cVariableDictionaryIdMax = std::numeric_limits::max(); -typedef int64_t logtype_dictionary_id_t; +using logtype_dictionary_id_t = int64_t; constexpr logtype_dictionary_id_t cLogtypeDictionaryIdMax = std::numeric_limits::max(); -typedef uint16_t archive_format_version_t; +using archive_format_version_t = uint16_t; // This flag is used to maintain two separate streams of archive format // versions: // - Development versions (which can change frequently as necessary) which @@ -28,12 +28,12 @@ typedef uint16_t archive_format_version_t; // as possible) which should not have the flag constexpr archive_format_version_t cArchiveFormatDevVersionFlag = 0x8000; -typedef uint64_t segment_id_t; +using segment_id_t = uint64_t; constexpr segment_id_t cInvalidSegmentId = std::numeric_limits::max(); -typedef int64_t encoded_variable_t; +using encoded_variable_t = int64_t; -typedef uint64_t group_id_t; +using group_id_t = uint64_t; // Constants constexpr char cDefaultConfigFilename[] = ".clp.rc"; diff --git a/components/core/src/clp/DictionaryWriter.hpp b/components/core/src/clp/DictionaryWriter.hpp index 9e3541913..7cac9d5aa 100644 --- a/components/core/src/clp/DictionaryWriter.hpp +++ b/components/core/src/clp/DictionaryWriter.hpp @@ -83,7 +83,7 @@ class DictionaryWriter { protected: // Types - typedef std::unordered_map value_to_id_t; + using value_to_id_t = std::unordered_map; // Variables bool m_is_open; diff --git a/components/core/src/clp/Grep.hpp b/components/core/src/clp/Grep.hpp index ebd007bae..f520af212 100644 --- a/components/core/src/clp/Grep.hpp +++ b/components/core/src/clp/Grep.hpp @@ -22,7 +22,7 @@ class Grep { * @param decompressed_msg * @param custom_arg Custom argument for the output function */ - typedef void (*OutputFunc)( + using OutputFunc = void (*)( std::string const& orig_file_path, streaming_archive::reader::Message const& compressed_msg, std::string const& decompressed_msg, diff --git a/components/core/src/clp_s/Defs.hpp b/components/core/src/clp_s/Defs.hpp index 2615098b7..ce2200a05 100644 --- a/components/core/src/clp_s/Defs.hpp +++ b/components/core/src/clp_s/Defs.hpp @@ -11,7 +11,7 @@ namespace clp_s { // Types -typedef int64_t epochtime_t; +using epochtime_t = int64_t; static epochtime_t const cEpochTimeMin = INT64_MIN; static epochtime_t const cEpochTimeMax = INT64_MAX; static double const cDoubleEpochTimeMin = std::numeric_limits::lowest(); @@ -20,21 +20,21 @@ static double const cDoubleEpochTimeMax = std::numeric_limits::max(); #define MICROSECONDS_TO_EPOCHTIME(x) 0 #define EPOCHTIME_T_PRINTF_FMT PRId64 -typedef uint64_t variable_dictionary_id_t; +using variable_dictionary_id_t = uint64_t; static variable_dictionary_id_t const cVariableDictionaryIdMax = UINT64_MAX; -typedef int64_t logtype_dictionary_id_t; +using logtype_dictionary_id_t = int64_t; static logtype_dictionary_id_t const cLogtypeDictionaryIdMax = INT64_MAX; -typedef uint16_t archive_format_version_t; +using archive_format_version_t = uint16_t; // This flag is used to maintain two separate streams of archive format versions: // - Development versions (which can change frequently as necessary) which should have the flag // - Production versions (which should be changed with care and as infrequently as possible) // which should not have the flag constexpr archive_format_version_t cArchiveFormatDevelopmentVersionFlag = 0x8000; -typedef uint64_t file_id_t; -typedef uint64_t segment_id_t; -typedef int64_t encoded_variable_t; +using file_id_t = uint64_t; +using segment_id_t = uint64_t; +using encoded_variable_t = int64_t; } // namespace clp_s // Macros diff --git a/components/core/src/clp_s/DictionaryWriter.hpp b/components/core/src/clp_s/DictionaryWriter.hpp index 9aaebdb4a..0ae136036 100644 --- a/components/core/src/clp_s/DictionaryWriter.hpp +++ b/components/core/src/clp_s/DictionaryWriter.hpp @@ -50,7 +50,7 @@ class DictionaryWriter { protected: // Types - typedef std::unordered_map value_to_id_t; + using value_to_id_t = std::unordered_map; // Variables bool m_is_open; diff --git a/components/core/src/clp_s/ReaderUtils.hpp b/components/core/src/clp_s/ReaderUtils.hpp index 220947a21..caa509d6a 100644 --- a/components/core/src/clp_s/ReaderUtils.hpp +++ b/components/core/src/clp_s/ReaderUtils.hpp @@ -18,7 +18,7 @@ class ReaderUtils { : TraceableException(error_code, filename, line_number) {} }; - typedef std::map SchemaMap; + using SchemaMap = std::map; static constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB /** diff --git a/components/core/src/clp_s/TimestampDictionaryReader.hpp b/components/core/src/clp_s/TimestampDictionaryReader.hpp index 132debfd4..3364c565c 100644 --- a/components/core/src/clp_s/TimestampDictionaryReader.hpp +++ b/components/core/src/clp_s/TimestampDictionaryReader.hpp @@ -73,9 +73,9 @@ class TimestampDictionaryReader { } private: - typedef std::map id_to_pattern_t; - typedef std::vector, TimestampEntry*>> - tokenized_column_to_range_t; + using id_to_pattern_t = std::map; + using tokenized_column_to_range_t + = std::vector, TimestampEntry*>>; // Variables bool m_is_open; diff --git a/components/core/src/clp_s/TimestampDictionaryWriter.hpp b/components/core/src/clp_s/TimestampDictionaryWriter.hpp index d040b0b56..81266b187 100644 --- a/components/core/src/clp_s/TimestampDictionaryWriter.hpp +++ b/components/core/src/clp_s/TimestampDictionaryWriter.hpp @@ -107,7 +107,7 @@ class TimestampDictionaryWriter { ZstdCompressor& compressor ); - typedef std::unordered_map pattern_to_id_t; + using pattern_to_id_t = std::unordered_map; // Variables bool m_is_open; diff --git a/components/core/src/clp_s/search/ColumnDescriptor.hpp b/components/core/src/clp_s/search/ColumnDescriptor.hpp index 0dc348817..7341ff07a 100644 --- a/components/core/src/clp_s/search/ColumnDescriptor.hpp +++ b/components/core/src/clp_s/search/ColumnDescriptor.hpp @@ -72,7 +72,7 @@ class DescriptorToken { std::string m_token; }; -typedef std::vector DescriptorList; +using DescriptorList = std::vector; DescriptorList tokenize_descriptor(std::vector const& descriptors); diff --git a/components/core/src/clp_s/search/Expression.hpp b/components/core/src/clp_s/search/Expression.hpp index 3b67bc16e..2919b75ae 100644 --- a/components/core/src/clp_s/search/Expression.hpp +++ b/components/core/src/clp_s/search/Expression.hpp @@ -8,7 +8,7 @@ #include "Value.hpp" namespace clp_s::search { -typedef std::list> OpList; +using OpList = std::list>; /** * Top level class for all logical expressions which represent filters diff --git a/components/core/src/clp_s/search/Integral.hpp b/components/core/src/clp_s/search/Integral.hpp index 0f54aff80..b46870c32 100644 --- a/components/core/src/clp_s/search/Integral.hpp +++ b/components/core/src/clp_s/search/Integral.hpp @@ -8,7 +8,7 @@ #include "Literal.hpp" namespace clp_s::search { -typedef std::variant Integral64; +using Integral64 = std::variant; // FIXME: figure out why String types are part of this bitmask constexpr LiteralTypeBitmask cIntegralLiteralTypes = cIntegralTypes | VarStringT; diff --git a/components/core/src/clp_s/search/Literal.hpp b/components/core/src/clp_s/search/Literal.hpp index 8374e01e6..af9b9b2f0 100644 --- a/components/core/src/clp_s/search/Literal.hpp +++ b/components/core/src/clp_s/search/Literal.hpp @@ -24,7 +24,7 @@ enum LiteralType : uint32_t { UnknownT = ((uint32_t)1) << 31 }; -typedef uint32_t LiteralTypeBitmask; +using LiteralTypeBitmask = uint32_t; constexpr LiteralTypeBitmask cIntegralTypes = LiteralType::IntegerT | LiteralType::FloatT; constexpr LiteralTypeBitmask cAllTypes = TypesEnd - 1; diff --git a/components/core/src/clp_s/search/OrOfAndForm.hpp b/components/core/src/clp_s/search/OrOfAndForm.hpp index 7a400eb3f..acc8254a2 100644 --- a/components/core/src/clp_s/search/OrOfAndForm.hpp +++ b/components/core/src/clp_s/search/OrOfAndForm.hpp @@ -8,8 +8,8 @@ #include "Transformation.hpp" namespace clp_s::search { -typedef std::vector> ExpressionVector; -typedef std::list> ExpressionList; +using ExpressionVector = std::vector>; +using ExpressionList = std::list>; // TODO: handle degenerate forms like empty or/and expressions class OrOfAndForm : public Transformation { diff --git a/components/core/src/glt/Defs.h b/components/core/src/glt/Defs.h index 82517d32c..40429489b 100644 --- a/components/core/src/glt/Defs.h +++ b/components/core/src/glt/Defs.h @@ -8,21 +8,21 @@ namespace glt { // Types -typedef int64_t epochtime_t; +using epochtime_t = int64_t; constexpr epochtime_t cEpochTimeMin = std::numeric_limits::min(); constexpr epochtime_t cEpochTimeMax = std::numeric_limits::max(); #define SECONDS_TO_EPOCHTIME(x) x * 1000 #define MICROSECONDS_TO_EPOCHTIME(x) 0 -typedef uint64_t variable_dictionary_id_t; +using variable_dictionary_id_t = uint64_t; constexpr variable_dictionary_id_t cVariableDictionaryIdMax = std::numeric_limits::max(); -typedef int64_t logtype_dictionary_id_t; +using logtype_dictionary_id_t = int64_t; constexpr logtype_dictionary_id_t cLogtypeDictionaryIdMax = std::numeric_limits::max(); -typedef uint16_t archive_format_version_t; +using archive_format_version_t = uint16_t; // This flag is used to maintain two separate streams of archive format // versions: // - Development versions (which can change frequently as necessary) which @@ -31,19 +31,19 @@ typedef uint16_t archive_format_version_t; // as possible) which should not have the flag constexpr archive_format_version_t cArchiveFormatDevVersionFlag = 0x8000; -typedef uint32_t file_id_t; -typedef uint64_t segment_id_t; +using file_id_t = uint32_t; +using segment_id_t = uint64_t; constexpr segment_id_t cInvalidSegmentId = std::numeric_limits::max(); -typedef size_t offset_t; -typedef int64_t encoded_variable_t; -typedef uint64_t combined_table_id_t; +using offset_t = size_t; +using encoded_variable_t = int64_t; +using combined_table_id_t = uint64_t; -typedef uint64_t group_id_t; +using group_id_t = uint64_t; -typedef uint64_t pipeline_id_t; +using pipeline_id_t = uint64_t; constexpr pipeline_id_t cPipelineIdMax = std::numeric_limits::max(); -typedef std::atomic_uint64_t atomic_pipeline_id_t; +using atomic_pipeline_id_t = std::atomic_uint64_t; // Macros // Rounds up VALUE to be a multiple of MULTIPLE diff --git a/components/core/src/glt/DictionaryWriter.hpp b/components/core/src/glt/DictionaryWriter.hpp index cbab4184b..ccd4b49dd 100644 --- a/components/core/src/glt/DictionaryWriter.hpp +++ b/components/core/src/glt/DictionaryWriter.hpp @@ -98,7 +98,7 @@ class DictionaryWriter { protected: // Types - typedef std::unordered_map value_to_id_t; + using value_to_id_t = std::unordered_map; // Variables bool m_is_open; diff --git a/components/core/src/glt/Grep.hpp b/components/core/src/glt/Grep.hpp index 240859d41..1ec319f62 100644 --- a/components/core/src/glt/Grep.hpp +++ b/components/core/src/glt/Grep.hpp @@ -20,7 +20,7 @@ class Grep { * @param decompressed_msg * @param custom_arg Custom argument for the output function */ - typedef void (*OutputFunc)( + using OutputFunc = void (*)( std::string const& orig_file_path, streaming_archive::reader::Message const& compressed_msg, std::string const& decompressed_msg, diff --git a/components/core/src/glt/streaming_archive/reader/Archive.hpp b/components/core/src/glt/streaming_archive/reader/Archive.hpp index 5588f692f..bdf35feaf 100644 --- a/components/core/src/glt/streaming_archive/reader/Archive.hpp +++ b/components/core/src/glt/streaming_archive/reader/Archive.hpp @@ -42,7 +42,7 @@ class Archive { * @param decompressed_msg * @param custom_arg Custom argument for the output function */ - typedef void (*OutputFunc)( + using OutputFunc = void (*)( std::string const& orig_file_path, streaming_archive::reader::Message const& compressed_msg, std::string const& decompressed_msg, From ab92468ea76f05fabc39c8ab5c059a617f932585 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:35:38 -0400 Subject: [PATCH 056/114] clp-core: Add a new FileReader class that uses system call without buffering. (#516) Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> --- components/core/CMakeLists.txt | 3 + components/core/src/clp/FileDescriptor.cpp | 9 +- components/core/src/clp/FileDescriptor.hpp | 9 ++ .../core/src/clp/FileDescriptorReader.cpp | 58 ++++++++++ .../core/src/clp/FileDescriptorReader.hpp | 104 ++++++++++++++++++ components/core/src/clp/ReaderInterface.hpp | 3 + .../core/tests/test-FileDescriptorReader.cpp | 81 ++++++++++++++ 7 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 components/core/src/clp/FileDescriptorReader.cpp create mode 100644 components/core/src/clp/FileDescriptorReader.hpp create mode 100644 components/core/tests/test-FileDescriptorReader.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 37baf9b39..1d93bc27b 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -348,6 +348,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/Value.hpp src/clp/FileDescriptor.cpp src/clp/FileDescriptor.hpp + src/clp/FileDescriptorReader.cpp + src/clp/FileDescriptorReader.hpp src/clp/FileReader.cpp src/clp/FileReader.hpp src/clp/FileWriter.cpp @@ -484,6 +486,7 @@ set(SOURCE_FILES_unitTest tests/test-encoding_methods.cpp tests/test-ffi_KeyValuePairLogEvent.cpp tests/test-ffi_SchemaTree.cpp + tests/test-FileDescriptorReader.cpp tests/test-Grep.cpp tests/test-hash_utils.cpp tests/test-ir_encoding_methods.cpp diff --git a/components/core/src/clp/FileDescriptor.cpp b/components/core/src/clp/FileDescriptor.cpp index 2e17bfe05..480859bd7 100644 --- a/components/core/src/clp/FileDescriptor.cpp +++ b/components/core/src/clp/FileDescriptor.cpp @@ -50,7 +50,7 @@ FileDescriptor::~FileDescriptor() { auto FileDescriptor::get_size() const -> size_t { struct stat stat_result {}; - if (0 != fstat(m_fd, &stat_result)) { + if (ErrorCode_Success != stat(stat_result)) { throw OperationFailed( ErrorCode_errno, __FILE__, @@ -60,4 +60,11 @@ auto FileDescriptor::get_size() const -> size_t { } return static_cast(stat_result.st_size); } + +auto FileDescriptor::stat(struct stat& stat_buffer) const -> ErrorCode { + if (0 != fstat(m_fd, &stat_buffer)) { + return ErrorCode_errno; + } + return ErrorCode_Success; +} } // namespace clp diff --git a/components/core/src/clp/FileDescriptor.hpp b/components/core/src/clp/FileDescriptor.hpp index a704326bf..6770f3aef 100644 --- a/components/core/src/clp/FileDescriptor.hpp +++ b/components/core/src/clp/FileDescriptor.hpp @@ -2,6 +2,7 @@ #define CLP_FILEDESCRIPTOR_HPP #include +#include #include #include @@ -83,6 +84,14 @@ class FileDescriptor { */ [[nodiscard]] auto get_open_mode() const -> OpenMode { return m_open_mode; } + /** + * Obtains information about the open file associated with the underlying file descriptor. + * @param stat_buffer Returns the stat results. + * @return ErrorCode_Success on success. + * @return ErrorCode_errno on error. + */ + [[nodiscard]] auto stat(struct stat& stat_buffer) const -> ErrorCode; + private: int m_fd{-1}; OpenMode m_open_mode; diff --git a/components/core/src/clp/FileDescriptorReader.cpp b/components/core/src/clp/FileDescriptorReader.cpp new file mode 100644 index 000000000..4beb926a9 --- /dev/null +++ b/components/core/src/clp/FileDescriptorReader.cpp @@ -0,0 +1,58 @@ +#include "FileDescriptorReader.hpp" + +#include +#include + +#include +#include +#include + +#include "ErrorCode.hpp" + +using std::span; + +namespace clp { +auto FileDescriptorReader::try_read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) + -> ErrorCode { + if (nullptr == buf) { + return ErrorCode_BadParam; + } + + num_bytes_read = 0; + span dst_view{buf, num_bytes_to_read}; + while (false == dst_view.empty()) { + auto const bytes_read = ::read(m_fd.get_raw_fd(), dst_view.data(), dst_view.size()); + if (0 == bytes_read) { + break; + } + if (bytes_read < 0) { + return ErrorCode_errno; + } + num_bytes_read += bytes_read; + dst_view = dst_view.subspan(bytes_read); + } + if (dst_view.size() == num_bytes_to_read) { + return ErrorCode_EndOfFile; + } + return ErrorCode_Success; +} + +auto FileDescriptorReader::try_seek_from_begin(size_t pos) -> ErrorCode { + if (auto const offset = lseek(m_fd.get_raw_fd(), static_cast(pos), SEEK_SET); + static_cast(-1) == offset) + { + return ErrorCode_errno; + } + + return ErrorCode_Success; +} + +auto FileDescriptorReader::try_get_pos(size_t& pos) -> ErrorCode { + auto const curr_offset = lseek(m_fd.get_raw_fd(), 0, SEEK_CUR); + if (static_cast(-1) == curr_offset) { + return ErrorCode_errno; + } + pos = static_cast(curr_offset); + return ErrorCode_Success; +} +} // namespace clp diff --git a/components/core/src/clp/FileDescriptorReader.hpp b/components/core/src/clp/FileDescriptorReader.hpp new file mode 100644 index 000000000..ca751471a --- /dev/null +++ b/components/core/src/clp/FileDescriptorReader.hpp @@ -0,0 +1,104 @@ +#ifndef CLP_FILEDESCRIPTORREADER_HPP +#define CLP_FILEDESCRIPTORREADER_HPP + +#include + +#include +#include +#include +#include + +#include "ErrorCode.hpp" +#include "FileDescriptor.hpp" +#include "ReaderInterface.hpp" +#include "TraceableException.hpp" + +namespace clp { +/** + * Class for performing direct reads from an on-disk file using `clp::FileDescriptor` and C-style + * system call. Unlike `clp::FileReader`, which uses on `FILE` stream interface to buffer read data, + * this class does not buffer data internally. Instead, the user of this class is expected to + * buffer and read the data efficiently. + * + * Note: If you don't plan to handle the data buffering yourself, do not use this class. Use + * `clp::FileReader` instead. + */ +class FileDescriptorReader : public ReaderInterface { +public: + // Types + class OperationFailed : public TraceableException { + public: + // Constructors + OperationFailed(ErrorCode error_code, char const* const filename, int line_number) + : TraceableException(error_code, filename, line_number) {} + + // Methods + [[nodiscard]] auto what() const noexcept -> char const* override { + return "clp::FileDescriptorReader operation failed"; + } + }; + + // Constructors + explicit FileDescriptorReader(std::string path) + : m_path{std::move(path)}, + m_fd{m_path, FileDescriptor::OpenMode::ReadOnly} {} + + // Explicitly disable copy constructor and assignment operator + FileDescriptorReader(FileDescriptorReader const&) = delete; + auto operator=(FileDescriptorReader const&) -> FileDescriptorReader& = delete; + + // Explicitly disable move constructor and assignment operator + FileDescriptorReader(FileDescriptorReader&&) = delete; + auto operator=(FileDescriptorReader&&) -> FileDescriptorReader& = delete; + + // Destructor + ~FileDescriptorReader() override = default; + + // Methods implementing the ReaderInterface + /** + * Tries to read up to a given number of bytes from the file. + * @param buf + * @param num_bytes_to_read The number of bytes to try and read + * @param num_bytes_read The actual number of bytes read + * @return ErrorCode_BadParam if buf is invalid + * @return ErrorCode_errno on error + * @return ErrorCode_EndOfFile on EOF + * @return ErrorCode_Success on success + */ + [[nodiscard]] auto + try_read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) -> ErrorCode override; + + /** + * Tries to seek to the given position, relative to the beginning of the file. + * @param pos + * @return ErrorCode_errno on error + * @return ErrorCode_Success on success + */ + [[nodiscard]] auto try_seek_from_begin(size_t pos) -> ErrorCode override; + + /** + @param pos Returns the position of the read head in the buffer. + * @return ErrorCode_errno on error + * @return ErrorCode_Success on success + */ + [[nodiscard]] auto try_get_pos(size_t& pos) -> ErrorCode override; + + // Methods + [[nodiscard]] auto get_path() const -> std::string_view { return m_path; } + + /** + * Obtains information about the open file associated with the underlying file descriptor. + * @param stat_buffer Returns the stat results. + * @return Same as `FileDescriptor::fstat` + */ + [[nodiscard]] auto try_fstat(struct stat& stat_buffer) const -> ErrorCode { + return m_fd.stat(stat_buffer); + } + +private: + std::string m_path; + FileDescriptor m_fd; +}; +} // namespace clp + +#endif // CLP_FILEDESCRIPTORREADER_HPP diff --git a/components/core/src/clp/ReaderInterface.hpp b/components/core/src/clp/ReaderInterface.hpp index 39f914c2d..0a33598ce 100644 --- a/components/core/src/clp/ReaderInterface.hpp +++ b/components/core/src/clp/ReaderInterface.hpp @@ -22,6 +22,9 @@ class ReaderInterface { char const* what() const noexcept override { return "ReaderInterface operation failed"; } }; + // Destructor + virtual ~ReaderInterface() = default; + // Methods virtual ErrorCode try_read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) = 0; virtual ErrorCode try_seek_from_begin(size_t pos) = 0; diff --git a/components/core/tests/test-FileDescriptorReader.cpp b/components/core/tests/test-FileDescriptorReader.cpp new file mode 100644 index 000000000..eba592e85 --- /dev/null +++ b/components/core/tests/test-FileDescriptorReader.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +#include + +#include "../src/clp/Array.hpp" +#include "../src/clp/FileDescriptorReader.hpp" +#include "../src/clp/FileReader.hpp" +#include "../src/clp/ReaderInterface.hpp" + +using clp::Array; + +namespace { +// Reused code starts +constexpr size_t cDefaultReaderBufferSize{1024}; + +[[nodiscard]] auto get_test_input_local_path() -> std::string; + +[[nodiscard]] auto get_test_input_path_relative_to_tests_dir() -> std::filesystem::path; + +/** + * @param reader + * @param read_buf_size The size of the buffer to use for individual reads from the reader. + * @return All data read from the given reader. + */ +auto get_content(clp::ReaderInterface& reader, size_t read_buf_size = cDefaultReaderBufferSize) + -> std::vector; + +auto get_test_input_local_path() -> std::string { + std::filesystem::path const current_file_path{__FILE__}; + auto const tests_dir{current_file_path.parent_path()}; + return (tests_dir / get_test_input_path_relative_to_tests_dir()).string(); +} + +auto get_test_input_path_relative_to_tests_dir() -> std::filesystem::path { + return std::filesystem::path{"test_log_files"} / "log.txt"; +} + +auto get_content(clp::ReaderInterface& reader, size_t read_buf_size) -> std::vector { + std::vector buf; + Array read_buf{read_buf_size}; + for (bool has_more_content{true}; has_more_content;) { + size_t num_bytes_read{}; + has_more_content = reader.read(read_buf.data(), read_buf_size, num_bytes_read); + std::string_view const view{read_buf.data(), num_bytes_read}; + buf.insert(buf.cend(), view.cbegin(), view.cend()); + } + return buf; +} +} // namespace + +// Reused code ends + +TEST_CASE("file_descriptor_reader_basic", "[FileDescriptorReader]") { + clp::FileReader ref_reader{get_test_input_local_path()}; + auto const expected{get_content(ref_reader)}; + + clp::FileDescriptorReader reader{get_test_input_local_path()}; + auto const actual{get_content(reader)}; + REQUIRE((actual == expected)); +} + +TEST_CASE("file_descriptor_reader_with_offset_and_seek", "[FileDescriptorReader]") { + constexpr size_t cOffset{319}; + + clp::FileReader ref_reader{get_test_input_local_path()}; + ref_reader.seek_from_begin(cOffset); + auto const expected{get_content(ref_reader)}; + auto const ref_end_pos{ref_reader.get_pos()}; + + clp::FileDescriptorReader reader(get_test_input_local_path()); + reader.seek_from_begin(cOffset); + auto const actual{get_content(reader)}; + auto const actual_end_pos{reader.get_pos()}; + + REQUIRE((actual_end_pos == ref_end_pos)); + REQUIRE((actual == expected)); +} From 54b832cb146b36f2d07c8f686c3cf9c98853509d Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:54:00 -0400 Subject: [PATCH 057/114] core: Add support for retrieving CURL error messages, handle unexpected CURL return code on macOS, and log such codes in tests (fixes #519). (#517) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../core/src/clp/CurlDownloadHandler.cpp | 18 ++++- .../core/src/clp/CurlDownloadHandler.hpp | 8 +++ components/core/src/clp/NetworkReader.cpp | 9 +++ components/core/src/clp/NetworkReader.hpp | 17 +++++ components/core/tests/test-NetworkReader.cpp | 71 +++++++++++++------ 5 files changed, 102 insertions(+), 21 deletions(-) diff --git a/components/core/src/clp/CurlDownloadHandler.cpp b/components/core/src/clp/CurlDownloadHandler.cpp index 8ec8fbfb6..9a2720083 100644 --- a/components/core/src/clp/CurlDownloadHandler.cpp +++ b/components/core/src/clp/CurlDownloadHandler.cpp @@ -2,13 +2,16 @@ #include #include +#include #include #include +#include #include namespace clp { CurlDownloadHandler::CurlDownloadHandler( + std::shared_ptr error_msg_buf, ProgressCallback progress_callback, WriteCallback write_callback, void* arg, @@ -17,7 +20,17 @@ CurlDownloadHandler::CurlDownloadHandler( bool disable_caching, std::chrono::seconds connection_timeout, std::chrono::seconds overall_timeout -) { +) + : m_error_msg_buf{std::move(error_msg_buf)} { + if (nullptr != m_error_msg_buf) { + // Set up error message buffer + // According to the docs (https://curl.se/libcurl/c/CURLOPT_ERRORBUFFER.html), since 7.60.0, + // a successful call to set `CURLOPT_ERRORBUFFER` will initialize the buffer to an empty + // string 7.60.0. Since we require at least 7.68.0, we don't need to clear the provided + // buffer before it's used. + m_easy_handle.set_option(CURLOPT_ERRORBUFFER, m_error_msg_buf->data()); + } + // Set up src url m_easy_handle.set_option(CURLOPT_URL, src_url.data()); @@ -46,5 +59,8 @@ CurlDownloadHandler::CurlDownloadHandler( if (false == m_http_headers.is_empty()) { m_easy_handle.set_option(CURLOPT_HTTPHEADER, m_http_headers.get_raw_list()); } + + // Set up failure on HTTP error reponse + m_easy_handle.set_option(CURLOPT_FAILONERROR, static_cast(true)); } } // namespace clp diff --git a/components/core/src/clp/CurlDownloadHandler.hpp b/components/core/src/clp/CurlDownloadHandler.hpp index b45f644ca..6421257ba 100644 --- a/components/core/src/clp/CurlDownloadHandler.hpp +++ b/components/core/src/clp/CurlDownloadHandler.hpp @@ -1,8 +1,10 @@ #ifndef CLP_CURLDOWNLOADHANDLER_HPP #define CLP_CURLDOWNLOADHANDLER_HPP +#include #include #include +#include #include #include @@ -18,6 +20,7 @@ namespace clp { class CurlDownloadHandler { public: // Types + using ErrorMsgBuf = std::array; /** * libcurl progress callback. This method must have C linkage. Doc: * https://curl.se/libcurl/c/CURLOPT_WRITEFUNCTION.html @@ -37,6 +40,9 @@ class CurlDownloadHandler { // Constructor /** + * @param error_msg_buf The buffer to store the CURL error message or `nullptr` if it shouldn't + * be stored. + * Doc: https://curl.se/libcurl/c/CURLOPT_ERRORBUFFER.html * @param progress_callback * @param write_callback * @param arg Argument to pass to `progress_callback` and `write_callback` @@ -49,6 +55,7 @@ class CurlDownloadHandler { * `connection_timeout`. Doc: https://curl.se/libcurl/c/CURLOPT_TIMEOUT.html */ explicit CurlDownloadHandler( + std::shared_ptr error_msg_buf, ProgressCallback progress_callback, WriteCallback write_callback, void* arg, @@ -78,6 +85,7 @@ class CurlDownloadHandler { private: CurlEasyHandle m_easy_handle; CurlStringList m_http_headers; + std::shared_ptr m_error_msg_buf; }; } // namespace clp diff --git a/components/core/src/clp/NetworkReader.cpp b/components/core/src/clp/NetworkReader.cpp index c0b5359bf..706763362 100644 --- a/components/core/src/clp/NetworkReader.cpp +++ b/components/core/src/clp/NetworkReader.cpp @@ -13,6 +13,7 @@ #include "CurlDownloadHandler.hpp" #include "CurlOperationFailed.hpp" #include "ErrorCode.hpp" +#include "Platform.hpp" namespace clp { /** @@ -158,6 +159,13 @@ auto NetworkReader::try_get_pos(size_t& pos) -> ErrorCode { // offset specified in the HTTP header. return ErrorCode_Failure; } + if constexpr (Platform::MacOs == cCurrentPlatform) { + // On macOS, HTTP response code 416 is not handled as `CURL_HTTP_RETURNED_ERROR` in + // some `libcurl` versions. + if (CURLE_RECV_ERROR == curl_return_code.value()) { + return ErrorCode_Failure; + } + } } if (false == at_least_one_byte_downloaded()) { @@ -200,6 +208,7 @@ auto NetworkReader::buffer_downloaded_data(NetworkReader::BufferView data) -> si auto NetworkReader::DownloaderThread::thread_method() -> void { try { CurlDownloadHandler curl_handler{ + m_reader.m_curl_error_msg_buf, curl_progress_callback, curl_write_callback, static_cast(&m_reader), diff --git a/components/core/src/clp/NetworkReader.hpp b/components/core/src/clp/NetworkReader.hpp index 68e6d1019..ba581d067 100644 --- a/components/core/src/clp/NetworkReader.hpp +++ b/components/core/src/clp/NetworkReader.hpp @@ -216,6 +216,19 @@ class NetworkReader : public ReaderInterface { return m_curl_ret_code.load(); } + /** + * @return The error message set by the underlying CURL handler. + * @return std::nullopt if the download is still in-progress or no error has occured. + */ + [[nodiscard]] auto get_curl_error_msg() const -> std::optional { + if (auto const ret_code{get_curl_ret_code()}; + false == ret_code.has_value() || CURLE_OK == ret_code.value()) + { + return std::nullopt; + } + return std::string_view{m_curl_error_msg_buf->data()}; + } + private: /** * This class implements clp::Thread to download data using CURL. @@ -334,6 +347,10 @@ class NetworkReader : public ReaderInterface { // These two members should only be set from `set_download_completion_status` std::atomic m_state{State::InProgress}; std::atomic> m_curl_ret_code; + + std::shared_ptr m_curl_error_msg_buf{ + std::make_shared() + }; }; } // namespace clp diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index 38172507d..5a900ced3 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -16,6 +16,7 @@ #include "../src/clp/ErrorCode.hpp" #include "../src/clp/FileReader.hpp" #include "../src/clp/NetworkReader.hpp" +#include "../src/clp/Platform.hpp" #include "../src/clp/ReaderInterface.hpp" namespace { @@ -35,6 +36,16 @@ constexpr size_t cDefaultReaderBufferSize{1024}; auto get_content(clp::ReaderInterface& reader, size_t read_buf_size = cDefaultReaderBufferSize) -> std::vector; +/** + * Asserts whether the given `CURLcode` and the CURL return code stored in the given `NetworkReader` + * instance are the same, and prints a log message if not. + * @param expected + * @param reader + * @return Whether the the assertion succeeded. + */ +[[nodiscard]] auto +assert_curl_error_code(CURLcode expected, clp::NetworkReader const& reader) -> bool; + auto get_test_input_local_path() -> std::string { std::filesystem::path const current_file_path{__FILE__}; auto const tests_dir{current_file_path.parent_path()}; @@ -64,6 +75,28 @@ auto get_content(clp::ReaderInterface& reader, size_t read_buf_size) -> std::vec } return buf; } + +auto assert_curl_error_code(CURLcode expected, clp::NetworkReader const& reader) -> bool { + auto const ret_code{reader.get_curl_ret_code()}; + if (false == ret_code.has_value()) { + WARN("The CURL error code hasn't been set yet in the given reader."); + return false; + } + auto const actual{ret_code.value()}; + if (expected == actual) { + return true; + } + std::string message_to_log{ + "Unexpected CURL error code: " + std::to_string(actual) + + "; expected: " + std::to_string(expected) + }; + auto const curl_error_message{reader.get_curl_error_msg()}; + if (curl_error_message.has_value()) { + message_to_log += "\nError message:\n" + std::string{curl_error_message.value()}; + } + WARN(message_to_log); + return false; +} } // namespace TEST_CASE("network_reader_basic", "[NetworkReader]") { @@ -73,10 +106,7 @@ TEST_CASE("network_reader_basic", "[NetworkReader]") { clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url()}; auto const actual{get_content(reader)}; - auto const ret_code{reader.get_curl_ret_code()}; - REQUIRE(ret_code.has_value()); - // NOLINTNEXTLINE(bugprone-unchecked-optional-access) - REQUIRE((CURLE_OK == ret_code.value())); + REQUIRE(assert_curl_error_code(CURLE_OK, reader)); REQUIRE((actual == expected)); } @@ -92,10 +122,7 @@ TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url(), cOffset}; auto const actual{get_content(reader)}; - auto const ret_code{reader.get_curl_ret_code()}; - REQUIRE(ret_code.has_value()); - // NOLINTNEXTLINE(bugprone-unchecked-optional-access) - REQUIRE((CURLE_OK == ret_code.value())); + REQUIRE(assert_curl_error_code(CURLE_OK, reader)); REQUIRE((reader.get_pos() == ref_end_pos)); REQUIRE((actual == expected)); } @@ -106,10 +133,7 @@ TEST_CASE("network_reader_with_offset_and_seek", "[NetworkReader]") { clp::NetworkReader reader(get_test_input_remote_url()); reader.seek_from_begin(cOffset); auto const actual{get_content(reader)}; - auto const ret_code{reader.get_curl_ret_code()}; - REQUIRE(ret_code.has_value()); - // NOLINTNEXTLINE(bugprone-unchecked-optional-access) - REQUIRE((CURLE_OK == ret_code.value())); + REQUIRE(assert_curl_error_code(CURLE_OK, reader)); REQUIRE((reader.get_pos() == ref_end_pos)); REQUIRE((actual == expected)); } @@ -147,13 +171,20 @@ TEST_CASE("network_reader_illegal_offset", "[NetworkReader]") { constexpr size_t cIllegalOffset{UINT32_MAX}; clp::CurlGlobalInstance const curl_global_instance; clp::NetworkReader reader{get_test_input_remote_url(), cIllegalOffset}; - while (true) { - auto const ret_code{reader.get_curl_ret_code()}; - if (ret_code.has_value()) { - REQUIRE((CURLE_HTTP_RETURNED_ERROR == ret_code.value())); - size_t pos{}; - REQUIRE((clp::ErrorCode_Failure == reader.try_get_pos(pos))); - break; - } + while (false == reader.get_curl_ret_code().has_value()) { + // Wait until the return code is ready + } + + if constexpr (clp::Platform::MacOs == clp::cCurrentPlatform) { + // On macOS, HTTP response code 416 is not handled as `CURL_HTTP_RETURNED_ERROR` in some + // `libcurl` versions. + REQUIRE( + (assert_curl_error_code(CURLE_HTTP_RETURNED_ERROR, reader) + || assert_curl_error_code(CURLE_RECV_ERROR, reader)) + ); + } else { + REQUIRE(assert_curl_error_code(CURLE_HTTP_RETURNED_ERROR, reader)); } + size_t pos{}; + REQUIRE((clp::ErrorCode_Failure == reader.try_get_pos(pos))); } From fee4afeb79fe0dba03eae0f5284a62636ae71b96 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 22 Aug 2024 22:54:28 -0400 Subject: [PATCH 058/114] regex-utils: Use `PUBLIC` include visibility for public library headers; Add missing link targets. (#522) --- components/core/src/clp/regex_utils/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/core/src/clp/regex_utils/CMakeLists.txt b/components/core/src/clp/regex_utils/CMakeLists.txt index c5d54dde0..e8fcfe556 100644 --- a/components/core/src/clp/regex_utils/CMakeLists.txt +++ b/components/core/src/clp/regex_utils/CMakeLists.txt @@ -13,8 +13,9 @@ add_library( ) add_library(clp::regex_utils ALIAS regex_utils) target_include_directories(regex_utils - PRIVATE + PUBLIC ../ "${PROJECT_SOURCE_DIR}/submodules" ) +target_link_libraries(regex_utils PRIVATE clp::string_utils) target_compile_features(regex_utils PRIVATE cxx_std_20) From ea7678fca67b6f560667dda9f7ac7b7e723b6ff7 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sun, 25 Aug 2024 16:55:40 -0400 Subject: [PATCH 059/114] ffi: Add `Deserializer` class to deserialize log events from key-value pair IR format. (#511) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 2 + .../src/clp/ffi/ir_stream/Deserializer.cpp | 734 ++++++++++++++++++ .../src/clp/ffi/ir_stream/Deserializer.hpp | 73 ++ .../clp/ffi/ir_stream/decoding_methods.cpp | 94 +-- .../clp/ffi/ir_stream/decoding_methods.hpp | 21 + .../clp/ffi/ir_stream/protocol_constants.hpp | 2 + .../core/src/clp/ffi/ir_stream/utils.hpp | 33 + .../core/tests/test-ir_encoding_methods.cpp | 61 +- 8 files changed, 973 insertions(+), 47 deletions(-) create mode 100644 components/core/src/clp/ffi/ir_stream/Deserializer.cpp create mode 100644 components/core/src/clp/ffi/ir_stream/Deserializer.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 1d93bc27b..c4f84570c 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -314,6 +314,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/encoding_methods.hpp src/clp/ffi/encoding_methods.inc src/clp/ffi/ir_stream/byteswap.hpp + src/clp/ffi/ir_stream/Deserializer.cpp + src/clp/ffi/ir_stream/Deserializer.hpp src/clp/ffi/ir_stream/decoding_methods.cpp src/clp/ffi/ir_stream/decoding_methods.hpp src/clp/ffi/ir_stream/decoding_methods.inc diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp new file mode 100644 index 000000000..453d58bcf --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp @@ -0,0 +1,734 @@ +#include "Deserializer.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../../ErrorCode.hpp" +#include "../../ir/EncodedTextAst.hpp" +#include "../../ir/types.hpp" +#include "../../ReaderInterface.hpp" +#include "../../time_types.hpp" +#include "../../type_utils.hpp" +#include "../KeyValuePairLogEvent.hpp" +#include "../SchemaTree.hpp" +#include "../SchemaTreeNode.hpp" +#include "../Value.hpp" +#include "decoding_methods.hpp" +#include "protocol_constants.hpp" +#include "utils.hpp" + +namespace clp::ffi::ir_stream { +namespace { +/** + * A collection of schema tree leaf node IDs. It represents the schema of a `KeyValuePairLogEvent`. + */ +using Schema = std::vector; + +/** + * Class to perform different actions depending on whether a transaction succeeds or fails. The + * default state assumes the transaction fails. + * @tparam SuccessHandler A cleanup lambda to call on success. + * @tparam FailureHandler A cleanup lambda to call on failure. + */ +template +requires(std::is_invocable_v && std::is_invocable_v) +class TransactionManager { +public: + // Constructor + TransactionManager(SuccessHandler success_handler, FailureHandler failure_handler) + : m_success_handler{success_handler}, + m_failure_handler{failure_handler} {} + + // Delete copy/move constructor and assignment + TransactionManager(TransactionManager const&) = delete; + TransactionManager(TransactionManager&&) = delete; + auto operator=(TransactionManager const&) -> TransactionManager& = delete; + auto operator=(TransactionManager&&) -> TransactionManager& = delete; + + // Destructor + ~TransactionManager() { + if (m_success) { + m_success_handler(); + } else { + m_failure_handler(); + } + } + + // Methods + /** + * Marks the transaction as successful. + */ + auto mark_success() -> void { m_success = true; } + +private: + // Variables + SuccessHandler m_success_handler; + FailureHandler m_failure_handler; + bool m_success{false}; +}; + +/** + * @param ir_error_code + * @return Equivalent `std::errc` code indicating the same error type. + */ +[[nodiscard]] auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc; + +/** + * @param tag + * @return Whether the tag represents a schema tree node. + */ +[[nodiscard]] auto is_schema_tree_node_tag(encoded_tag_t tag) -> bool; + +/** + * @param tag + * @return The corresponding schema tree node type on success. + * @return std::nullopt if the tag doesn't match to any defined schema tree node type. + */ +[[nodiscard]] auto schema_tree_node_tag_to_type(encoded_tag_t tag +) -> std::optional; + +/** + * Deserializes the parent ID of a schema tree node. + * @param reader + * @param parent_id Returns the deserialized result. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the next packet in the stream isn't a parent ID. + * @return Same as `deserialize_tag` on any other failure. + */ +[[nodiscard]] auto deserialize_schema_tree_node_parent_id( + ReaderInterface& reader, + SchemaTreeNode::id_t& parent_id +) -> IRErrorCode; + +/** + * Deserializes the key name of a schema tree node. + * @param reader + * @param key_name Returns the deserialized key name. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return Same as `deserialize_tag` or `deserialize_string` on failure. + */ +[[nodiscard]] auto deserialize_schema_tree_node_key_name( + ReaderInterface& reader, + std::string& key_name +) -> IRErrorCode; + +/** + * Deserializes an integer value packet. + * @param reader + * @param tag + * @param val Returns the deserialized value. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the given tag doesn't correspond to an integer + * packet. + */ +[[nodiscard]] auto +deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val) -> IRErrorCode; + +/** + * Deserializes a string packet. + * @param reader + * @param tag + * @param deserialized_str Returns the deserialized string. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the given tag doesn't correspond to a string + * packet. + */ +[[nodiscard]] auto deserialize_string( + ReaderInterface& reader, + encoded_tag_t tag, + std::string& deserialized_str +) -> IRErrorCode; + +/** + * Deserializes all UTC offset packets until a non-UTC offset packet tag is read. + * @param reader + * @param tag Takes the current tag as input and returns the last tag read. + * @param utc_offset Returns the deserialized UTC offset. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return Same as `deserialize_utc_offset_change` or `deserialize_tag` on failure. + */ +[[nodiscard]] auto deserialize_utc_offset_changes( + ReaderInterface& reader, + encoded_tag_t& tag, + UtcOffset& utc_offset +) -> IRErrorCode; + +/** + * Deserializes all schema tree node packets and inserts them into the schema tree until a non- + * schema tree node tag is read. + * @param reader + * @param tag Takes the current tag as input and returns the last tag read. + * @param schema_tree Returns the schema tree with all new nodes inserted. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the packet tag doesn't correspond to any known + * schema node type or the node being deserialized already exists in the current in-memory schema + * tree. + * @return Same as `deserialize_schema_tree_node_parent_id`, `deserialize_string`, or + * `deserialize_tag` on any other failure. + */ +[[nodiscard]] auto deserialize_schema_tree_nodes( + ReaderInterface& reader, + encoded_tag_t& tag, + SchemaTree& schema_tree +) -> IRErrorCode; + +/** + * Deserializes the IDs of all keys in a log event. + * @param reader + * @param tag Takes the current tag as input and returns the last tag read. + * @param schema Returns the deserialized schema. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return Same as `deserialize_tag` on any other failure. + */ +[[nodiscard]] auto +deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) -> IRErrorCode; + +/** + * Deserializes the next value and pushes the result into `node_id_value_pairs`. + * @param reader + * @param tag + * @param node_id The node ID that corresponds to the value. + * @param node_id_value_pairs Returns the ID-value pair constructed from the deserialized value. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the tag doesn't correspond to any known value + * type. + * @return Same as `deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs` on any other + * failure. + */ +[[nodiscard]] auto deserialize_value_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode; + +/** + * Deserializes an encoded text AST and pushes the result into node_id_value_pairs. + * @tparam encoded_variable_t + * @param reader + * @param node_id The node ID that corresponds to the value. + * @param node_id_value_pairs Returns the ID-value pair constructed by the deserialized encoded text + * AST. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return Same as `deserialize_tag` or `deserialize_encoded_text_ast` on failure. + */ +template +requires(std::is_same_v + || std::is_same_v) +[[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode; + +/** + * Deserializes values and constructs ID-value pairs according to the given schema. The number of + * values to deserialize is indicated by the size of the given schema. + * @param reader + * @param tag + * @param schema The log event's schema. + * @param node_id_value_pairs Returns the constructed ID-value pairs. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if a key is duplicated in the deserialized log + * event. + * @return Same as `deserialize_tag` or `deserialize_value_and_insert_to_node_id_value_pairs` on any + * other failure. + */ +[[nodiscard]] auto deserialize_value_and_construct_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + Schema const& schema, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode; + +auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc { + switch (ir_error_code) { + case IRErrorCode_Incomplete_IR: + return std::errc::result_out_of_range; + case IRErrorCode_Corrupted_IR: + case IRErrorCode_Decode_Error: + return std::errc::protocol_error; + case IRErrorCode_Eof: + return std::errc::no_message_available; + default: + return std::errc::not_supported; + } +} + +auto is_schema_tree_node_tag(encoded_tag_t tag) -> bool { + return (tag & cProtocol::Payload::SchemaTreeNodeMask) == cProtocol::Payload::SchemaTreeNodeMask; +} + +auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { + switch (tag) { + case cProtocol::Payload::SchemaTreeNodeInt: + return SchemaTreeNode::Type::Int; + case cProtocol::Payload::SchemaTreeNodeFloat: + return SchemaTreeNode::Type::Float; + case cProtocol::Payload::SchemaTreeNodeBool: + return SchemaTreeNode::Type::Bool; + case cProtocol::Payload::SchemaTreeNodeStr: + return SchemaTreeNode::Type::Str; + case cProtocol::Payload::SchemaTreeNodeUnstructuredArray: + return SchemaTreeNode::Type::UnstructuredArray; + case cProtocol::Payload::SchemaTreeNodeObj: + return SchemaTreeNode::Type::Obj; + default: + return std::nullopt; + } +} + +auto deserialize_schema_tree_node_parent_id( + ReaderInterface& reader, + SchemaTreeNode::id_t& parent_id +) -> IRErrorCode { + encoded_tag_t tag{}; + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + if (cProtocol::Payload::SchemaTreeNodeParentIdUByte == tag) { + uint8_t deserialized_id{}; + if (false == deserialize_int(reader, deserialized_id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + parent_id = static_cast(deserialized_id); + } else if (cProtocol::Payload::SchemaTreeNodeParentIdUShort == tag) { + uint16_t deserialized_id{}; + if (false == deserialize_int(reader, deserialized_id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + parent_id = static_cast(deserialized_id); + } else { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + return IRErrorCode_Success; +} + +auto deserialize_schema_tree_node_key_name(ReaderInterface& reader, std::string& key_name) + -> IRErrorCode { + encoded_tag_t str_packet_tag{}; + if (auto const err{deserialize_tag(reader, str_packet_tag)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + if (auto const err{deserialize_string(reader, str_packet_tag, key_name)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val) + -> IRErrorCode { + if (cProtocol::Payload::ValueInt8 == tag) { + int8_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + // NOLINTNEXTLINE(bugprone-signed-char-misuse,cert-str34-c) + val = deserialized_val; + } else if (cProtocol::Payload::ValueInt16 == tag) { + int16_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else if (cProtocol::Payload::ValueInt32 == tag) { + int32_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else if (cProtocol::Payload::ValueInt64 == tag) { + int64_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_string(ReaderInterface& reader, encoded_tag_t tag, std::string& deserialized_str) + -> IRErrorCode { + size_t str_length{}; + if (cProtocol::Payload::StrLenUByte == tag) { + uint8_t length{}; + if (false == deserialize_int(reader, length)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + str_length = static_cast(length); + } else if (cProtocol::Payload::StrLenUShort == tag) { + uint16_t length{}; + if (false == deserialize_int(reader, length)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + str_length = static_cast(length); + } else if (cProtocol::Payload::StrLenUInt == tag) { + uint32_t length{}; + if (false == deserialize_int(reader, length)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + str_length = static_cast(length); + } else { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + if (clp::ErrorCode_Success != reader.try_read_string(str_length, deserialized_str)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_utc_offset_changes( + ReaderInterface& reader, + encoded_tag_t& tag, + UtcOffset& utc_offset +) -> IRErrorCode { + while (cProtocol::Payload::UtcOffsetChange == tag) { + if (auto const err{deserialize_utc_offset_change(reader, utc_offset)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_schema_tree_nodes( + ReaderInterface& reader, + encoded_tag_t& tag, + SchemaTree& schema_tree +) -> IRErrorCode { + while (is_schema_tree_node_tag(tag)) { + auto const type{schema_tree_node_tag_to_type(tag)}; + if (false == type.has_value()) { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + + SchemaTreeNode::id_t parent_id{}; + if (auto const err{deserialize_schema_tree_node_parent_id(reader, parent_id)}; + IRErrorCode_Success != err) + { + return err; + } + + std::string key_name; + if (auto const err{deserialize_schema_tree_node_key_name(reader, key_name)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + + // Insert the node to the schema tree + SchemaTree::NodeLocator const locator{parent_id, key_name, type.value()}; + if (schema_tree.has_node(locator)) { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + std::ignore = schema_tree.insert_node(locator); + + // Read the next tag + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) + -> IRErrorCode { + schema.clear(); + while (true) { + if (cProtocol::Payload::KeyIdUByte == tag) { + uint8_t id{}; + if (false == deserialize_int(reader, id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + schema.push_back(static_cast(id)); + } else if (cProtocol::Payload::KeyIdUShort == tag) { + uint16_t id{}; + if (false == deserialize_int(reader, id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + schema.push_back(static_cast(id)); + } else { + break; + } + + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + } + + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_value_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode { + switch (tag) { + case cProtocol::Payload::ValueInt8: + case cProtocol::Payload::ValueInt16: + case cProtocol::Payload::ValueInt32: + case cProtocol::Payload::ValueInt64: { + value_int_t value_int{}; + if (auto const err{deserialize_int_val(reader, tag, value_int)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + node_id_value_pairs.emplace(node_id, Value{value_int}); + break; + } + case cProtocol::Payload::ValueFloat: { + uint64_t val{}; + if (false == deserialize_int(reader, val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + node_id_value_pairs.emplace(node_id, Value{bit_cast(val)}); + break; + } + case cProtocol::Payload::ValueTrue: + node_id_value_pairs.emplace(node_id, Value{true}); + break; + case cProtocol::Payload::ValueFalse: + node_id_value_pairs.emplace(node_id, Value{false}); + break; + case cProtocol::Payload::StrLenUByte: + case cProtocol::Payload::StrLenUShort: + case cProtocol::Payload::StrLenUInt: { + std::string value_str; + if (auto const err{deserialize_string(reader, tag, value_str)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + node_id_value_pairs.emplace(node_id, Value{std::move(value_str)}); + break; + } + case cProtocol::Payload::ValueEightByteEncodingClpStr: + if (auto const err{deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs< + ir::eight_byte_encoded_variable_t>(reader, node_id, node_id_value_pairs)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + break; + case cProtocol::Payload::ValueFourByteEncodingClpStr: + if (auto const err{deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs< + ir::four_byte_encoded_variable_t>(reader, node_id, node_id_value_pairs)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + break; + case cProtocol::Payload::ValueNull: + node_id_value_pairs.emplace(node_id, Value{}); + break; + case cProtocol::Payload::ValueEmpty: + node_id_value_pairs.emplace(node_id, std::nullopt); + break; + default: + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + return IRErrorCode::IRErrorCode_Success; +} + +template +requires(std::is_same_v + || std::is_same_v) +[[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode { + encoded_tag_t tag{}; + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + + std::string logtype; + std::vector encoded_vars; + std::vector dict_vars; + if (auto const err{deserialize_encoded_text_ast(reader, tag, logtype, encoded_vars, dict_vars)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + + node_id_value_pairs.emplace( + node_id, + Value{ir::EncodedTextAst{logtype, dict_vars, encoded_vars}} + ); + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_value_and_construct_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + Schema const& schema, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode { + node_id_value_pairs.clear(); + node_id_value_pairs.reserve(schema.size()); + for (auto const node_id : schema) { + if (node_id_value_pairs.contains(node_id)) { + // The key should be unique in a schema + return IRErrorCode_Corrupted_IR; + } + + if (auto const err{deserialize_value_and_insert_to_node_id_value_pairs( + reader, + tag, + node_id, + node_id_value_pairs + )}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + + if (schema.size() != node_id_value_pairs.size()) { + if (auto const err{deserialize_tag(reader, tag)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + } + } + return IRErrorCode::IRErrorCode_Success; +} +} // namespace + +auto Deserializer::create(ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result { + bool is_four_byte_encoded{}; + if (auto const err{get_encoding_type(reader, is_four_byte_encoded)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + std::vector metadata; + encoded_tag_t metadata_type{}; + if (auto const err{deserialize_preamble(reader, metadata_type, metadata)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + if (cProtocol::Metadata::EncodingJson != metadata_type) { + return std::errc::protocol_not_supported; + } + + auto metadata_json = nlohmann::json::parse(metadata, nullptr, false); + if (metadata_json.is_discarded()) { + return std::errc::protocol_error; + } + auto const version_iter{metadata_json.find(cProtocol::Metadata::VersionKey)}; + if (metadata_json.end() == version_iter || false == version_iter->is_string()) { + return std::errc::protocol_error; + } + auto const version = version_iter->get_ref(); + // TODO: Just before the KV-pair IR format is formally released, we should replace this + // hard-coded version check with `ffi::ir_stream::validate_protocol_version`. + if (std::string_view{static_cast(cProtocol::Metadata::BetaVersionValue)} + != version) + { + return std::errc::protocol_not_supported; + } + + return Deserializer{}; +} + +auto Deserializer::deserialize_to_next_log_event(clp::ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result { + auto const utc_offset_snapshot{m_utc_offset}; + m_schema_tree->take_snapshot(); + TransactionManager revert_manager{ + []() -> void {}, + [&]() -> void { + m_utc_offset = utc_offset_snapshot; + m_schema_tree->revert(); + } + }; + + encoded_tag_t tag{}; + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return ir_error_code_to_errc(err); + } + + if (auto const err{deserialize_utc_offset_changes(reader, tag, m_utc_offset)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + if (auto const err{deserialize_schema_tree_nodes(reader, tag, *m_schema_tree)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + Schema schema; + if (auto const err{deserialize_schema(reader, tag, schema)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs; + if (false == schema.empty()) { + if (auto const err{deserialize_value_and_construct_node_id_value_pairs( + reader, + tag, + schema, + node_id_value_pairs + )}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + } else { + if (cProtocol::Payload::ValueEmpty != tag) { + return ir_error_code_to_errc(IRErrorCode::IRErrorCode_Corrupted_IR); + } + } + + auto result{KeyValuePairLogEvent::create( + m_schema_tree, + std::move(node_id_value_pairs), + m_utc_offset + )}; + if (false == result.has_error()) { + revert_manager.mark_success(); + } + + return std::move(result); +} +} // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp new file mode 100644 index 000000000..c7327fd5b --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp @@ -0,0 +1,73 @@ +#ifndef CLP_FFI_IR_STREAM_DESERIALIZER_HPP +#define CLP_FFI_IR_STREAM_DESERIALIZER_HPP + +#include + +#include + +#include "../../ReaderInterface.hpp" +#include "../../time_types.hpp" +#include "../KeyValuePairLogEvent.hpp" +#include "../SchemaTree.hpp" + +namespace clp::ffi::ir_stream { +/** + * A deserializer for log events from a CLP kv-pair IR stream. The class ensures any internal state + * remains consistent even when a deserialization failure occurs (i.e., it's transactional). + * + * NOTE: This class is designed only to provide deserialization functionalities. Callers are + * responsible for maintaining a `ReaderInterface` to input IR bytes from an I/O stream. + */ +class Deserializer { +public: + // Factory function + /** + * Creates a deserializer by reading the stream's preamble from the given reader. + * @param reader + * @return A result containing the deserializer or an error code indicating the failure: + * - std::errc::result_out_of_range if the IR stream is truncated + * - std::errc::protocol_error if the IR stream is corrupted + * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format + * or uses an unsupported version + */ + [[nodiscard]] static auto create(ReaderInterface& reader + ) -> OUTCOME_V2_NAMESPACE::std_result; + + // Delete copy constructor and assignment + Deserializer(Deserializer const&) = delete; + auto operator=(Deserializer const&) -> Deserializer& = delete; + + // Define default move constructor and assignment + Deserializer(Deserializer&&) = default; + auto operator=(Deserializer&&) -> Deserializer& = default; + + // Destructor + ~Deserializer() = default; + + // Methods + /** + * Deserializes the stream from the given reader up to and including the next log event. + * @param reader + * @return A result containing the deserialized log event or an error code indicating the + * failure: + * - std::errc::result_out_of_range if the IR stream is truncated + * - std::errc::protocol_error if the IR stream is corrupted + * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format + * or uses an unsupported version + * - Same as `KeyValuePairLogEvent::create` if the intermediate deserialized result cannot + * construct a valid key-value pair log event + */ + [[nodiscard]] auto deserialize_to_next_log_event(ReaderInterface& reader + ) -> OUTCOME_V2_NAMESPACE::std_result; + +private: + // Constructor + Deserializer() = default; + + // Variables + std::shared_ptr m_schema_tree{std::make_shared()}; + UtcOffset m_utc_offset{0}; +}; +} // namespace clp::ffi::ir_stream + +#endif // CLP_FFI_IR_STREAM_DESERIALIZER_HPP diff --git a/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp b/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp index 29f57df0a..9388470e4 100644 --- a/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp @@ -5,6 +5,7 @@ #include "../../ir/types.hpp" #include "byteswap.hpp" #include "protocol_constants.hpp" +#include "utils.hpp" using clp::ir::eight_byte_encoded_variable_t; using clp::ir::epoch_time_ms_t; @@ -24,16 +25,6 @@ namespace clp::ffi::ir_stream { template static bool is_variable_tag(encoded_tag_t tag, bool& is_encoded_var); -/** - * Deserializes an integer from the given reader - * @tparam integer_t Type of the integer to deserialize - * @param reader - * @param value Returns the deserialized integer - * @return true on success, false if the reader doesn't contain enough data to deserialize - */ -template -static bool deserialize_int(ReaderInterface& reader, integer_t& value); - /** * Deserializes a logtype from the given reader * @param reader @@ -138,27 +129,6 @@ static bool is_variable_tag(encoded_tag_t tag, bool& is_encoded_var) { return false; } -template -static bool deserialize_int(ReaderInterface& reader, integer_t& value) { - integer_t value_little_endian; - if (reader.try_read_numeric_value(value_little_endian) != ErrorCode_Success) { - return false; - } - - constexpr auto read_size = sizeof(integer_t); - static_assert(read_size == 1 || read_size == 2 || read_size == 4 || read_size == 8); - if constexpr (read_size == 1) { - value = value_little_endian; - } else if constexpr (read_size == 2) { - value = bswap_16(value_little_endian); - } else if constexpr (read_size == 4) { - value = bswap_32(value_little_endian); - } else if constexpr (read_size == 8) { - value = bswap_64(value_little_endian); - } - return true; -} - static IRErrorCode deserialize_logtype(ReaderInterface& reader, encoded_tag_t encoded_tag, string& logtype) { size_t logtype_length; @@ -362,6 +332,38 @@ auto deserialize_log_event( vector& encoded_vars, vector& dict_vars, epoch_time_ms_t& timestamp_or_timestamp_delta +) -> IRErrorCode { + if (auto const err + = deserialize_encoded_text_ast(reader, encoded_tag, logtype, encoded_vars, dict_vars); + IRErrorCode_Success != err) + { + return err; + } + + // NOTE: for the eight-byte encoding, the timestamp is the actual timestamp; for the four-byte + // encoding, the timestamp is a timestamp delta + if (ErrorCode_Success != reader.try_read_numeric_value(encoded_tag)) { + return IRErrorCode_Incomplete_IR; + } + if (auto error_code = deserialize_timestamp( + reader, + encoded_tag, + timestamp_or_timestamp_delta + ); + IRErrorCode_Success != error_code) + { + return error_code; + } + return IRErrorCode_Success; +} + +template +auto deserialize_encoded_text_ast( + ReaderInterface& reader, + encoded_tag_t encoded_tag, + std::string& logtype, + std::vector& encoded_vars, + std::vector& dict_vars ) -> IRErrorCode { // Handle variables string var_str; @@ -393,20 +395,6 @@ auto deserialize_log_event( return error_code; } - // NOTE: for the eight-byte encoding, the timestamp is the actual timestamp; for the four-byte - // encoding, the timestamp is a timestamp delta - if (ErrorCode_Success != reader.try_read_numeric_value(encoded_tag)) { - return IRErrorCode_Incomplete_IR; - } - if (auto error_code = deserialize_timestamp( - reader, - encoded_tag, - timestamp_or_timestamp_delta - ); - IRErrorCode_Success != error_code) - { - return error_code; - } return IRErrorCode_Success; } @@ -568,4 +556,20 @@ template auto deserialize_log_event( vector& dict_vars, epoch_time_ms_t& timestamp_or_timestamp_delta ) -> IRErrorCode; + +template auto deserialize_encoded_text_ast( + ReaderInterface& reader, + encoded_tag_t encoded_tag, + std::string& logtype, + std::vector& encoded_vars, + std::vector& dict_vars +) -> IRErrorCode; + +template auto deserialize_encoded_text_ast( + ReaderInterface& reader, + encoded_tag_t encoded_tag, + std::string& logtype, + std::vector& encoded_vars, + std::vector& dict_vars +) -> IRErrorCode; } // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp b/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp index 982b9c7aa..fb6f6a3c0 100644 --- a/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp +++ b/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp @@ -89,6 +89,27 @@ auto deserialize_log_event( ir::epoch_time_ms_t& timestamp_or_timestamp_delta ) -> IRErrorCode; +/** + * Deserializes an encoded text AST from the given stream + * @tparam encoded_variable_t + * @param reader + * @param encoded_tag Tag of the next packet to read + * @param logtype Returns the logtype + * @param encoded_vars Returns the encoded variables + * @param dict_vars Returns the dictionary variables + * @return IRErrorCode_Success on success + * @return IRErrorCode_Corrupted_IR if `reader` contains invalid IR + * @return IRErrorCode_Incomplete_IR if `reader` doesn't contain enough data + */ +template +auto deserialize_encoded_text_ast( + ReaderInterface& reader, + encoded_tag_t encoded_tag, + std::string& logtype, + std::vector& encoded_vars, + std::vector& dict_vars +) -> IRErrorCode; + /** * Decodes the IR message calls the given methods to handle each component of the message * @tparam unescape_logtype Whether to remove the escape characters from the logtype before calling diff --git a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp index 9f84cc4e1..915a8a56d 100644 --- a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp +++ b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp @@ -73,6 +73,8 @@ constexpr int8_t SchemaTreeNodeParentIdUShort = 0x61; constexpr int8_t KeyIdUByte = 0x65; constexpr int8_t KeyIdUShort = 0x66; +constexpr int8_t SchemaTreeNodeMask = 0x70; + constexpr int8_t SchemaTreeNodeInt = 0x71; constexpr int8_t SchemaTreeNodeFloat = 0x72; constexpr int8_t SchemaTreeNodeBool = 0x73; diff --git a/components/core/src/clp/ffi/ir_stream/utils.hpp b/components/core/src/clp/ffi/ir_stream/utils.hpp index 7879c3f74..b816c6385 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.hpp +++ b/components/core/src/clp/ffi/ir_stream/utils.hpp @@ -9,7 +9,9 @@ #include +#include "../../ErrorCode.hpp" #include "../../ir/types.hpp" +#include "../../ReaderInterface.hpp" #include "byteswap.hpp" #include "encoding_methods.hpp" #include "protocol_constants.hpp" @@ -33,6 +35,16 @@ serialize_metadata(nlohmann::json& metadata, std::vector& output_buf) -> template auto serialize_int(integer_t value, std::vector& output_buf) -> void; +/** + * Deserializes an integer from the given reader + * @tparam integer_t Type of the integer to deserialize + * @param reader + * @param value Returns the deserialized integer + * @return Whether the reader contained enough data to deserialize. + */ +template +[[nodiscard]] auto deserialize_int(ReaderInterface& reader, integer_t& value) -> bool; + /** * Serializes a string using CLP's encoding for unstructured text. * @tparam encoded_variable_t @@ -72,6 +84,27 @@ auto serialize_int(integer_t value, std::vector& output_buf) -> void { output_buf.insert(output_buf.end(), data_view.begin(), data_view.end()); } +template +auto deserialize_int(ReaderInterface& reader, integer_t& value) -> bool { + integer_t value_little_endian; + if (reader.try_read_numeric_value(value_little_endian) != clp::ErrorCode_Success) { + return false; + } + + constexpr auto cReadSize = sizeof(integer_t); + static_assert(cReadSize == 1 || cReadSize == 2 || cReadSize == 4 || cReadSize == 8); + if constexpr (cReadSize == 1) { + value = value_little_endian; + } else if constexpr (cReadSize == 2) { + value = bswap_16(value_little_endian); + } else if constexpr (cReadSize == 4) { + value = bswap_32(value_little_endian); + } else if constexpr (cReadSize == 8) { + value = bswap_64(value_little_endian); + } + return true; +} + template [[nodiscard]] auto serialize_clp_string( std::string_view str, diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index e9b161b8a..6eec92673 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -14,6 +14,7 @@ #include "../src/clp/ErrorCode.hpp" #include "../src/clp/ffi/encoding_methods.hpp" #include "../src/clp/ffi/ir_stream/decoding_methods.hpp" +#include "../src/clp/ffi/ir_stream/Deserializer.hpp" #include "../src/clp/ffi/ir_stream/encoding_methods.hpp" #include "../src/clp/ffi/ir_stream/protocol_constants.hpp" #include "../src/clp/ffi/ir_stream/Serializer.hpp" @@ -34,6 +35,7 @@ using clp::ffi::ir_stream::cProtocol::MagicNumberLength; using clp::ffi::ir_stream::deserialize_preamble; using clp::ffi::ir_stream::deserialize_tag; using clp::ffi::ir_stream::deserialize_utc_offset_change; +using clp::ffi::ir_stream::Deserializer; using clp::ffi::ir_stream::encoded_tag_t; using clp::ffi::ir_stream::get_encoding_type; using clp::ffi::ir_stream::IRErrorCode; @@ -150,6 +152,14 @@ template Serializer& serializer ) -> bool; +/** + * Counts the number of leaves in a JSON tree. A node is considered as a leaf if it's a primitive + * value, an empty map (`{}`), or an array. + * @param root + * @return The number of leaves under the given root. + */ +[[nodiscard]] auto count_num_leaves(nlohmann::json const& root) -> size_t; + template [[nodiscard]] auto serialize_log_events( vector const& log_events, @@ -275,6 +285,30 @@ auto unpack_and_serialize_msgpack_bytes( } return serializer.serialize_msgpack_map(msgpack_obj.via.map); } + +// NOLINTNEXTLINE(misc-no-recursion) +auto count_num_leaves(nlohmann::json const& root) -> size_t { + if (false == root.is_object()) { + return 0; + } + + size_t num_leaves{0}; + for (auto const& [key, val] : root.items()) { + if (val.is_primitive() || val.is_array()) { + ++num_leaves; + } else if (val.is_object()) { + if (val.empty()) { + ++num_leaves; + } else { + num_leaves += count_num_leaves(val); + } + } else { + FAIL("Unknown JSON object types."); + } + } + + return num_leaves; +} } // namespace /** @@ -1006,15 +1040,15 @@ TEMPLATE_TEST_CASE( ); } +// NOLINTNEXTLINE(readability-function-cognitive-complexity) TEMPLATE_TEST_CASE( "ffi_ir_stream_Serializer_serialize_msgpack", "[clp][ffi][ir_stream][Serializer]", four_byte_encoded_variable_t, eight_byte_encoded_variable_t ) { - // TODO: Test deserializing the serialized bytes once a KV-pair IR deserializer is implemented. - vector ir_buf; + vector serialized_json_objects; auto result{Serializer::create()}; REQUIRE((false == result.has_error())); @@ -1024,6 +1058,7 @@ TEMPLATE_TEST_CASE( auto const empty_obj = nlohmann::json::parse("{}"); REQUIRE(unpack_and_serialize_msgpack_bytes(nlohmann::json::to_msgpack(empty_obj), serializer)); + serialized_json_objects.emplace_back(empty_obj); // Test encoding basic object constexpr string_view cShortString{"short_string"}; @@ -1050,6 +1085,7 @@ TEMPLATE_TEST_CASE( {"empty_array", empty_array}}; REQUIRE(unpack_and_serialize_msgpack_bytes(nlohmann::json::to_msgpack(basic_obj), serializer)); + serialized_json_objects.emplace_back(basic_obj); auto basic_array = empty_array; basic_array.emplace_back(1); @@ -1083,5 +1119,26 @@ TEMPLATE_TEST_CASE( nlohmann::json::to_msgpack(recursive_obj), serializer )); + serialized_json_objects.emplace_back(recursive_obj); + } + + flush_and_clear_serializer_buffer(serializer, ir_buf); + + // Deserialize the results + BufferReader reader{size_checked_pointer_cast(ir_buf.data()), ir_buf.size()}; + auto deserializer_result = Deserializer::create(reader); + REQUIRE_FALSE(deserializer_result.has_error()); + auto& deserializer = deserializer_result.value(); + + for (auto const& json_obj : serialized_json_objects) { + auto const kv_log_event_result = deserializer.deserialize_to_next_log_event(reader); + REQUIRE_FALSE(kv_log_event_result.has_error()); + auto const& kv_log_event = kv_log_event_result.value(); + auto const num_leaves_in_json_obj = count_num_leaves(json_obj); + auto const num_kv_pairs = kv_log_event.get_node_id_value_pairs().size(); + REQUIRE((num_leaves_in_json_obj == num_kv_pairs)); } + + // TODO: Test validating the deserialized bytes once we've implemented a KeyValuePairLogEvent to + // JSON deserializer. } From e8be3c3e0e8b526c9aae84fd835ddb633dd32dcb Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:39:43 -0400 Subject: [PATCH 060/114] core: Mark spdlog specialization functions as const (fixes #524). (#525) --- components/core/src/clp/spdlog_with_specializations.hpp | 8 +++++--- components/core/src/glt/spdlog_with_specializations.hpp | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/core/src/clp/spdlog_with_specializations.hpp b/components/core/src/clp/spdlog_with_specializations.hpp index 24771f44e..e80993592 100644 --- a/components/core/src/clp/spdlog_with_specializations.hpp +++ b/components/core/src/clp/spdlog_with_specializations.hpp @@ -16,7 +16,7 @@ struct fmt::formatter { } template - auto format(clp::ErrorCode const& error_code, FormatContext& ctx) { + auto format(clp::ErrorCode const& error_code, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}", static_cast(error_code)); } }; @@ -30,7 +30,8 @@ struct fmt::formatter> template auto - format(clp::ffi::search::ExactVariableToken const& v, FormatContext& ctx) { + format(clp::ffi::search::ExactVariableToken const& v, + FormatContext& ctx) const { return fmt::format_to( ctx.out(), "ExactVariableToken(\"{}\") as {}", @@ -48,7 +49,8 @@ struct fmt::formatter> { } template - auto format(clp::ffi::search::WildcardToken const& v, FormatContext& ctx) { + auto + format(clp::ffi::search::WildcardToken const& v, FormatContext& ctx) const { return fmt::format_to( ctx.out(), "WildcardToken(\"{}\") as {}TokenType({}){}", diff --git a/components/core/src/glt/spdlog_with_specializations.hpp b/components/core/src/glt/spdlog_with_specializations.hpp index 8cd279e9e..1518d5a62 100644 --- a/components/core/src/glt/spdlog_with_specializations.hpp +++ b/components/core/src/glt/spdlog_with_specializations.hpp @@ -16,7 +16,7 @@ struct fmt::formatter { } template - auto format(glt::ErrorCode const& error_code, FormatContext& ctx) { + auto format(glt::ErrorCode const& error_code, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}", static_cast(error_code)); } }; @@ -30,7 +30,8 @@ struct fmt::formatter> template auto - format(glt::ffi::search::ExactVariableToken const& v, FormatContext& ctx) { + format(glt::ffi::search::ExactVariableToken const& v, + FormatContext& ctx) const { return fmt::format_to( ctx.out(), "ExactVariableToken(\"{}\") as {}", @@ -48,7 +49,8 @@ struct fmt::formatter> { } template - auto format(glt::ffi::search::WildcardToken const& v, FormatContext& ctx) { + auto + format(glt::ffi::search::WildcardToken const& v, FormatContext& ctx) const { return fmt::format_to( ctx.out(), "WildcardToken(\"{}\") as {}TokenType({}){}", From 9537fde393781e6ac889d0e37a88de5debb66172 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:47:16 -0400 Subject: [PATCH 061/114] Refactor dependency downloads: (#508) - Checksum dependencies using taskfiles rather than a separate script. - Move core's dependency download script into taskfiles. - Add support for downloading yscope-log-viewer even when no .git directory exists. --- .github/actions/clp-core-build/action.yaml | 14 +- .github/workflows/clp-core-build-macos.yaml | 13 +- .github/workflows/clp-core-build.yaml | 10 +- Taskfile.yml | 70 +-- .../clp-env-base-centos7.4/Dockerfile | 6 + .../clp-env-base-ubuntu-focal/Dockerfile | 6 + .../clp-env-base-ubuntu-jammy/Dockerfile | 6 + .../tools/scripts/deps-download/Catch2.json | 10 - .../scripts/deps-download/abseil-cpp.json | 10 - .../tools/scripts/deps-download/antlr4.json | 14 - .../tools/scripts/deps-download/date.json | 10 - .../scripts/deps-download/download-all.sh | 29 -- .../scripts/deps-download/download-dep.py | 95 ---- .../tools/scripts/deps-download/json.json | 10 - .../scripts/deps-download/log-surgeon.json | 10 - .../tools/scripts/deps-download/outcome.json | 10 - .../tools/scripts/deps-download/simdjson.json | 11 - .../tools/scripts/deps-download/sqlite3.json | 14 - .../tools/scripts/deps-download/yaml-cpp.json | 10 - .../lib_install/macos-12/install-all.sh | 2 + deps-tasks.yml | 445 ++++++++++++++++++ docs/src/dev-guide/building-package.md | 4 +- docs/src/dev-guide/components-core/index.md | 16 +- lint-tasks.yml | 2 + tools/scripts/deps-download/download-dep.py | 88 ++++ tools/scripts/deps-download/init.sh | 17 + tools/scripts/find-broken-docs-links.py | 58 +-- 27 files changed, 652 insertions(+), 338 deletions(-) delete mode 100644 components/core/tools/scripts/deps-download/Catch2.json delete mode 100644 components/core/tools/scripts/deps-download/abseil-cpp.json delete mode 100644 components/core/tools/scripts/deps-download/antlr4.json delete mode 100644 components/core/tools/scripts/deps-download/date.json delete mode 100755 components/core/tools/scripts/deps-download/download-all.sh delete mode 100644 components/core/tools/scripts/deps-download/download-dep.py delete mode 100644 components/core/tools/scripts/deps-download/json.json delete mode 100644 components/core/tools/scripts/deps-download/log-surgeon.json delete mode 100644 components/core/tools/scripts/deps-download/outcome.json delete mode 100644 components/core/tools/scripts/deps-download/simdjson.json delete mode 100644 components/core/tools/scripts/deps-download/sqlite3.json delete mode 100644 components/core/tools/scripts/deps-download/yaml-cpp.json create mode 100644 deps-tasks.yml create mode 100644 tools/scripts/deps-download/download-dep.py create mode 100755 tools/scripts/deps-download/init.sh diff --git a/.github/actions/clp-core-build/action.yaml b/.github/actions/clp-core-build/action.yaml index aed244c25..ab5070b09 100644 --- a/.github/actions/clp-core-build/action.yaml +++ b/.github/actions/clp-core-build/action.yaml @@ -18,10 +18,6 @@ inputs: runs: using: "composite" steps: - - shell: "bash" - working-directory: "./components/core" - run: "./tools/scripts/deps-download/download-all.sh" - - if: "inputs.use_published_image == 'false'" uses: "actions/download-artifact@v4" with: @@ -46,13 +42,19 @@ runs: fi shell: "bash" + - run: "./tools/scripts/deps-download/init.sh" + shell: "bash" + - run: >- docker run --user $(id -u):$(id -g) - --volume "$GITHUB_WORKSPACE/components/core":/mnt/clp + --volume "$GITHUB_WORKSPACE":/mnt/clp --workdir /mnt/clp ${{steps.get_image_props.outputs.qualified_image_name}} - /mnt/clp/tools/scripts/utils/build-and-run-unit-tests.sh . build + bash -c "task deps:core && + /mnt/clp/components/core/tools/scripts/utils/build-and-run-unit-tests.sh + /mnt/clp/components/core + /mnt/clp/components/core/build" shell: "bash" - if: "inputs.upload_binaries == 'true'" diff --git a/.github/workflows/clp-core-build-macos.yaml b/.github/workflows/clp-core-build-macos.yaml index c46dfc878..dc9e8209a 100644 --- a/.github/workflows/clp-core-build-macos.yaml +++ b/.github/workflows/clp-core-build-macos.yaml @@ -11,6 +11,9 @@ on: - "components/core/tools/scripts/lib_install/macos-12/**" - "components/core/tools/scripts/deps-download/**" - "components/core/tools/scripts/utils/build-and-run-unit-tests.sh" + - "deps-tasks.yml" + - "Taskfile.yml" + - "tools/scripts/deps-download/**" push: paths: - ".github/workflows/clp-core-build-macos.yaml" @@ -21,6 +24,9 @@ on: - "components/core/tools/scripts/lib_install/macos-12/**" - "components/core/tools/scripts/deps-download/**" - "components/core/tools/scripts/utils/build-and-run-unit-tests.sh" + - "deps-tasks.yml" + - "Taskfile.yml" + - "tools/scripts/deps-download/**" workflow_dispatch: concurrency: @@ -47,10 +53,11 @@ jobs: - name: "Install dependencies" run: "./components/core/tools/scripts/lib_install/macos-12/install-all.sh" - - name: "Download source dependencies" + - run: "./tools/scripts/deps-download/init.sh" + shell: "bash" + + - run: "task deps:core" shell: "bash" - working-directory: "./components/core" - run: "./tools/scripts/deps-download/download-all.sh" - name: "Build CLP-core and run unit tests" shell: "bash" diff --git a/.github/workflows/clp-core-build.yaml b/.github/workflows/clp-core-build.yaml index d0dbbb28a..47853375c 100644 --- a/.github/workflows/clp-core-build.yaml +++ b/.github/workflows/clp-core-build.yaml @@ -8,6 +8,9 @@ on: - ".github/workflows/clp-core-build.yaml" - ".gitmodules" - "components/core/**" + - "deps-tasks.yml" + - "Taskfile.yml" + - "tools/scripts/deps-download/**" - "!components/core/tools/scripts/lib_install/macos-12/**" push: paths: @@ -16,6 +19,9 @@ on: - ".github/workflows/clp-core-build.yaml" - ".gitmodules" - "components/core/**" + - "deps-tasks.yml" + - "Taskfile.yml" + - "tools/scripts/deps-download/**" - "!components/core/tools/scripts/lib_install/macos-12/**" workflow_dispatch: @@ -83,8 +89,10 @@ jobs: - "components/core/CMakeLists.txt" - "components/core/src/**" - "components/core/tests/**" - - "components/core/tools/scripts/deps-download/**" - "components/core/tools/scripts/utils/build-and-run-unit-tests.sh" + - "deps-tasks.yml" + - "Taskfile.yml" + - "tools/scripts/deps-download/**" centos74-deps-image: if: "needs.filter-relevant-changes.outputs.centos74_image_changed == 'true'" diff --git a/Taskfile.yml b/Taskfile.yml index 5b818c6e1..5912bd579 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,16 +1,22 @@ version: "3" includes: + deps: "deps-tasks.yml" docs: "docs/tasks.yml" lint: "lint-tasks.yml" utils: "tools/yscope-dev-utils/taskfiles/utils.yml" vars: - # Paths + # Source paths + G_COMPONENTS_DIR: "{{.ROOT_DIR}}/components" + G_CORE_COMPONENT_DIR: "{{.G_COMPONENTS_DIR}}/core" + G_CORE_COMPONENT_SUBMODULES_DIR: "{{.G_CORE_COMPONENT_DIR}}/submodules" + G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.G_COMPONENTS_DIR}}/log-viewer-webui" + + # Build paths G_BUILD_DIR: "{{.ROOT_DIR}}/build" G_CORE_COMPONENT_BUILD_DIR: "{{.G_BUILD_DIR}}/core" G_LOG_VIEWER_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/log-viewer-webui" - G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" G_METEOR_BUILD_DIR: "{{.G_BUILD_DIR}}/meteor" G_NODEJS_14_BUILD_DIR: "{{.G_BUILD_DIR}}/nodejs-14" G_NODEJS_14_BIN_DIR: "{{.G_NODEJS_14_BUILD_DIR}}/bin" @@ -20,6 +26,9 @@ vars: G_PACKAGE_VENV_DIR: "{{.G_BUILD_DIR}}/package-venv" G_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/webui" + # Taskfile paths + G_UTILS_TASKFILE: "{{.ROOT_DIR}}/tools/yscope-dev-utils/taskfiles/utils.yml" + # Versions G_PACKAGE_VERSION: "0.2.0-dev" @@ -171,7 +180,7 @@ tasks: vars: SRC_DIR: "components/core" sources: - - "{{.G_BUILD_DIR}}/core-submodules.md5" + - "{{.G_DEPS_CORE_CHECKSUM_FILE}}" - "{{.SRC_DIR}}/cmake/**/*" - "{{.SRC_DIR}}/CMakeLists.txt" - "{{.SRC_DIR}}/src/**/*" @@ -183,7 +192,7 @@ tasks: - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" - deps: ["core-submodules", "init"] + deps: ["deps:core", "init"] cmds: - "mkdir -p '{{.G_CORE_COMPONENT_BUILD_DIR}}'" - "cmake -S '{{.SRC_DIR}}' -B '{{.G_CORE_COMPONENT_BUILD_DIR}}'" @@ -317,31 +326,6 @@ tasks: NODEJS_VERSION: "v14.21.3" OUTPUT_DIR: "{{.OUTPUT_DIR}}" - core-submodules: - internal: true - vars: - CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" - OUTPUT_DIR: "submodules" - sources: - - "{{.TASKFILE}}" - - ".gitmodules" - - "tools/scripts/deps-download/**/*" - dir: "components/core" - generates: ["{{.CHECKSUM_FILE}}"] - deps: - - "init" - - task: "utils:validate-checksum" - vars: - CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" - DATA_DIR: "{{.OUTPUT_DIR}}" - cmds: - - "tools/scripts/deps-download/download-all.sh" - # This command must be last - - task: "utils:compute-checksum" - vars: - DATA_DIR: "{{.OUTPUT_DIR}}" - OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - download-and-extract-tar: internal: true label: "{{.TASK}}-{{.TAR_NAME}}" @@ -399,7 +383,7 @@ tasks: PACKAGE_OUTPUT_DIR: "{{.SRC_DIR}}/node_modules" SERVER_OUTPUT_DIR: "{{.SRC_DIR}}/server/node_modules" sources: - - "{{.G_BUILD_DIR}}/log-viewer-webui-submodules.md5" + - "{{.G_DEPS_LOG_VIEWER_CHECKSUM_FILE}}" - "{{.G_BUILD_DIR}}/nodejs-22.md5" - "{{.TASKFILE}}" - "client/package.json" @@ -418,7 +402,7 @@ tasks: - "{{.PACKAGE_CHECKSUM_FILE}}" - "{{.SERVER_CHECKSUM_FILE}}" deps: - - "log-viewer-webui-submodules" + - "deps:log-viewer" - "nodejs-22" - task: "utils:validate-checksum" vars: @@ -469,30 +453,6 @@ tasks: "{{.SERVER_CHECKSUM_FILE}}" > "{{.CHECKSUM_FILE}}" - log-viewer-webui-submodules: - internal: true - vars: - CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" - OUTPUT_DIR: "yscope-log-viewer" - sources: - - "{{.TASKFILE}}" - - ".gitmodules" - dir: "components/log-viewer-webui" - generates: ["{{.CHECKSUM_FILE}}"] - deps: - - "init" - - task: "utils:validate-checksum" - vars: - CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" - DATA_DIR: "{{.OUTPUT_DIR}}" - cmds: - - "git submodule update --init --recursive yscope-log-viewer" - # This command must be last - - task: "utils:compute-checksum" - vars: - DATA_DIR: "{{.OUTPUT_DIR}}" - OUTPUT_FILE: "{{.CHECKSUM_FILE}}" - meteor: vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" diff --git a/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile b/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile index 1de75872a..feb3ae521 100644 --- a/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile +++ b/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile @@ -18,6 +18,12 @@ RUN ln -s /opt/rh/devtoolset-10/enable /etc/profile.d/devtoolset.sh # cannot be forced to use a bash shell that loads .bashrc RUN cp ./tools/docker-images/clp-env-base-centos7.4/setup-scripts/git /usr/bin/git +# NOTE: +# 1. `task` doesn't have an apt/yum package so we use its install script. +# 2. We don't want to install it using `install-prebuilt-packages.sh` since users may use that on +# their own machines and it would change their environment in a way that can't easily be undone. +RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + # Remove cached files RUN yum clean all \ && rm -rf /tmp/* /var/tmp/* diff --git a/components/core/tools/docker-images/clp-env-base-ubuntu-focal/Dockerfile b/components/core/tools/docker-images/clp-env-base-ubuntu-focal/Dockerfile index f50ccadb4..e34deb336 100644 --- a/components/core/tools/docker-images/clp-env-base-ubuntu-focal/Dockerfile +++ b/components/core/tools/docker-images/clp-env-base-ubuntu-focal/Dockerfile @@ -16,6 +16,12 @@ RUN update-alternatives --set cpp /usr/bin/cpp-10 RUN ./tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh +# NOTE: +# 1. `task` doesn't have an apt/yum package so we use its install script. +# 2. We don't want to install it using `install-prebuilt-packages.sh` since users may use that on +# their own machines and it would change their environment in a way that can't easily be undone. +RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + # Remove cached files RUN apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/components/core/tools/docker-images/clp-env-base-ubuntu-jammy/Dockerfile b/components/core/tools/docker-images/clp-env-base-ubuntu-jammy/Dockerfile index 61dec3228..affdf131d 100644 --- a/components/core/tools/docker-images/clp-env-base-ubuntu-jammy/Dockerfile +++ b/components/core/tools/docker-images/clp-env-base-ubuntu-jammy/Dockerfile @@ -7,6 +7,12 @@ ADD ./tools/scripts/lib_install ./tools/scripts/lib_install RUN ./tools/scripts/lib_install/ubuntu-jammy/install-all.sh +# NOTE: +# 1. `task` doesn't have an apt/yum package so we use its install script. +# 2. We don't want to install it using `install-prebuilt-packages.sh` since users may use that on +# their own machines and it would change their environment in a way that can't easily be undone. +RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + # Remove cached files RUN apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/components/core/tools/scripts/deps-download/Catch2.json b/components/core/tools/scripts/deps-download/Catch2.json deleted file mode 100644 index b26eb68e8..000000000 --- a/components/core/tools/scripts/deps-download/Catch2.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/catchorg/Catch2/archive/refs/tags/v2.13.7.zip", - "unzip": true, - "targets": [ - { - "source": "Catch2-2.13.7", - "destination": "submodules/Catch2" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/abseil-cpp.json b/components/core/tools/scripts/deps-download/abseil-cpp.json deleted file mode 100644 index e38bf8bdb..000000000 --- a/components/core/tools/scripts/deps-download/abseil-cpp.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/abseil/abseil-cpp/archive/refs/tags/20230802.1.zip", - "unzip": true, - "targets": [ - { - "source": "abseil-cpp-20230802.1", - "destination": "submodules/abseil-cpp" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/antlr4.json b/components/core/tools/scripts/deps-download/antlr4.json deleted file mode 100644 index ff0d4d871..000000000 --- a/components/core/tools/scripts/deps-download/antlr4.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "url": "https://www.antlr.org/download/antlr-4.13.1-complete.jar", - "unzip": false, - "hash": { - "algo": "sha3_256", - "digest": "292ba55b3be8443777737e94841cff7a343e7067747c2cb6f58830797b20be65" - }, - "targets": [ - { - "source": "antlr-4.13.1-complete.jar", - "destination": "third-party/antlr/antlr-4.13.1-complete.jar" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/date.json b/components/core/tools/scripts/deps-download/date.json deleted file mode 100644 index 127275b51..000000000 --- a/components/core/tools/scripts/deps-download/date.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/HowardHinnant/date/archive/refs/tags/v3.0.1.zip", - "unzip": true, - "targets": [ - { - "source": "date-3.0.1", - "destination": "submodules/date" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/download-all.sh b/components/core/tools/scripts/deps-download/download-all.sh deleted file mode 100755 index b552f1247..000000000 --- a/components/core/tools/scripts/deps-download/download-all.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# Stop on error -set -e - -script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" -project_root_dir="$script_dir"/../../../../../ -component_root_dir="$script_dir"/../../../ - -cd "${component_root_dir}" -mkdir -p submodules - -# We don't use a git submodule for sqlite3 since that would require building the -# sqlite amalgamation -python3 "${script_dir}/download-dep.py" "${script_dir}/sqlite3.json" -python3 "${script_dir}/download-dep.py" "${script_dir}/antlr4.json" - -if [ -e "$project_root_dir/.git" ] ; then - git submodule update --init --recursive -else - python3 "${script_dir}/download-dep.py" "${script_dir}/abseil-cpp.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/Catch2.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/date.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/json.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/log-surgeon.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/outcome.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/simdjson.json" - python3 "${script_dir}/download-dep.py" "${script_dir}/yaml-cpp.json" -fi diff --git a/components/core/tools/scripts/deps-download/download-dep.py b/components/core/tools/scripts/deps-download/download-dep.py deleted file mode 100644 index 3a8c011a1..000000000 --- a/components/core/tools/scripts/deps-download/download-dep.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import hashlib -import json -import logging -import mmap -import pathlib -import shutil -import sys -import uuid -import urllib.parse -import urllib.request - -# Setup logging -# Create logger -logger = logging.getLogger() -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) - - -def hash_file(algo: str, path: pathlib.Path): - if "sha3_256" == algo: - hasher = hashlib.sha3_256() - with open(path, 'rb') as f: - with mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) as mapped_file: - hasher.update(mapped_file) - return hasher.hexdigest() - - -def main(argv): - script_dir = pathlib.Path(__file__).parent.resolve() - project_root_dir = script_dir.parent.parent.parent - - args_parser = argparse.ArgumentParser(description="Download dependency.") - args_parser.add_argument("config-file", help="Dependency configuration file.") - - parsed_args = vars(args_parser.parse_args(argv[1:])) - config_file_path = pathlib.Path(parsed_args["config-file"]).resolve() - - # Load configurations - with open(config_file_path) as f: - config = json.load(f) - - target_url = config["url"] - parsed_url = urllib.parse.urlparse(target_url) - filename = pathlib.Path(parsed_url.path).name - - extraction_dir = pathlib.Path("/") / "tmp" / str(uuid.uuid4()) - extraction_dir.mkdir(parents=True, exist_ok=True) - - # Download file - file_path = extraction_dir / filename - urllib.request.urlretrieve(target_url, file_path) - if config["unzip"]: - # NOTE: We need to convert file_path to a str since unpack_archive only - # accepts a path-like object on Python versions >= 3.7 - shutil.unpack_archive(str(file_path), extraction_dir) - - if "hash" in config: - # Verify hash - hash = hash_file(config["hash"]["algo"], file_path) - if hash != config["hash"]["digest"]: - logger.fatal("Hash mismatch.") - return -1 - - for target in config["targets"]: - target_source_path = extraction_dir / target["source"] - target_dest_path = project_root_dir / target["destination"] - - target_dest_parent = target_dest_path.parent - - # Remove destination - if target_dest_path.exists(): - shutil.rmtree(target_dest_path, ignore_errors=True) - else: - # Create destination parent - target_dest_parent.mkdir(parents=True, exist_ok=True) - - # Copy destination to target - if config["unzip"]: - shutil.copytree(target_source_path, target_dest_path) - else: - shutil.copy(target_source_path, target_dest_path) - - shutil.rmtree(extraction_dir) - - return 0 - - -if "__main__" == __name__: - sys.exit(main(sys.argv)) diff --git a/components/core/tools/scripts/deps-download/json.json b/components/core/tools/scripts/deps-download/json.json deleted file mode 100644 index 687c2697b..000000000 --- a/components/core/tools/scripts/deps-download/json.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.zip", - "unzip": true, - "targets": [ - { - "source": "json-3.11.3", - "destination": "submodules/json" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/log-surgeon.json b/components/core/tools/scripts/deps-download/log-surgeon.json deleted file mode 100644 index 3b8951951..000000000 --- a/components/core/tools/scripts/deps-download/log-surgeon.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/y-scope/log-surgeon/archive/895f464.zip", - "unzip": true, - "targets": [ - { - "source": "log-surgeon-895f46489b1911ab3b3aac3202afd56c96e8cd98", - "destination": "submodules/log-surgeon" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/outcome.json b/components/core/tools/scripts/deps-download/outcome.json deleted file mode 100644 index 1a0725f4b..000000000 --- a/components/core/tools/scripts/deps-download/outcome.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/ned14/outcome/archive/refs/tags/v2.2.9.zip", - "unzip": true, - "targets": [ - { - "source": "outcome-2.2.9", - "destination": "submodules/outcome" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/simdjson.json b/components/core/tools/scripts/deps-download/simdjson.json deleted file mode 100644 index 8b9999961..000000000 --- a/components/core/tools/scripts/deps-download/simdjson.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "url": "https://github.com/simdjson/simdjson/archive/refs/tags/v3.6.3.zip", - "unzip": true, - "targets": [ - { - "source": "simdjson-3.6.3", - "destination": "submodules/simdjson" - } - ] -} - diff --git a/components/core/tools/scripts/deps-download/sqlite3.json b/components/core/tools/scripts/deps-download/sqlite3.json deleted file mode 100644 index 9b9391d89..000000000 --- a/components/core/tools/scripts/deps-download/sqlite3.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "url": "https://www.sqlite.org/2021/sqlite-amalgamation-3360000.zip", - "unzip": true, - "hash": { - "algo": "sha3_256", - "digest": "d25609210ec93b3c8c7da66a03cf82e2c9868cfbd2d7d866982861855e96f972" - }, - "targets": [ - { - "source": "sqlite-amalgamation-3360000", - "destination": "submodules/sqlite3" - } - ] -} diff --git a/components/core/tools/scripts/deps-download/yaml-cpp.json b/components/core/tools/scripts/deps-download/yaml-cpp.json deleted file mode 100644 index e9b4138c8..000000000 --- a/components/core/tools/scripts/deps-download/yaml-cpp.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "url": "https://github.com/jbeder/yaml-cpp/archive/refs/tags/yaml-cpp-0.7.0.zip", - "unzip": true, - "targets": [ - { - "source": "yaml-cpp-yaml-cpp-0.7.0", - "destination": "submodules/yaml-cpp" - } - ] -} diff --git a/components/core/tools/scripts/lib_install/macos-12/install-all.sh b/components/core/tools/scripts/lib_install/macos-12/install-all.sh index c13223ba6..99e178e92 100755 --- a/components/core/tools/scripts/lib_install/macos-12/install-all.sh +++ b/components/core/tools/scripts/lib_install/macos-12/install-all.sh @@ -10,8 +10,10 @@ brew update brew install \ boost \ cmake \ + coreutils \ fmt \ gcc \ + go-task \ java11 \ libarchive \ lz4 \ diff --git a/deps-tasks.yml b/deps-tasks.yml new file mode 100644 index 000000000..daf6186cd --- /dev/null +++ b/deps-tasks.yml @@ -0,0 +1,445 @@ +version: "3" +vars: + # Utility script path + G_DEP_DOWNLOAD_SCRIPT: "{{.ROOT_DIR}}/tools/scripts/deps-download/download-dep.py" + + # Target checksum files + G_DEPS_CORE_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#core.md5" + G_DEPS_LOG_VIEWER_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#log-viewer.md5" + + # Submodule checksum files + G_ABSEIL_CPP_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#abseil-cpp.md5" + G_ANTLR4_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#antlr4.md5" + G_CATCH2_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#Catch2.md5" + G_DATE_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#date.md5" + G_JSON_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#json.md5" + G_LOG_SURGEON_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#log-surgeon.md5" + G_OUTCOME_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#outcome.md5" + G_SIMDJSON_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#simdjson.md5" + G_SQLITE3_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#sqlite3.md5" + G_YAML_CPP_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#yaml-cpp.md5" + G_YSCOPE_LOG_VIEWER_CHECKSUM_FILE: "{{.G_BUILD_DIR}}/deps#yscope-log-viewer.md5" + +tasks: + default: + cmds: + - task: "core" + - task: "log-viewer" + + core: + vars: + sources: + - "{{.G_ABSEIL_CPP_CHECKSUM_FILE}}" + - "{{.G_ANTLR4_CHECKSUM_FILE}}" + - "{{.G_CATCH2_CHECKSUM_FILE}}" + - "{{.G_DATE_CHECKSUM_FILE}}" + - "{{.G_JSON_CHECKSUM_FILE}}" + - "{{.G_LOG_SURGEON_CHECKSUM_FILE}}" + - "{{.G_OUTCOME_CHECKSUM_FILE}}" + - "{{.G_SIMDJSON_CHECKSUM_FILE}}" + - "{{.G_SQLITE3_CHECKSUM_FILE}}" + - "{{.G_YAML_CPP_CHECKSUM_FILE}}" + generates: ["{{.G_DEPS_CORE_CHECKSUM_FILE}}"] + deps: ["all-internal-deps"] + cmds: + - >- + cat + "{{.G_ABSEIL_CPP_CHECKSUM_FILE}}" + "{{.G_ANTLR4_CHECKSUM_FILE}}" + "{{.G_CATCH2_CHECKSUM_FILE}}" + "{{.G_DATE_CHECKSUM_FILE}}" + "{{.G_JSON_CHECKSUM_FILE}}" + "{{.G_LOG_SURGEON_CHECKSUM_FILE}}" + "{{.G_OUTCOME_CHECKSUM_FILE}}" + "{{.G_SIMDJSON_CHECKSUM_FILE}}" + "{{.G_SQLITE3_CHECKSUM_FILE}}" + "{{.G_YAML_CPP_CHECKSUM_FILE}}" + >> "{{.G_DEPS_CORE_CHECKSUM_FILE}}" + + log-viewer: + sources: + - "{{.G_YSCOPE_LOG_VIEWER_CHECKSUM_FILE}}" + generates: ["{{.G_DEPS_LOG_VIEWER_CHECKSUM_FILE}}"] + deps: ["all-internal-deps"] + cmds: + - >- + cat + "{{.G_YSCOPE_LOG_VIEWER_CHECKSUM_FILE}}" + >> "{{.G_DEPS_LOG_VIEWER_CHECKSUM_FILE}}" + + # NOTE: `git submodule update` doesn't support parallel invocations, so we can't use it to + # download submodules in parallel. This means: + # 1. the submodule tasks cannot be specified as a list of `deps`, because `task` always runs + # `deps` tasks in parallel. + # 2. we need to force higher level tasks, like `core` and `log-viewer`, to run their submodule + # download tasks serially. + # + # As a solution, the `all-internal-deps` task below: + # 1. uses `cmds` to sequentially download `ALL` submodules required by the clp-package. + # 2. uses `run: once`, so it executes once even if multiple higher level targets depend on it. + # + # All higher level tasks must depend on this task instead of depending on the individual + # submodule tasks in this file. + all-internal-deps: + internal: true + run: "once" + cmds: + - task: "abseil-cpp" + - task: "antlr4" + - task: "Catch2" + - task: "date" + - task: "json" + - task: "log-surgeon" + - task: "outcome" + - task: "simdjson" + - task: "sqlite3" + - task: "yaml-cpp" + - task: "yscope-log-viewer" + + abseil-cpp: + internal: true + vars: + CHECKSUM_FILE: "{{.G_ABSEIL_CPP_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/abseil-cpp" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "abseil-cpp-20230802.1" + SRC_URL: "https://github.com/abseil/abseil-cpp/archive/refs/tags/20230802.1.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + antlr4: + internal: true + vars: + CHECKSUM_FILE: "{{.G_ANTLR4_CHECKSUM_FILE}}" + DEST_DIR: "{{.G_CORE_COMPONENT_DIR}}/third-party/antlr" + DEST: "{{.DEST_DIR}}/antlr-4.13.1-complete.jar" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST_DIR}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--no-submodule" + SRC_NAME: "antlr-4.13.1-complete.jar" + SRC_URL: "https://www.antlr.org/download/antlr-4.13.1-complete.jar" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST_DIR}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + Catch2: + internal: true + vars: + CHECKSUM_FILE: "{{.G_CATCH2_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/Catch2" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "Catch2-2.13.7" + SRC_URL: "https://github.com/catchorg/Catch2/archive/refs/tags/v2.13.7.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + date: + internal: true + vars: + CHECKSUM_FILE: "{{.G_DATE_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/date" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "date-3.0.1" + SRC_URL: "https://github.com/HowardHinnant/date/archive/refs/tags/v3.0.1.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + json: + internal: true + vars: + CHECKSUM_FILE: "{{.G_JSON_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/json" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "json-3.11.3" + SRC_URL: "https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + log-surgeon: + internal: true + vars: + CHECKSUM_FILE: "{{.G_LOG_SURGEON_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/log-surgeon" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "log-surgeon-895f46489b1911ab3b3aac3202afd56c96e8cd98" + SRC_URL: "https://github.com/y-scope/log-surgeon/archive/895f464.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + outcome: + internal: true + vars: + CHECKSUM_FILE: "{{.G_OUTCOME_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/outcome" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "outcome-2.2.9" + SRC_URL: "https://github.com/ned14/outcome/archive/refs/tags/v2.2.9.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + simdjson: + internal: true + vars: + CHECKSUM_FILE: "{{.G_SIMDJSON_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/simdjson" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "simdjson-3.6.3" + SRC_URL: "https://github.com/simdjson/simdjson/archive/refs/tags/v3.6.3.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + # We don't use a git submodule for sqlite3 since that would require building the sqlite + # amalgamation + sqlite3: + internal: true + vars: + CHECKSUM_FILE: "{{.G_SQLITE3_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/sqlite3" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract --no-submodule" + SRC_NAME: "sqlite-amalgamation-3360000" + SRC_URL: "https://www.sqlite.org/2021/sqlite-amalgamation-3360000.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + yaml-cpp: + internal: true + vars: + CHECKSUM_FILE: "{{.G_YAML_CPP_CHECKSUM_FILE}}" + DEST: "{{.G_CORE_COMPONENT_SUBMODULES_DIR}}/yaml-cpp" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "yaml-cpp-yaml-cpp-0.7.0" + SRC_URL: "https://github.com/jbeder/yaml-cpp/archive/refs/tags/yaml-cpp-0.7.0.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + yscope-log-viewer: + internal: true + vars: + CHECKSUM_FILE: "{{.G_YSCOPE_LOG_VIEWER_CHECKSUM_FILE}}" + DEST: "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/yscope-log-viewer" + sources: + - "{{.G_DEP_DOWNLOAD_SCRIPT}}" + - "{{.G_UTILS_TASKFILE}}" + - "{{.ROOT_DIR}}/Taskfile.yml" + - "{{.TASKFILE}}" + generates: ["{{.CHECKSUM_FILE}}"] + deps: + - ":init" + - task: ":utils:validate-checksum" + vars: + CHECKSUM_FILE: "{{.CHECKSUM_FILE}}" + DATA_DIR: "{{.DEST}}" + cmds: + - task: "download-dependency" + vars: + DEST: "{{.DEST}}" + FLAGS: "--extract" + SRC_NAME: "yscope-log-viewer-df996eac000823d02f9cd0b9eb4bb732dd634ae5" + SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/df996ea.zip" + # This command must be last + - task: ":utils:compute-checksum" + vars: + DATA_DIR: "{{.DEST}}" + OUTPUT_FILE: "{{.CHECKSUM_FILE}}" + + download-dependency: + internal: true + label: "{{.TASK}}-{{.SRC_NAME}}" + requires: + vars: ["DEST", "FLAGS", "SRC_NAME", "SRC_URL"] + deps: + - ":init" + cmds: + - >- + python3 "{{.G_DEP_DOWNLOAD_SCRIPT}}" + "{{.SRC_URL}}" + {{.SRC_NAME}} + "{{.DEST}}" + {{.FLAGS}} diff --git a/docs/src/dev-guide/building-package.md b/docs/src/dev-guide/building-package.md index 32d0ae417..4cf4e5349 100644 --- a/docs/src/dev-guide/building-package.md +++ b/docs/src/dev-guide/building-package.md @@ -16,10 +16,10 @@ prebuilt version instead, check out the [releases](https://github.com/y-scope/cl ## Setup -Download CLP core's source dependencies: +Initialize the project ```shell -components/core/tools/scripts/deps-download/download-all.sh +tools/scripts/deps-download/init.sh ``` Install CLP core's dependencies diff --git a/docs/src/dev-guide/components-core/index.md b/docs/src/dev-guide/components-core/index.md index 62360486a..cffb0f004 100644 --- a/docs/src/dev-guide/components-core/index.md +++ b/docs/src/dev-guide/components-core/index.md @@ -7,17 +7,26 @@ CLP core is the low-level component that performs compression, decompression, an * We have built and tested CLP on the OSes listed [below](#native-environment). * If you have trouble building for another OS, file an issue, and we may be able to help. * A compiler that supports C++20 and std::span (e.g., gcc-10) +* [Task](https://taskfile.dev/) To build, we require some source dependencies, packages from package managers, and libraries built from source. +### Set up + +To initialize the project, run: + +```shell +tools/scripts/deps-download/init.sh +``` + ### Source Dependencies -We use both git submodules and third-party source packages. To download all, you can run this -script: +We use both git submodules and third-party source packages. To download all, run this `task` +command: ```shell -components/core/tools/scripts/deps-download/download-all.sh +task deps:core ``` This will download: @@ -27,6 +36,7 @@ This will download: * [date](https://github.com/HowardHinnant/date.git) (v3.0.1) * [json](https://github.com/nlohmann/json.git) (v3.10.4) * [log-surgeon](https://github.com/y-scope/log-surgeon) (895f464) +* [outcome](https://github.com/ned14/outcome) (v2.2.9) * [simdjson](https://github.com/simdjson/simdjson) (v3.6.3) * [SQLite3](https://www.sqlite.org/download.html) (v3.36.0) * [yaml-cpp](https://github.com/jbeder/yaml-cpp.git) (v0.7.0) diff --git a/lint-tasks.yml b/lint-tasks.yml index 9f21cd8ed..63cff497f 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -110,6 +110,7 @@ tasks: components/core/config \ components/package-template/src/etc \ docs \ + deps-tasks.yml \ lint-tasks.yml \ Taskfile.yml @@ -151,6 +152,7 @@ tasks: - "components/clp-package-utils/clp_package_utils" - "components/clp-py-utils/clp_py_utils" - "components/job-orchestration/job_orchestration" + - "tools/scripts" - "docs/conf" cmd: |- . "{{.G_LINT_VENV_DIR}}/bin/activate" diff --git a/tools/scripts/deps-download/download-dep.py b/tools/scripts/deps-download/download-dep.py new file mode 100644 index 000000000..5866461fd --- /dev/null +++ b/tools/scripts/deps-download/download-dep.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +import argparse +import logging +import os +import shutil +import subprocess +import sys +import tempfile +import urllib.parse +import urllib.request +from pathlib import Path + +# Setup logging +# Create logger +logger = logging.getLogger() +logger.setLevel(logging.INFO) +# Setup console logging +logging_console_handler = logging.StreamHandler() +logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") +logging_console_handler.setFormatter(logging_formatter) +logger.addHandler(logging_console_handler) + + +def main(argv): + args_parser = argparse.ArgumentParser(description="Download dependency.") + args_parser.add_argument("source_url", help="URL of the source file.") + args_parser.add_argument("source_name", help="Name of the source file.") + args_parser.add_argument("dest_dir", help="Output directory for the download.") + args_parser.add_argument("--extract", action="store_true", help="Extract the source file.") + args_parser.add_argument( + "--no-submodule", + action="store_false", + dest="use_submodule", + help="Don't use git submodule update", + ) + + parsed_args = args_parser.parse_args(argv[1:]) + source_url = parsed_args.source_url + source_name = parsed_args.source_name + dest_dir = Path(parsed_args.dest_dir).resolve() + extract_source = parsed_args.extract + + script_path = Path(os.path.realpath(__file__)) + git_dir = script_path.parent / ".." / ".." / ".." / ".git" + if git_dir.exists() and git_dir.is_dir(): + if parsed_args.use_submodule: + cmd = ["git", "submodule", "update", "--init", "--recursive", str(dest_dir)] + try: + subprocess.run(cmd, check=True) + except subprocess.CalledProcessError: + logger.exception(f"Failed to update submodule '{dest_dir}'.") + return -1 + return 0 + + with tempfile.TemporaryDirectory() as work_dir_name: + work_dir = Path(work_dir_name) + + parsed_url = urllib.parse.urlparse(source_url) + filename = Path(parsed_url.path).name + file_path = work_dir / filename + + # Download file + urllib.request.urlretrieve(source_url, file_path) + if extract_source: + # NOTE: We need to convert `file_path` to a str since `unpack_archive` only accepts a + # path-like object on Python versions >= 3.7 + shutil.unpack_archive(str(file_path), work_dir) + + if dest_dir.exists(): + shutil.rmtree(dest_dir, ignore_errors=True) + else: + dest_dir.parent.mkdir(parents=True, exist_ok=True) + + source_path = work_dir / source_name + if not source_path.exists(): + logger.error(f"Source '{source_path}' doesn't exist.") + return -1 + + if extract_source: + shutil.copytree(source_path, dest_dir) + else: + shutil.copy(source_path, dest_dir) + + return 0 + + +if "__main__" == __name__: + sys.exit(main(sys.argv)) diff --git a/tools/scripts/deps-download/init.sh b/tools/scripts/deps-download/init.sh new file mode 100755 index 000000000..57fcd4594 --- /dev/null +++ b/tools/scripts/deps-download/init.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Exit on any error +set -e + +# Error on undefined variable +set -u + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +project_root_dir="$script_dir/../../../" +download_dep_script="$script_dir/download-dep.py" + +python3 "${download_dep_script}" \ + https://github.com/y-scope/yscope-dev-utils/archive/ff1611e6.zip \ + yscope-dev-utils-ff1611e6f9b116da27dc7f8f71797829c22d0b1a \ + "${project_root_dir}/tools/yscope-dev-utils" \ + --extract diff --git a/tools/scripts/find-broken-docs-links.py b/tools/scripts/find-broken-docs-links.py index 349e927ef..1a1eb7427 100644 --- a/tools/scripts/find-broken-docs-links.py +++ b/tools/scripts/find-broken-docs-links.py @@ -11,19 +11,19 @@ def main(argv): # Check for docs.yscope.com links with ".md" suffixes if _check_tracked_files( - r"docs\.yscope\.com/.+\.md", - repo_root, - repo_root, - "docs.yscope.com links cannot have \".md\" suffixes." + r"docs\.yscope\.com/.+\.md", + repo_root, + repo_root, + 'docs.yscope.com links cannot have ".md" suffixes.', ): found_violation = True # Check for sphinx :link: attributes that have ".md" suffixes if _check_tracked_files( - r":link:[[:space:]]*.+\.md", - repo_root, - repo_root / "docs", - "sphinx :link: attributes cannot have \".md\" suffixes" + r":link:[[:space:]]*.+\.md", + repo_root, + repo_root / "docs", + 'sphinx :link: attributes cannot have ".md" suffixes', ): found_violation = True @@ -35,18 +35,13 @@ def main(argv): def _get_repo_root() -> Path: path_str = subprocess.check_output( - ["git", "rev-parse", "--show-toplevel"], - cwd=Path(__file__).parent, - text=True + ["git", "rev-parse", "--show-toplevel"], cwd=Path(__file__).parent, text=True ) return Path(path_str.strip()) def _check_tracked_files( - pattern: str, - repo_root: Path, - dir_to_search: Path, - error_msg: str + pattern: str, repo_root: Path, dir_to_search: Path, error_msg: str ) -> bool: """ Check for a pattern in all tracked files in the repo (except this script). @@ -60,16 +55,16 @@ def _check_tracked_files( # NOTE: "-z" ensures the paths won't be quoted (while delimiting them using '\0') for path_str in subprocess.check_output( - [ - "git", - "ls-files", - "--cached", - "--exclude-standard", - "-z", - str(dir_to_search.relative_to(repo_root)) - ], - cwd=repo_root, - text=True, + [ + "git", + "ls-files", + "--cached", + "--exclude-standard", + "-z", + str(dir_to_search.relative_to(repo_root)), + ], + cwd=repo_root, + text=True, ).split("\0"): path = Path(path_str) @@ -79,16 +74,9 @@ def _check_tracked_files( try: for match in subprocess.check_output( - [ - "grep", - "--extended-regexp", - "--line-number", - "--with-filename", - pattern, - path - ], - cwd=repo_root, - text=True, + ["grep", "--extended-regexp", "--line-number", "--with-filename", pattern, path], + cwd=repo_root, + text=True, ).splitlines(): _parse_and_print_match(match, error_msg) found_matches = True From ea9e5e3fdf4a76476d78cc38a4d2bf948f5f9909 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:34:34 -0400 Subject: [PATCH 062/114] lint: Fix violations in log-viewer-webui and webui. (#529) --- components/log-viewer-webui/client/src/ui/QueryStatus.jsx | 1 + .../webui/imports/api/search/server/QueryJobsDbManager.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx index d46e6b885..84f367d0e 100644 --- a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -36,6 +36,7 @@ const QueryStatus = () => { console.error(error); setErrorMsg(error); + return; } diff --git a/components/webui/imports/api/search/server/QueryJobsDbManager.js b/components/webui/imports/api/search/server/QueryJobsDbManager.js index 835aae796..9efc4771c 100644 --- a/components/webui/imports/api/search/server/QueryJobsDbManager.js +++ b/components/webui/imports/api/search/server/QueryJobsDbManager.js @@ -1,4 +1,4 @@ -import msgpack from "@msgpack/msgpack"; +import {encode} from "@msgpack/msgpack"; import {sleep} from "/imports/utils/misc"; @@ -57,7 +57,7 @@ class QueryJobsDbManager { (${QUERY_JOBS_TABLE_COLUMN_NAMES.JOB_CONFIG}, ${QUERY_JOBS_TABLE_COLUMN_NAMES.TYPE}) VALUES (?, ?)`, - [Buffer.from(msgpack.encode(searchConfig)), + [Buffer.from(encode(searchConfig)), QUERY_JOB_TYPE.SEARCH_OR_AGGREGATION], ); From a3a3f356df13021c57bdce2bf5c99e5f3fa8dd66 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Thu, 5 Sep 2024 04:52:20 -0400 Subject: [PATCH 063/114] core: Link reducer-server against missing dynamic libraries; Upgrade to mongocxx 3.10.2; Add test for shared library build (fixes #526). (#527) Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> --- .github/actions/clp-core-build/action.yaml | 11 +- .github/workflows/clp-core-build-macos.yaml | 15 ++- .github/workflows/clp-core-build.yaml | 26 ++++- components/core/CMakeLists.txt | 2 + components/core/src/reducer/CMakeLists.txt | 5 + .../centos7.4/install-packages-from-source.sh | 3 +- .../core/tools/scripts/lib_install/mongoc.sh | 106 ------------------ .../tools/scripts/lib_install/mongocxx.sh | 5 +- .../install-packages-from-source.sh | 3 +- .../install-packages-from-source.sh | 3 +- .../scripts/utils/build-and-run-unit-tests.py | 101 +++++++++++++++++ .../scripts/utils/build-and-run-unit-tests.sh | 26 ----- lint-tasks.yml | 1 + 13 files changed, 157 insertions(+), 150 deletions(-) delete mode 100755 components/core/tools/scripts/lib_install/mongoc.sh create mode 100644 components/core/tools/scripts/utils/build-and-run-unit-tests.py delete mode 100755 components/core/tools/scripts/utils/build-and-run-unit-tests.sh diff --git a/.github/actions/clp-core-build/action.yaml b/.github/actions/clp-core-build/action.yaml index ab5070b09..e627ec4fb 100644 --- a/.github/actions/clp-core-build/action.yaml +++ b/.github/actions/clp-core-build/action.yaml @@ -8,6 +8,9 @@ inputs: use_published_image: description: "Whether to use the published container image" required: true + use_shared_libs: + description: "Whether to build the core binaries by linking against shared libraries" + required: true upload_binaries: description: "Whether to upload the core binaries" required: true @@ -52,9 +55,11 @@ runs: --workdir /mnt/clp ${{steps.get_image_props.outputs.qualified_image_name}} bash -c "task deps:core && - /mnt/clp/components/core/tools/scripts/utils/build-and-run-unit-tests.sh - /mnt/clp/components/core - /mnt/clp/components/core/build" + python3 /mnt/clp/components/core/tools/scripts/utils/build-and-run-unit-tests.py + ${{inputs.use_shared_libs == 'true' && '--use-shared-libs' || ''}} + --source-dir /mnt/clp/components/core + --build-dir /mnt/clp/components/core/build + --num-jobs $(getconf _NPROCESSORS_ONLN)" shell: "bash" - if: "inputs.upload_binaries == 'true'" diff --git a/.github/workflows/clp-core-build-macos.yaml b/.github/workflows/clp-core-build-macos.yaml index dc9e8209a..2398b14a2 100644 --- a/.github/workflows/clp-core-build-macos.yaml +++ b/.github/workflows/clp-core-build-macos.yaml @@ -10,7 +10,7 @@ on: - "components/core/tests/**" - "components/core/tools/scripts/lib_install/macos-12/**" - "components/core/tools/scripts/deps-download/**" - - "components/core/tools/scripts/utils/build-and-run-unit-tests.sh" + - "components/core/tools/scripts/utils/build-and-run-unit-tests.py" - "deps-tasks.yml" - "Taskfile.yml" - "tools/scripts/deps-download/**" @@ -23,7 +23,7 @@ on: - "components/core/tests/**" - "components/core/tools/scripts/lib_install/macos-12/**" - "components/core/tools/scripts/deps-download/**" - - "components/core/tools/scripts/utils/build-and-run-unit-tests.sh" + - "components/core/tools/scripts/utils/build-and-run-unit-tests.py" - "deps-tasks.yml" - "Taskfile.yml" - "tools/scripts/deps-download/**" @@ -36,6 +36,9 @@ concurrency: jobs: build-macos: + strategy: + matrix: + use_shared_libs: [true, false] runs-on: "macos-12" steps: - uses: "actions/checkout@v4" @@ -63,4 +66,10 @@ jobs: shell: "bash" working-directory: "./components/core" # NOTE: We omit the Stopwatch tests since GH's macOS runner is too slow - run: "./tools/scripts/utils/build-and-run-unit-tests.sh . build ~[Stopwatch]" + run: >- + python3 ./tools/scripts/utils/build-and-run-unit-tests.py + ${{matrix.use_shared_libs == 'true' && '--use-shared-libs' || ''}} + --source-dir . + --build-dir build + --num-jobs $(getconf _NPROCESSORS_ONLN) + --test-spec "~[Stopwatch]" diff --git a/.github/workflows/clp-core-build.yaml b/.github/workflows/clp-core-build.yaml index 47853375c..fa2c1d4a5 100644 --- a/.github/workflows/clp-core-build.yaml +++ b/.github/workflows/clp-core-build.yaml @@ -89,7 +89,7 @@ jobs: - "components/core/CMakeLists.txt" - "components/core/src/**" - "components/core/tests/**" - - "components/core/tools/scripts/utils/build-and-run-unit-tests.sh" + - "components/core/tools/scripts/utils/build-and-run-unit-tests.py" - "deps-tasks.yml" - "Taskfile.yml" - "tools/scripts/deps-download/**" @@ -177,6 +177,11 @@ jobs: needs: - "centos74-deps-image" - "filter-relevant-changes" + strategy: + matrix: + use_shared_libs: [true, false] + name: "centos74-${{matrix.use_shared_libs && 'dynamic' || 'static'}}-linked-bins" + continue-on-error: true runs-on: "ubuntu-latest" steps: - uses: "actions/checkout@v4" @@ -192,6 +197,7 @@ jobs: OS_NAME: "centos7.4" with: image_name: "${{env.DEPS_IMAGE_NAME_PREFIX}}${{env.OS_NAME}}" + use_shared_libs: "${{matrix.use_shared_libs}}" use_published_image: >- ${{needs.filter-relevant-changes.outputs.centos74_image_changed == 'false' || (github.event_name != 'pull_request' && github.ref == 'refs/heads/main')}} @@ -205,6 +211,15 @@ jobs: needs: - "filter-relevant-changes" - "ubuntu-focal-deps-image" + strategy: + matrix: + include: + - use_shared_libs: true + upload_binaries: false + - use_shared_libs: false + upload_binaries: true + name: "ubuntu-focal-${{matrix.use_shared_libs && 'dynamic' || 'static'}}-linked-bins" + continue-on-error: true runs-on: "ubuntu-latest" steps: - uses: "actions/checkout@v4" @@ -220,10 +235,11 @@ jobs: OS_NAME: "ubuntu-focal" with: image_name: "${{env.DEPS_IMAGE_NAME_PREFIX}}${{env.OS_NAME}}" + use_shared_libs: "${{matrix.use_shared_libs}}" use_published_image: >- ${{needs.filter-relevant-changes.outputs.ubuntu_focal_image_changed == 'false' || (github.event_name != 'pull_request' && github.ref == 'refs/heads/main')}} - upload_binaries: "true" + upload_binaries: "${{matrix.upload_binaries}}" binaries_artifact_name: "${{env.BINARIES_ARTIFACT_NAME_PREFIX}}${{env.OS_NAME}}" ubuntu-jammy-binaries: @@ -234,6 +250,11 @@ jobs: needs: - "filter-relevant-changes" - "ubuntu-jammy-deps-image" + strategy: + matrix: + use_shared_libs: [true, false] + name: "ubuntu-jammy-${{matrix.use_shared_libs && 'dynamic' || 'static'}}-linked-bins" + continue-on-error: true runs-on: "ubuntu-latest" steps: - uses: "actions/checkout@v4" @@ -249,6 +270,7 @@ jobs: OS_NAME: "ubuntu-jammy" with: image_name: "${{env.DEPS_IMAGE_NAME_PREFIX}}${{env.OS_NAME}}" + use_shared_libs: "${{matrix.use_shared_libs}}" use_published_image: >- ${{needs.filter-relevant-changes.outputs.ubuntu_jammy_image_changed == 'false' || (github.event_name != 'pull_request' && github.ref == 'refs/heads/main')}} diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index c4f84570c..79c685024 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -198,6 +198,8 @@ add_subdirectory(submodules/abseil-cpp EXCLUDE_FROM_ALL) # Add simdjson add_subdirectory(submodules/simdjson EXCLUDE_FROM_ALL) +find_package(Threads REQUIRED) + # Add yaml-cpp add_subdirectory(submodules/yaml-cpp EXCLUDE_FROM_ALL) diff --git a/components/core/src/reducer/CMakeLists.txt b/components/core/src/reducer/CMakeLists.txt index 16958da74..4685009f2 100644 --- a/components/core/src/reducer/CMakeLists.txt +++ b/components/core/src/reducer/CMakeLists.txt @@ -44,11 +44,16 @@ target_include_directories(reducer-server PRIVATE "${PROJECT_SOURCE_DIR}/submodu target_link_libraries(reducer-server PRIVATE Boost::program_options + Boost::system clp::string_utils fmt::fmt ${MONGOCXX_TARGET} msgpack-cxx spdlog::spdlog + # Threads::Threads is necessary because on Ubuntu Focal (20.04), libssl (a dependency of + # libmongocxx) depends on libpthread, but its cmake script doesn't seem to provide the flags + # to link against libpthread. + Threads::Threads ) # Put the built executable at the root of the build directory set_target_properties( diff --git a/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh index 08c1cafb6..82f2abb1c 100755 --- a/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh +++ b/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh @@ -28,8 +28,7 @@ lib_install_scripts_dir=$script_dir/.. "$lib_install_scripts_dir"/libarchive.sh 3.5.1 "$lib_install_scripts_dir"/lz4.sh 1.8.2 "$lib_install_scripts_dir"/mariadb-connector-c.sh 3.2.3 -"$lib_install_scripts_dir"/mongoc.sh 1.24.4 -"$lib_install_scripts_dir"/mongocxx.sh 3.8.0 +"$lib_install_scripts_dir"/mongocxx.sh 3.10.2 "$lib_install_scripts_dir"/msgpack.sh 6.0.0 "$lib_install_scripts_dir"/spdlog.sh 1.9.2 "$lib_install_scripts_dir"/zstandard.sh 1.4.9 diff --git a/components/core/tools/scripts/lib_install/mongoc.sh b/components/core/tools/scripts/lib_install/mongoc.sh deleted file mode 100755 index c9a784344..000000000 --- a/components/core/tools/scripts/lib_install/mongoc.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env bash - -# Dependencies: -# - cmake -# - curl -# - git -# - g++ -# NOTE: Dependencies should be installed outside the script to allow the script to be largely -# distro-agnostic - -# Exit on any error -set -e - -# Error on undefined variable -set -u - -cUsage="Usage: ${BASH_SOURCE[0]} [ <.deb output directory>]" -if [ "$#" -lt 1 ] ; then - echo "$cUsage" - exit -fi -version=$1 - -package_name=libmongoc-dev -temp_dir="/tmp/${package_name}-installation" -deb_output_dir="${temp_dir}" -if [[ "$#" -gt 1 ]] ; then - deb_output_dir="$(readlink -f "$2")" - if [ ! -d "${deb_output_dir}" ] ; then - echo "${deb_output_dir} does not exist or is not a directory" - exit - fi -fi - -# Check if already installed -set +e -dpkg -l "${package_name}" | grep "${version}" -installed=$? -set -e -if [ $installed -eq 0 ] ; then - # Nothing to do - exit -fi - -echo "Checking for elevated privileges..." -install_cmd_args=() -if [ ${EUID:-$(id -u)} -ne 0 ] ; then - sudo echo "Script can elevate privileges." - install_cmd_args+=("sudo") -fi - -# Download -mkdir -p "$temp_dir" -cd "$temp_dir" -extracted_dir="${temp_dir}/mongo-c-driver-${version}" -if [ ! -e "${extracted_dir}" ] ; then - tar_filename="mongo-c-driver-${version}.tar.gz" - if [ ! -e "${tar_filename}" ] ; then - curl \ - -fsSL \ - "https://github.com/mongodb/mongo-c-driver/releases/download/${version}/${tar_filename}" \ - -o "${tar_filename}" - fi - - tar -xf "${tar_filename}" -fi - -# Set up -cd "${extracted_dir}" -mkdir -p build -cd build -cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF \ - -DENABLE_ICU=OFF \ - -DENABLE_TESTS=OFF \ - .. - -# Check if checkinstall is installed -set +e -command -v checkinstall -checkinstall_installed=$? -set -e - -# Install -if [ $checkinstall_installed -eq 0 ] ; then - install_cmd_args+=( - checkinstall - --pkgname "${package_name}" - --pkgversion "${version}" - --provides "${package_name}" - --nodoc - -y - --pakdir "${deb_output_dir}" - ) -fi -install_cmd_args+=( - cmake - --build . - --target install - --parallel -) -"${install_cmd_args[@]}" - -# Clean up -rm -rf "$temp_dir" diff --git a/components/core/tools/scripts/lib_install/mongocxx.sh b/components/core/tools/scripts/lib_install/mongocxx.sh index da41ef71d..8a06fcc76 100755 --- a/components/core/tools/scripts/lib_install/mongocxx.sh +++ b/components/core/tools/scripts/lib_install/mongocxx.sh @@ -67,12 +67,9 @@ fi # Set up cd "${extracted_dir}/build" -# NOTE: Although the mongocxx docs indicate we should use -# '-DMONGOCXX_OVERRIDE_DEFAULT_INSTALL_PREFIX=OFF' to install to the default location (/usr/local), -# this doesn't seem to work, so we specify CMAKE_INSTALL_PREFIX here cmake \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DMONGOCXX_OVERRIDE_DEFAULT_INSTALL_PREFIX=OFF \ -DBUILD_SHARED_AND_STATIC_LIBS=ON \ -DBUILD_SHARED_LIBS_WITH_STATIC_MONGOC=ON \ -DENABLE_TESTS=OFF \ diff --git a/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh index 1281d0267..d785b536f 100755 --- a/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh +++ b/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh @@ -15,8 +15,7 @@ lib_install_scripts_dir=$script_dir/.. "$lib_install_scripts_dir"/fmtlib.sh 8.0.1 "$lib_install_scripts_dir"/libarchive.sh 3.5.1 "$lib_install_scripts_dir"/lz4.sh 1.8.2 -"$lib_install_scripts_dir"/mongoc.sh 1.24.4 -"$lib_install_scripts_dir"/mongocxx.sh 3.8.0 +"$lib_install_scripts_dir"/mongocxx.sh 3.10.2 "$lib_install_scripts_dir"/msgpack.sh 6.0.0 "$lib_install_scripts_dir"/spdlog.sh 1.9.2 "$lib_install_scripts_dir"/zstandard.sh 1.4.9 diff --git a/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh index 527f392a5..8049dbebf 100755 --- a/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh +++ b/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh @@ -12,8 +12,7 @@ lib_install_scripts_dir=$script_dir/.. "$lib_install_scripts_dir"/fmtlib.sh 8.0.1 "$lib_install_scripts_dir"/libarchive.sh 3.5.1 "$lib_install_scripts_dir"/lz4.sh 1.8.2 -"$lib_install_scripts_dir"/mongoc.sh 1.24.4 -"$lib_install_scripts_dir"/mongocxx.sh 3.8.0 +"$lib_install_scripts_dir"/mongocxx.sh 3.10.2 "$lib_install_scripts_dir"/msgpack.sh 6.0.0 "$lib_install_scripts_dir"/spdlog.sh 1.9.2 "$lib_install_scripts_dir"/zstandard.sh 1.4.9 diff --git a/components/core/tools/scripts/utils/build-and-run-unit-tests.py b/components/core/tools/scripts/utils/build-and-run-unit-tests.py new file mode 100644 index 000000000..7c4b13617 --- /dev/null +++ b/components/core/tools/scripts/utils/build-and-run-unit-tests.py @@ -0,0 +1,101 @@ +import argparse +import logging +import subprocess +import sys +from pathlib import Path +from typing import List, Optional + +# Set up console logging +logging_console_handler = logging.StreamHandler() +logging_formatter = logging.Formatter( + "%(asctime)s.%(msecs)03d %(levelname)s [%(module)s] %(message)s", datefmt="%Y-%m-%dT%H:%M:%S" +) +logging_console_handler.setFormatter(logging_formatter) + +# Set up root logger +root_logger = logging.getLogger() +root_logger.setLevel(logging.INFO) +root_logger.addHandler(logging_console_handler) + +# Create logger +logger = logging.getLogger(__name__) + + +def _config_cmake_project(src_dir: Path, build_dir: Path, use_shared_libs: bool): + cmd = [ + "cmake", + "-S", + str(src_dir), + "-B", + str(build_dir), + ] + if use_shared_libs: + cmd.append("-DCLP_USE_STATIC_LIBS=OFF") + subprocess.run(cmd, check=True) + + +def _build_project(build_dir: Path, num_jobs: Optional[int]): + """ + :param build_dir: + :param num_jobs: Max number of jobs to run when building. + """ + + cmd = [ + "cmake", + "--build", + str(build_dir), + "--parallel", + ] + if num_jobs is not None: + cmd.append(str(num_jobs)) + subprocess.run(cmd, check=True) + + +def _run_unit_tests(build_dir: Path, test_spec: Optional[str]): + """ + :param build_dir: + :param test_spec: Catch2 test specification. + """ + + cmd = [ + "./unitTest", + ] + if test_spec is not None: + cmd.append(test_spec) + subprocess.run(cmd, cwd=build_dir, check=True) + + +def main(argv: List[str]) -> int: + args_parser = argparse.ArgumentParser( + description="Builds the CLP-core's binaries and runs its unit tests." + ) + args_parser.add_argument( + "--source-dir", required=True, help="Directory containing the main CMakeLists.txt." + ) + args_parser.add_argument("--build-dir", required=True, help="Build output directory.") + args_parser.add_argument( + "--use-shared-libs", + action="store_true", + help="Build targets by linking against shared libraries.", + ) + args_parser.add_argument( + "--num-jobs", type=int, help="Max number of jobs to run when building." + ) + args_parser.add_argument("--test-spec", help="Catch2 test specification.") + + parsed_args = args_parser.parse_args(argv[1:]) + src_dir: Path = Path(parsed_args.source_dir) + build_dir: Path = Path(parsed_args.build_dir) + use_shared_libs: bool = parsed_args.use_shared_libs + num_jobs: Optional[int] = parsed_args.num_jobs + test_spec: Optional[str] = parsed_args.test_spec + + _config_cmake_project(src_dir, build_dir, use_shared_libs) + _build_project(build_dir, num_jobs) + _run_unit_tests(build_dir, test_spec) + + return 0 + + +if "__main__" == __name__: + sys.exit(main(sys.argv)) diff --git a/components/core/tools/scripts/utils/build-and-run-unit-tests.sh b/components/core/tools/scripts/utils/build-and-run-unit-tests.sh deleted file mode 100755 index aae94e0ad..000000000 --- a/components/core/tools/scripts/utils/build-and-run-unit-tests.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# Exit on any error -set -e -# Error on undefined variable -set -u - -cUsage="Usage: ${BASH_SOURCE[0]} [ ]" -if [ "$#" -lt 2 ]; then - echo "$cUsage" - exit 1 -fi -src_dir="$1" -build_dir="$2" -if [ "$#" -gt 2 ]; then - unit_tests_filter="$3" -fi - -cmake -S "$src_dir" -B "$build_dir" -cmake --build "$build_dir" --parallel "$(getconf _NPROCESSORS_ONLN)" -cd "$build_dir" -if [ -z "${unit_tests_filter+x}" ]; then - ./unitTest -else - ./unitTest "$unit_tests_filter" -fi diff --git a/lint-tasks.yml b/lint-tasks.yml index 63cff497f..a3c86cc80 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -151,6 +151,7 @@ tasks: - for: - "components/clp-package-utils/clp_package_utils" - "components/clp-py-utils/clp_py_utils" + - "components/core/tools/scripts/utils" - "components/job-orchestration/job_orchestration" - "tools/scripts" - "docs/conf" From decdc2dd9f15a329bd28d34ff242347d457bf60b Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:22:59 -0400 Subject: [PATCH 064/114] core: Add support for building on Centos Stream 9 and drop support for building on Centos 7.4 (fixes #521). (#528) Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> --- .github/workflows/clp-core-build.yaml | 24 ++++++------ components/core/.clang-format | 4 +- components/core/CMakeLists.txt | 18 +++++++-- components/core/src/clp/MySQLDB.hpp | 2 +- .../core/src/clp/MySQLParamBindings.hpp | 2 +- .../core/src/clp/MySQLPreparedStatement.hpp | 2 +- components/core/src/glt/MySQLDB.hpp | 2 +- .../core/src/glt/MySQLParamBindings.hpp | 2 +- .../core/src/glt/MySQLPreparedStatement.hpp | 2 +- .../clp-env-base-centos-stream-9/Dockerfile | 22 +++++++++++ .../clp-env-base-centos-stream-9/build.sh | 15 +++++++ .../clp-env-base-centos7.4/Dockerfile | 39 ------------------- .../clp-env-base-centos7.4/build.sh | 6 --- .../clp-env-base-centos7.4/setup-scripts/git | 4 -- .../install-all.sh | 4 +- .../install-packages-from-source.sh | 18 +++++++++ .../install-prebuilt-packages.sh | 19 +++++++++ .../centos7.4/install-packages-from-source.sh | 34 ---------------- .../centos7.4/install-prebuilt-packages.sh | 24 ------------ .../lib_install/mariadb-connector-c.sh | 5 ++- ...all.md => centos-stream-9-deps-install.md} | 21 ++-------- docs/src/dev-guide/components-core/index.md | 4 +- docs/src/dev-guide/tooling-containers.md | 8 ++-- docs/src/dev-guide/tooling-gh-workflows.md | 14 +++---- 24 files changed, 129 insertions(+), 166 deletions(-) create mode 100644 components/core/tools/docker-images/clp-env-base-centos-stream-9/Dockerfile create mode 100755 components/core/tools/docker-images/clp-env-base-centos-stream-9/build.sh delete mode 100644 components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile delete mode 100755 components/core/tools/docker-images/clp-env-base-centos7.4/build.sh delete mode 100755 components/core/tools/docker-images/clp-env-base-centos7.4/setup-scripts/git rename components/core/tools/scripts/lib_install/{centos7.4 => centos-stream-9}/install-all.sh (63%) create mode 100755 components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh create mode 100755 components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh delete mode 100755 components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh delete mode 100755 components/core/tools/scripts/lib_install/centos7.4/install-prebuilt-packages.sh rename docs/src/dev-guide/components-core/{centos7.4-deps-install.md => centos-stream-9-deps-install.md} (55%) diff --git a/.github/workflows/clp-core-build.yaml b/.github/workflows/clp-core-build.yaml index fa2c1d4a5..9cec1fc2b 100644 --- a/.github/workflows/clp-core-build.yaml +++ b/.github/workflows/clp-core-build.yaml @@ -36,7 +36,7 @@ jobs: filter-relevant-changes: runs-on: "ubuntu-latest" outputs: - centos74_image_changed: "${{steps.filter.outputs.centos74_image}}" + centos_stream_9_image_changed: "${{steps.filter.outputs.centos_stream_9_image}}" ubuntu_focal_image_changed: "${{steps.filter.outputs.ubuntu_focal_image}}" ubuntu_jammy_image_changed: "${{steps.filter.outputs.ubuntu_jammy_image}}" clp_changed: "${{steps.filter.outputs.clp}}" @@ -63,12 +63,12 @@ jobs: # image (since it would be different from the published image). base: "main" filters: | - centos74_image: + centos_stream_9_image: - ".github/actions/**" - ".github/workflows/clp-core-build.yaml" - "components/core/tools/scripts/lib_install/*.sh" - - "components/core/tools/docker-images/clp-env-base-centos7.4/**" - - "components/core/tools/scripts/lib_install/centos7.4/**" + - "components/core/tools/docker-images/clp-env-base-centos-stream-9/**" + - "components/core/tools/scripts/lib_install/centos-stream-9/**" ubuntu_focal_image: - ".github/actions/**" - ".github/workflows/clp-core-build.yaml" @@ -94,8 +94,8 @@ jobs: - "Taskfile.yml" - "tools/scripts/deps-download/**" - centos74-deps-image: - if: "needs.filter-relevant-changes.outputs.centos74_image_changed == 'true'" + centos-stream-9-deps-image: + if: "needs.filter-relevant-changes.outputs.centos_stream_9_image_changed == 'true'" needs: "filter-relevant-changes" runs-on: "ubuntu-latest" steps: @@ -109,7 +109,7 @@ jobs: - uses: "./.github/actions/clp-core-build-containers" env: - OS_NAME: "centos7.4" + OS_NAME: "centos-stream-9" with: image_name: "${{env.DEPS_IMAGE_NAME_PREFIX}}${{env.OS_NAME}}" docker_context: "components/core" @@ -169,18 +169,18 @@ jobs: ${{github.event_name != 'pull_request' && github.ref == 'refs/heads/main'}} token: "${{secrets.GITHUB_TOKEN}}" - centos74-binaries: + centos-stream-9-binaries: # Run if the ancestor jobs succeeded OR they were skipped and clp was changed. if: >- success() || (!cancelled() && !failure() && needs.filter-relevant-changes.outputs.clp_changed == 'true') needs: - - "centos74-deps-image" + - "centos-stream-9-deps-image" - "filter-relevant-changes" strategy: matrix: use_shared_libs: [true, false] - name: "centos74-${{matrix.use_shared_libs && 'dynamic' || 'static'}}-linked-bins" + name: "centos-stream-9-${{matrix.use_shared_libs && 'dynamic' || 'static'}}-linked-bins" continue-on-error: true runs-on: "ubuntu-latest" steps: @@ -194,12 +194,12 @@ jobs: - uses: "./.github/actions/clp-core-build" env: - OS_NAME: "centos7.4" + OS_NAME: "centos-stream-9" with: image_name: "${{env.DEPS_IMAGE_NAME_PREFIX}}${{env.OS_NAME}}" use_shared_libs: "${{matrix.use_shared_libs}}" use_published_image: >- - ${{needs.filter-relevant-changes.outputs.centos74_image_changed == 'false' + ${{needs.filter-relevant-changes.outputs.centos_stream_9_image_changed == 'false' || (github.event_name != 'pull_request' && github.ref == 'refs/heads/main')}} upload_binaries: "false" diff --git a/components/core/.clang-format b/components/core/.clang-format index 99a0d74ce..c282164b8 100644 --- a/components/core/.clang-format +++ b/components/core/.clang-format @@ -74,8 +74,8 @@ IncludeCategories: # NOTE: A header is grouped by first matching regex # Library headers. Update when adding new libraries. # NOTE: clang-format retains leading white-space on a line in violation of the YAML spec. - - Regex: "<(absl|antlr4|archive|boost|bsoncxx|catch2|curl|date|fmt|json|log_surgeon|mariadb\ -|mongocxx|msgpack|openssl|outcome|regex_utils|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" + - Regex: "<(absl|antlr4|archive|boost|bsoncxx|catch2|curl|date|fmt|json|log_surgeon|mongocxx\ +|msgpack|mysql|openssl|outcome|regex_utils|simdjson|spdlog|sqlite3|string_utils|yaml-cpp|zstd)" Priority: 3 # C system headers - Regex: "^<.+\\.h>" diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 79c685024..a7c6d5a90 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -51,10 +51,20 @@ endif() # Detect linking mode (static or shared); Default to static. set(CLP_USE_STATIC_LIBS ON CACHE BOOL "Whether to link against static libraries") -if (CLP_USE_STATIC_LIBS AND APPLE) - message(AUTHOR_WARNING "Building with static libraries is unsupported on macOS." - " Switching to shared libraries.") - set(CLP_USE_STATIC_LIBS OFF) +if (CLP_USE_STATIC_LIBS) + if (APPLE) + set(CLP_STATIC_LIBS_UNSUPPORTED_PLATFORM "macOS") + elseif (EXISTS "/etc/centos-release") + set(CLP_STATIC_LIBS_UNSUPPORTED_PLATFORM "CentOS") + endif() + + if (DEFINED CLP_STATIC_LIBS_UNSUPPORTED_PLATFORM) + message( + AUTHOR_WARNING + "Building with static libraries is unsupported on" + " ${CLP_STATIC_LIBS_UNSUPPORTED_PLATFORM}. Switching to shared libraries.") + set(CLP_USE_STATIC_LIBS OFF) + endif() endif () if(CLP_USE_STATIC_LIBS) set(CLP_LIBS_STRING "static") diff --git a/components/core/src/clp/MySQLDB.hpp b/components/core/src/clp/MySQLDB.hpp index d60e84bce..42635449b 100644 --- a/components/core/src/clp/MySQLDB.hpp +++ b/components/core/src/clp/MySQLDB.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include "Defs.h" #include "ErrorCode.hpp" diff --git a/components/core/src/clp/MySQLParamBindings.hpp b/components/core/src/clp/MySQLParamBindings.hpp index 42a81e4eb..5a7c7d636 100644 --- a/components/core/src/clp/MySQLParamBindings.hpp +++ b/components/core/src/clp/MySQLParamBindings.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "ErrorCode.hpp" #include "TraceableException.hpp" diff --git a/components/core/src/clp/MySQLPreparedStatement.hpp b/components/core/src/clp/MySQLPreparedStatement.hpp index 1abf3f828..5e25be6f3 100644 --- a/components/core/src/clp/MySQLPreparedStatement.hpp +++ b/components/core/src/clp/MySQLPreparedStatement.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "ErrorCode.hpp" #include "MySQLParamBindings.hpp" diff --git a/components/core/src/glt/MySQLDB.hpp b/components/core/src/glt/MySQLDB.hpp index 4045fce12..97a5d33f5 100644 --- a/components/core/src/glt/MySQLDB.hpp +++ b/components/core/src/glt/MySQLDB.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include "Defs.h" #include "ErrorCode.hpp" diff --git a/components/core/src/glt/MySQLParamBindings.hpp b/components/core/src/glt/MySQLParamBindings.hpp index 754b4401f..abfe8d3a1 100644 --- a/components/core/src/glt/MySQLParamBindings.hpp +++ b/components/core/src/glt/MySQLParamBindings.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "ErrorCode.hpp" #include "TraceableException.hpp" diff --git a/components/core/src/glt/MySQLPreparedStatement.hpp b/components/core/src/glt/MySQLPreparedStatement.hpp index c6cd0e390..ec68dda59 100644 --- a/components/core/src/glt/MySQLPreparedStatement.hpp +++ b/components/core/src/glt/MySQLPreparedStatement.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "ErrorCode.hpp" #include "MySQLParamBindings.hpp" diff --git a/components/core/tools/docker-images/clp-env-base-centos-stream-9/Dockerfile b/components/core/tools/docker-images/clp-env-base-centos-stream-9/Dockerfile new file mode 100644 index 000000000..e7b37fc32 --- /dev/null +++ b/components/core/tools/docker-images/clp-env-base-centos-stream-9/Dockerfile @@ -0,0 +1,22 @@ +FROM dokken/centos-stream-9 AS base + +WORKDIR /root + +RUN mkdir -p ./tools/scripts/lib_install +ADD ./tools/scripts/lib_install ./tools/scripts/lib_install + +RUN ./tools/scripts/lib_install/centos-stream-9/install-all.sh + +# NOTE: +# 1. `task` doesn't have an apt/dnf package so we use its install script. +# 2. We don't want to install it using `install-prebuilt-packages.sh` since users may use that on +# their own machines and it would change their environment in a way that can't easily be undone. +RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin + +# Remove cached files +RUN dnf clean all \ + && rm -rf /tmp/* /var/tmp/* + +# Flatten the image +FROM scratch +COPY --from=base / / diff --git a/components/core/tools/docker-images/clp-env-base-centos-stream-9/build.sh b/components/core/tools/docker-images/clp-env-base-centos-stream-9/build.sh new file mode 100755 index 000000000..fa9cc18ea --- /dev/null +++ b/components/core/tools/docker-images/clp-env-base-centos-stream-9/build.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# Exit on any error +set -e + +# Error on undefined variable +set -u + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +component_root="${script_dir}/../../../" + +docker build \ + --tag clp-core-dependencies-x86-centos-stream-9:dev \ + "$component_root" \ + --file "${script_dir}/Dockerfile" diff --git a/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile b/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile deleted file mode 100644 index feb3ae521..000000000 --- a/components/core/tools/docker-images/clp-env-base-centos7.4/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM centos:centos7.4.1708 AS BASE - -WORKDIR /root - -RUN mkdir -p ./tools/docker-images/clp-env-base-centos7.4 -ADD ./tools/docker-images/clp-env-base-centos7.4/setup-scripts ./tools/docker-images/clp-env-base-centos7.4/setup-scripts - -RUN mkdir -p ./tools/scripts/lib_install -ADD ./tools/scripts/lib_install ./tools/scripts/lib_install - -RUN ./tools/scripts/lib_install/centos7.4/install-all.sh - -# Enable gcc 10 in login shells and non-interactive non-login shells -RUN ln -s /opt/rh/devtoolset-10/enable /etc/profile.d/devtoolset.sh - -# Enable git 2.27 -# NOTE: We use a script to enable the SCL git package on each git call because some Github actions -# cannot be forced to use a bash shell that loads .bashrc -RUN cp ./tools/docker-images/clp-env-base-centos7.4/setup-scripts/git /usr/bin/git - -# NOTE: -# 1. `task` doesn't have an apt/yum package so we use its install script. -# 2. We don't want to install it using `install-prebuilt-packages.sh` since users may use that on -# their own machines and it would change their environment in a way that can't easily be undone. -RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin - -# Remove cached files -RUN yum clean all \ - && rm -rf /tmp/* /var/tmp/* - -# Flatten the image -FROM scratch -COPY --from=BASE / / - -# Set PKG_CONFIG_PATH since CentOS doesn't look in /usr/local by default -ENV PKG_CONFIG_PATH /usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig - -# Load .bashrc for non-interactive bash shells -ENV BASH_ENV=/etc/bashrc diff --git a/components/core/tools/docker-images/clp-env-base-centos7.4/build.sh b/components/core/tools/docker-images/clp-env-base-centos7.4/build.sh deleted file mode 100755 index 41f6bceae..000000000 --- a/components/core/tools/docker-images/clp-env-base-centos7.4/build.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" -component_root=${script_dir}/../../../ - -docker build -t clp-core-dependencies-x86-centos7.4:dev ${component_root} --file ${script_dir}/Dockerfile diff --git a/components/core/tools/docker-images/clp-env-base-centos7.4/setup-scripts/git b/components/core/tools/docker-images/clp-env-base-centos7.4/setup-scripts/git deleted file mode 100755 index 8e18fb754..000000000 --- a/components/core/tools/docker-images/clp-env-base-centos7.4/setup-scripts/git +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -source /opt/rh/rh-git227/enable -git "$@" diff --git a/components/core/tools/scripts/lib_install/centos7.4/install-all.sh b/components/core/tools/scripts/lib_install/centos-stream-9/install-all.sh similarity index 63% rename from components/core/tools/scripts/lib_install/centos7.4/install-all.sh rename to components/core/tools/scripts/lib_install/centos-stream-9/install-all.sh index e338a30d7..c50fb81cc 100755 --- a/components/core/tools/scripts/lib_install/centos7.4/install-all.sh +++ b/components/core/tools/scripts/lib_install/centos-stream-9/install-all.sh @@ -8,5 +8,5 @@ set -u script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" -"$script_dir"/install-prebuilt-packages.sh -"$script_dir"/install-packages-from-source.sh +"${script_dir}/install-prebuilt-packages.sh" +"${script_dir}/install-packages-from-source.sh" diff --git a/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh new file mode 100755 index 000000000..e0b6a6c28 --- /dev/null +++ b/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Exit on any error +set -e + +# Error on undefined variable +set -u + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +lib_install_scripts_dir="${script_dir}/.." + +# NOTE: The remaining installation scripts depend on boost, so we install it beforehand. +"${lib_install_scripts_dir}/install-boost.sh" 1.76.0 + +"${lib_install_scripts_dir}/fmtlib.sh" 8.0.1 +"${lib_install_scripts_dir}/spdlog.sh" 1.9.2 +"${lib_install_scripts_dir}/mongocxx.sh" 3.10.2 +"${lib_install_scripts_dir}/msgpack.sh" 6.0.0 diff --git a/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh b/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh new file mode 100755 index 000000000..e90f54733 --- /dev/null +++ b/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# Exit on any error +set -e + +# Error on undefined variable +set -u + +dnf install -y \ + cmake \ + gcc-c++ \ + git \ + java-11-openjdk \ + libarchive-devel \ + libcurl-devel \ + libzstd-devel \ + make \ + mariadb-connector-c-devel \ + openssl-devel diff --git a/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh deleted file mode 100755 index 82f2abb1c..000000000 --- a/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -# Exit on any error -set -e - -# Enable gcc 10 -source /opt/rh/devtoolset-10/enable - -# Enable git -source /opt/rh/rh-git227/enable - -# Error on undefined variable -# NOTE: We enable this *after* sourcing the scripts above since we can't guarantee they won't have -# unbound variables in them. -set -u - -script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" -lib_install_scripts_dir=$script_dir/.. - -# NOTE: The remaining installation scripts depend on curl, so we install it first. -"$lib_install_scripts_dir"/install-curl.sh 8.8.0 - -# NOTE: The remaining installation scripts depend on cmake and boost, so we install them beforehand. -"$lib_install_scripts_dir"/install-cmake.sh 3.21.2 -"$lib_install_scripts_dir"/install-boost.sh 1.76.0 - -"$lib_install_scripts_dir"/fmtlib.sh 8.0.1 -"$lib_install_scripts_dir"/libarchive.sh 3.5.1 -"$lib_install_scripts_dir"/lz4.sh 1.8.2 -"$lib_install_scripts_dir"/mariadb-connector-c.sh 3.2.3 -"$lib_install_scripts_dir"/mongocxx.sh 3.10.2 -"$lib_install_scripts_dir"/msgpack.sh 6.0.0 -"$lib_install_scripts_dir"/spdlog.sh 1.9.2 -"$lib_install_scripts_dir"/zstandard.sh 1.4.9 diff --git a/components/core/tools/scripts/lib_install/centos7.4/install-prebuilt-packages.sh b/components/core/tools/scripts/lib_install/centos7.4/install-prebuilt-packages.sh deleted file mode 100755 index f7d14ad7c..000000000 --- a/components/core/tools/scripts/lib_install/centos7.4/install-prebuilt-packages.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# Exit on any error -set -e - -# Error on undefined variable -set -u - -yum install -y \ - bzip2 \ - centos-release-scl \ - java-11-openjdk \ - make \ - openssl-devel \ - openssl-static \ - python3 \ - python3-pip \ - rsync \ - zlib-static - -# Install packages from CentOS' software collections repository (centos-release-scl) -yum install -y \ - devtoolset-10 \ - rh-git227 diff --git a/components/core/tools/scripts/lib_install/mariadb-connector-c.sh b/components/core/tools/scripts/lib_install/mariadb-connector-c.sh index 7ec16f409..4159f5f9b 100755 --- a/components/core/tools/scripts/lib_install/mariadb-connector-c.sh +++ b/components/core/tools/scripts/lib_install/mariadb-connector-c.sh @@ -47,8 +47,9 @@ fi source /etc/os-release if [ $ID = "ubuntu" ] ; then os_version=ubuntu-$UBUNTU_CODENAME -elif [ $ID = "centos" ] ; then - os_version=centos${VERSION_ID} +else + echo "Unsupported OS ID: $ID" + exit 1 fi # Download diff --git a/docs/src/dev-guide/components-core/centos7.4-deps-install.md b/docs/src/dev-guide/components-core/centos-stream-9-deps-install.md similarity index 55% rename from docs/src/dev-guide/components-core/centos7.4-deps-install.md rename to docs/src/dev-guide/components-core/centos-stream-9-deps-install.md index 040bafa42..654b9bf5a 100644 --- a/docs/src/dev-guide/components-core/centos7.4-deps-install.md +++ b/docs/src/dev-guide/components-core/centos-stream-9-deps-install.md @@ -1,4 +1,4 @@ -# Centos 7.4 setup +# Centos Stream 9 setup To install the dependencies required to build clp-core, follow the steps below. These same steps are used by our Docker containers. @@ -18,22 +18,7 @@ without using a packager. So if you ever need to uninstall them, you will need t ::: ```shell -components/core/tools/scripts/lib_install/centos7.4/install-all.sh +components/core/tools/scripts/lib_install/centos-stream-9/install-all.sh ``` -## Set up dependencies - -* Enable gcc 10 - - ```shell - ln -s /opt/rh/devtoolset-10/enable /etc/profile.d/devtoolset.sh - ``` - -* Set PKG_CONFIG_PATH since CentOS doesn't look in `/usr/local` by default. - You should add this to your shell's profile/startup file (e.g., `.bashrc`). - - ```shell - export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig - ``` - -[src-install-script]: https://github.com/y-scope/clp/blob/main/components/core/tools/scripts/lib_install/centos7.4/install-packages-from-source.sh +[src-install-script]: https://github.com/y-scope/clp/blob/main/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh diff --git a/docs/src/dev-guide/components-core/index.md b/docs/src/dev-guide/components-core/index.md index cffb0f004..36fdad548 100644 --- a/docs/src/dev-guide/components-core/index.md +++ b/docs/src/dev-guide/components-core/index.md @@ -53,7 +53,7 @@ A handful of packages and libraries are required to build CLP. There are two opt See the relevant README for your OS: -* [CentOS 7.4](centos7.4-deps-install) +* [CentOS Stream 9](centos-stream-9-deps-install) * [macOS 12](macos12-deps-install) * [Ubuntu 20.04](ubuntu-focal-deps-install) * [Ubuntu 22.04](ubuntu-jammy-deps-install) @@ -97,7 +97,7 @@ the relevant paths on your machine. :::{toctree} :hidden: -centos7.4-deps-install +centos-stream-9-deps-install macos12-deps-install ubuntu-focal-deps-install ubuntu-jammy-deps-install diff --git a/docs/src/dev-guide/tooling-containers.md b/docs/src/dev-guide/tooling-containers.md index 1b1490e5f..9dc6238f8 100644 --- a/docs/src/dev-guide/tooling-containers.md +++ b/docs/src/dev-guide/tooling-containers.md @@ -3,11 +3,11 @@ We publish (to [GitHub packages][gh-packages]) several Docker container images useful for building and running CLP: -* An [image][core-deps-centos-7.4] containing the dependencies necessary to build CLP core in a - Centos 7.4 x86 environment. +* An [image][core-deps-centos-stream-9] containing the dependencies necessary to build CLP core in a + Centos Stream 9 x86 environment. ```text - ghcr.io/y-scope/clp/clp-core-dependencies-x86-centos7.4:main + ghcr.io/y-scope/clp/clp-core-dependencies-x86-centos-stream-9:main ``` * An [image][core-deps-ubuntu-focal] containing the dependencies necessary to build CLP core in an @@ -45,7 +45,7 @@ and running CLP: ghcr.io/y-scope/clp/clp-execution-x86-ubuntu-jammy:main ``` -[core-deps-centos-7.4]: https://github.com/y-scope/clp/pkgs/container/clp%2Fclp-core-dependencies-x86-centos7.4 +[core-deps-centos-stream-9]: https://github.com/y-scope/clp/pkgs/container/clp%2Fclp-core-dependencies-x86-centos-stream-9 [core-deps-ubuntu-focal]: https://github.com/y-scope/clp/pkgs/container/clp%2Fclp-core-dependencies-x86-ubuntu-focal [core-deps-ubuntu-jammy]: https://github.com/y-scope/clp/pkgs/container/clp%2Fclp-core-dependencies-x86-ubuntu-jammy [core-ubuntu-focal]: https://github.com/y-scope/clp/pkgs/container/clp%2Fclp-core-x86-ubuntu-focal diff --git a/docs/src/dev-guide/tooling-gh-workflows.md b/docs/src/dev-guide/tooling-gh-workflows.md index bd3da8606..ffaec430f 100644 --- a/docs/src/dev-guide/tooling-gh-workflows.md +++ b/docs/src/dev-guide/tooling-gh-workflows.md @@ -28,13 +28,13 @@ shown below. } }%% flowchart LR - filter-relevant-changes --> centos74-deps-image + filter-relevant-changes --> centos-stream-9-deps-image filter-relevant-changes --> ubuntu-focal-deps-image filter-relevant-changes --> ubuntu-jammy-deps-image - filter-relevant-changes --> centos74-binaries + filter-relevant-changes --> centos-stream-9-binaries filter-relevant-changes --> ubuntu-focal-binaries filter-relevant-changes --> ubuntu-jammy-binaries - centos74-deps-image --> centos74-binaries + centos-stream-9-deps-image --> centos-stream-9-binaries ubuntu-focal-deps-image --> ubuntu-focal-binaries ubuntu-jammy-deps-image --> ubuntu-jammy-binaries ubuntu-focal-binaries --> ubuntu-focal-binaries-image @@ -44,14 +44,14 @@ Arrows between jobs indicate a dependency. The jobs are as follows: * `filter-relevant-changes`: Filters the changes in the pull request or commit to determine which of the following jobs should run. -* `centos74-deps-image`: Builds a container image containing the dependencies necessary to build - CLP-core in a CentOS 7.4 x86 environment. +* `centos-stream-9-deps-image`: Builds a container image containing the dependencies necessary to + build CLP-core in a CentOS Stream 9 x86 environment. * `ubuntu-focal-deps-image`: Builds a container image containing the dependencies necessary to build CLP-core in an Ubuntu Focal x86 environment. * `ubuntu-jammy-deps-image`: Builds a container image containing the dependencies necessary to build CLP-core in an Ubuntu Jammy x86 environment. -* `centos74-binaries`: Builds the CLP-core binaries in the built CentOS 7.4 container and runs - core's unit tests. +* `centos-stream-9-binaries`: Builds the CLP-core binaries in the built CentOS Stream 9 container + and runs core's unit tests. * `ubuntu-focal-binaries`: Builds the CLP-core binaries in the built Ubuntu Focal container and runs core's unit tests. * `ubuntu-jammy-binaries`: Builds the CLP-core binaries in the built Ubuntu Jammy container and runs From cb434593b7ad340d59879811720d315327de1640 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sun, 8 Sep 2024 21:33:02 -0400 Subject: [PATCH 065/114] core: Replace `std::unique_ptr` with `Array` in `NetworkReader`. (#531) --- components/core/src/clp/NetworkReader.cpp | 10 ++++++---- components/core/src/clp/NetworkReader.hpp | 6 +++--- components/core/tests/test-NetworkReader.cpp | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/components/core/src/clp/NetworkReader.cpp b/components/core/src/clp/NetworkReader.cpp index 706763362..cdde759c2 100644 --- a/components/core/src/clp/NetworkReader.cpp +++ b/components/core/src/clp/NetworkReader.cpp @@ -128,8 +128,7 @@ NetworkReader::NetworkReader( m_buffer_pool_size{std::max(cMinBufferPoolSize, buffer_pool_size)}, m_buffer_size{std::max(cMinBufferSize, buffer_size)} { for (size_t i = 0; i < m_buffer_pool_size; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) - m_buffer_pool.emplace_back(std::make_unique(m_buffer_size)); + m_buffer_pool.emplace_back(m_buffer_size); } m_downloader_thread = std::make_unique(*this, offset, disable_caching); m_downloader_thread->start(); @@ -248,7 +247,10 @@ auto NetworkReader::acquire_empty_buffer() -> void { return; } } - m_curr_downloader_buf.emplace(m_buffer_pool.at(m_curr_downloader_buf_idx).get(), m_buffer_size); + m_curr_downloader_buf.emplace( + m_buffer_pool.at(m_curr_downloader_buf_idx).data(), + m_buffer_size + ); } auto NetworkReader::release_empty_buffer() -> void { @@ -264,7 +266,7 @@ auto NetworkReader::enqueue_filled_buffer() -> void { } std::unique_lock const buffer_resource_lock{m_buffer_resource_mutex}; m_filled_buffer_queue.emplace( - m_buffer_pool.at(m_curr_downloader_buf_idx).get(), + m_buffer_pool.at(m_curr_downloader_buf_idx).data(), m_buffer_size - m_curr_downloader_buf.value().size() ); diff --git a/components/core/src/clp/NetworkReader.hpp b/components/core/src/clp/NetworkReader.hpp index ba581d067..7c808fd4f 100644 --- a/components/core/src/clp/NetworkReader.hpp +++ b/components/core/src/clp/NetworkReader.hpp @@ -17,6 +17,7 @@ #include +#include "Array.hpp" #include "CurlDownloadHandler.hpp" #include "CurlGlobalInstance.hpp" #include "ErrorCode.hpp" @@ -106,7 +107,7 @@ class NetworkReader : public ReaderInterface { ); // Destructor - virtual ~NetworkReader(); + ~NetworkReader() override; // Copy/Move Constructors // These are disabled since this class' synchronization primitives are non-copyable and @@ -330,8 +331,7 @@ class NetworkReader : public ReaderInterface { size_t m_buffer_size{cDefaultBufferSize}; size_t m_curr_downloader_buf_idx{0}; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) - std::vector> m_buffer_pool; + std::vector> m_buffer_pool; std::queue m_filled_buffer_queue; std::optional m_curr_downloader_buf; std::optional m_curr_reader_buf; diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index 5a900ced3..cd4b90cc0 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -11,6 +11,7 @@ #include #include +#include "../src/clp/Array.hpp" #include "../src/clp/CurlDownloadHandler.hpp" #include "../src/clp/CurlGlobalInstance.hpp" #include "../src/clp/ErrorCode.hpp" @@ -65,12 +66,11 @@ auto get_test_input_path_relative_to_tests_dir() -> std::filesystem::path { auto get_content(clp::ReaderInterface& reader, size_t read_buf_size) -> std::vector { std::vector buf; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) - auto const read_buf{std::make_unique(read_buf_size)}; + clp::Array read_buf{read_buf_size}; for (bool has_more_content{true}; has_more_content;) { size_t num_bytes_read{}; - has_more_content = reader.read(read_buf.get(), read_buf_size, num_bytes_read); - std::string_view const view{read_buf.get(), num_bytes_read}; + has_more_content = reader.read(read_buf.data(), read_buf_size, num_bytes_read); + std::string_view const view{read_buf.data(), num_bytes_read}; buf.insert(buf.cend(), view.cbegin(), view.cend()); } return buf; From 5b7ab18955937cba50fddfdad3f284b77825fc94 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sun, 8 Sep 2024 23:10:54 -0400 Subject: [PATCH 066/114] ffi: Add support for serializing a `KeyValuePairLogEvent` as a `nlohmann::json` object. (#512) Co-authored-by: Devin Gibson Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../core/src/clp/ffi/KeyValuePairLogEvent.cpp | 300 +++++++++++++++++- .../core/src/clp/ffi/KeyValuePairLogEvent.hpp | 13 + .../core/tests/test-ir_encoding_methods.cpp | 8 +- 3 files changed, 317 insertions(+), 4 deletions(-) diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp index d08803e08..4b528c039 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp @@ -1,6 +1,8 @@ #include "KeyValuePairLogEvent.hpp" #include +#include +#include #include #include #include @@ -9,6 +11,7 @@ #include #include +#include #include #include "../ir/EncodedTextAst.hpp" @@ -20,9 +23,98 @@ using clp::ir::EightByteEncodedTextAst; using clp::ir::FourByteEncodedTextAst; using std::string; +using std::vector; namespace clp::ffi { namespace { +/** + * Concept for a function to handle a JSON exception. + * @tparam Func + */ +template +concept JsonExceptionHandlerConcept = std::is_invocable_v; + +/** + * Helper class for `KeyValuePairLogEvent::serialize_to_json`, used to: + * - iterate over the children of a non-leaf schema tree node, so long as those children are in the + * subtree defined by the `KeyValuePairLogEvent`. + * - group a non-leaf schema tree node with the JSON object that it's being serialized into. + * - add the node's corresponding JSON object to its parent's corresponding JSON object (or if the + * node is the root, replace the parent JSON object) when this class is destructed. + * @tparam JsonExceptionHandler Type of handler for any `nlohmann::json::exception` that occurs + * during destruction. + */ +template +class JsonSerializationIterator { +public: + // Constructor + JsonSerializationIterator( + SchemaTreeNode const* schema_tree_node, + vector const& schema_subtree_bitmap, + nlohmann::json::object_t* parent_json_obj, + JsonExceptionHandler json_exception_callback + ) + : m_schema_tree_node{schema_tree_node}, + m_parent_json_obj{parent_json_obj}, + m_json_exception_callback{json_exception_callback} { + for (auto const child_id : schema_tree_node->get_children_ids()) { + if (schema_subtree_bitmap[child_id]) { + m_child_schema_tree_nodes.push_back(child_id); + } + } + m_child_schema_tree_node_it = m_child_schema_tree_nodes.cbegin(); + } + + // Delete copy/move constructor and assignment + JsonSerializationIterator(JsonSerializationIterator const&) = delete; + JsonSerializationIterator(JsonSerializationIterator&&) = delete; + auto operator=(JsonSerializationIterator const&) -> JsonSerializationIterator& = delete; + auto operator=(JsonSerializationIterator&&) -> JsonSerializationIterator& = delete; + + // Destructor + ~JsonSerializationIterator() { + try { + // If the current node is the root, then replace the `parent` with this node's JSON + // object. Otherwise, add this node's JSON object as a child of the parent JSON object. + if (m_schema_tree_node->get_id() == SchemaTree::cRootId) { + *m_parent_json_obj = std::move(m_json_obj); + } else { + m_parent_json_obj->emplace( + string{m_schema_tree_node->get_key_name()}, + std::move(m_json_obj) + ); + } + } catch (nlohmann::json::exception const& ex) { + m_json_exception_callback(ex); + } + } + + /** + * @return Whether there are more child schema tree nodes to traverse. + */ + [[nodiscard]] auto has_next_child_schema_tree_node() const -> bool { + return m_child_schema_tree_node_it != m_child_schema_tree_nodes.end(); + } + + /** + * Gets the next child schema tree node and advances the iterator. + * @return The next child schema tree node. + */ + [[nodiscard]] auto get_next_child_schema_tree_node() -> SchemaTreeNode::id_t { + return *(m_child_schema_tree_node_it++); + } + + [[nodiscard]] auto get_json_obj() -> nlohmann::json::object_t& { return m_json_obj; } + +private: + SchemaTreeNode const* m_schema_tree_node; + vector m_child_schema_tree_nodes; + vector::const_iterator m_child_schema_tree_node_it; + nlohmann::json::object_t* m_parent_json_obj; + nlohmann::json::object_t m_json_obj; + JsonExceptionHandler m_json_exception_callback; +}; + /** * @param type * @param value @@ -62,6 +154,42 @@ node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> b KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs ) -> bool; +/** + * @param node_id_value_pairs + * @param schema_tree + * @return A result containing a bitmap where every bit corresponds to the ID of a node in the + * schema tree, and the set bits correspond to the nodes in the subtree defined by all paths from + * the root node to the nodes in `node_id_value_pairs`; or an error code indicating a failure: + * - std::errc::result_out_of_range if a node ID in `node_id_value_pairs` doesn't exist in the + * schema tree. + */ +[[nodiscard]] auto get_schema_subtree_bitmap( + KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs, + SchemaTree const& schema_tree +) -> OUTCOME_V2_NAMESPACE::std_result>; + +/** + * Inserts the given key-value pair into the JSON object (map). + * @param node The schema tree node of the key to insert. + * @param optional_val The value to insert. + * @param json_obj The JSON object to insert the kv-pair into. + * @return Whether the insertion was successful. + */ +[[nodiscard]] auto insert_kv_pair_into_json_obj( + SchemaTreeNode const& node, + std::optional const& optional_val, + nlohmann::json::object_t& json_obj +) -> bool; + +/** + * Decodes a value as an `EncodedTextAst` according to the encoding type. + * NOTE: This function assumes that `val` is either a `FourByteEncodedTextAst` or + * `EightByteEncodedTextAst`. + * @param val + * @return Same as `EncodedTextAst::decode_and_unparse`. + */ +[[nodiscard]] auto decode_as_encoded_text_ast(Value const& val) -> std::optional; + auto node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> bool { switch (type) { case SchemaTreeNode::Type::Obj: @@ -138,7 +266,7 @@ auto is_leaf_node( SchemaTreeNode::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs ) -> bool { - std::vector dfs_stack; + vector dfs_stack; dfs_stack.reserve(schema_tree.get_size()); dfs_stack.push_back(node_id); while (false == dfs_stack.empty()) { @@ -153,6 +281,98 @@ auto is_leaf_node( } return true; } + +auto get_schema_subtree_bitmap( + KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs, + SchemaTree const& schema_tree +) -> OUTCOME_V2_NAMESPACE::std_result> { + auto schema_subtree_bitmap{vector(schema_tree.get_size(), false)}; + for (auto const& [node_id, val] : node_id_value_pairs) { + if (node_id >= schema_subtree_bitmap.size()) { + return std::errc::result_out_of_range; + } + schema_subtree_bitmap[node_id] = true; + + // Iteratively mark the parents as true + auto parent_id{schema_tree.get_node(node_id).get_parent_id()}; + while (true) { + if (schema_subtree_bitmap[parent_id]) { + // Parent already set by other child + break; + } + schema_subtree_bitmap[parent_id] = true; + if (SchemaTree::cRootId == parent_id) { + break; + } + parent_id = schema_tree.get_node(parent_id).get_parent_id(); + } + } + return schema_subtree_bitmap; +} + +auto insert_kv_pair_into_json_obj( + SchemaTreeNode const& node, + std::optional const& optional_val, + nlohmann::json::object_t& json_obj +) -> bool { + string const key_name{node.get_key_name()}; + auto const type{node.get_type()}; + if (false == optional_val.has_value()) { + json_obj.emplace(key_name, nlohmann::json::object()); + return true; + } + + try { + auto const& val{optional_val.value()}; + switch (type) { + case SchemaTreeNode::Type::Int: + json_obj.emplace(key_name, val.get_immutable_view()); + break; + case SchemaTreeNode::Type::Float: + json_obj.emplace(key_name, val.get_immutable_view()); + break; + case SchemaTreeNode::Type::Bool: + json_obj.emplace(key_name, val.get_immutable_view()); + break; + case SchemaTreeNode::Type::Str: + if (val.is()) { + json_obj.emplace(key_name, string{val.get_immutable_view()}); + } else { + auto const decoded_result{decode_as_encoded_text_ast(val)}; + if (false == decoded_result.has_value()) { + return false; + } + json_obj.emplace(key_name, decoded_result.value()); + } + break; + case SchemaTreeNode::Type::UnstructuredArray: { + auto const decoded_result{decode_as_encoded_text_ast(val)}; + if (false == decoded_result.has_value()) { + return false; + } + json_obj.emplace(key_name, nlohmann::json::parse(decoded_result.value())); + break; + } + case SchemaTreeNode::Type::Obj: + json_obj.emplace(key_name, nullptr); + break; + default: + return false; + } + } catch (nlohmann::json::exception const& ex) { + return false; + } catch (Value::OperationFailed const& ex) { + return false; + } + + return true; +} + +auto decode_as_encoded_text_ast(Value const& val) -> std::optional { + return val.is() + ? val.get_immutable_view().decode_and_unparse() + : val.get_immutable_view().decode_and_unparse(); +} } // namespace auto KeyValuePairLogEvent::create( @@ -167,4 +387,82 @@ auto KeyValuePairLogEvent::create( } return KeyValuePairLogEvent{std::move(schema_tree), std::move(node_id_value_pairs), utc_offset}; } + +auto KeyValuePairLogEvent::serialize_to_json( +) const -> OUTCOME_V2_NAMESPACE::std_result { + if (m_node_id_value_pairs.empty()) { + return nlohmann::json::object(); + } + + bool json_exception_captured{false}; + auto json_exception_handler = [&]([[maybe_unused]] nlohmann::json::exception const& ex + ) -> void { json_exception_captured = true; }; + using DfsIterator = JsonSerializationIterator; + + // NOTE: We use a `std::stack` (which uses `std::deque` as the underlying container) instead of + // a `std::vector` to avoid implementing move semantics for `DfsIterator` (required when the + // vector grows). + std::stack dfs_stack; + + auto const schema_subtree_bitmap_ret{ + get_schema_subtree_bitmap(m_node_id_value_pairs, *m_schema_tree) + }; + if (schema_subtree_bitmap_ret.has_error()) { + return schema_subtree_bitmap_ret.error(); + } + auto const& schema_subtree_bitmap{schema_subtree_bitmap_ret.value()}; + + // Traverse the schema tree in DFS order, but only traverse the nodes that are set in + // `schema_subtree_bitmap`. + // + // On the way down: + // - for each non-leaf node, create a `nlohmann::json::object_t`; + // - for each leaf node, insert the key-value pair into the parent `nlohmann::json::object_t`. + // + // On the way up, add the current node's `nlohmann::json::object_t` to the parent's + // `nlohmann::json::object_t`. + auto const& root_schema_tree_node{m_schema_tree->get_node(SchemaTree::cRootId)}; + auto root_json_obj = nlohmann::json::object_t(); + + dfs_stack.emplace( + &root_schema_tree_node, + schema_subtree_bitmap, + &root_json_obj, + json_exception_handler + ); + while (false == dfs_stack.empty() && false == json_exception_captured) { + auto& top{dfs_stack.top()}; + if (false == top.has_next_child_schema_tree_node()) { + dfs_stack.pop(); + continue; + } + auto const child_schema_tree_node_id{top.get_next_child_schema_tree_node()}; + auto const& child_schema_tree_node{m_schema_tree->get_node(child_schema_tree_node_id)}; + if (m_node_id_value_pairs.contains(child_schema_tree_node_id)) { + // Handle leaf node + if (false + == insert_kv_pair_into_json_obj( + child_schema_tree_node, + m_node_id_value_pairs.at(child_schema_tree_node_id), + top.get_json_obj() + )) + { + return std::errc::protocol_error; + } + } else { + dfs_stack.emplace( + &child_schema_tree_node, + schema_subtree_bitmap, + &top.get_json_obj(), + json_exception_handler + ); + } + } + + if (json_exception_captured) { + return std::errc::protocol_error; + } + + return root_json_obj; +} } // namespace clp::ffi diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp index ad50ee41f..e08128f49 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "../time_types.hpp" @@ -60,6 +61,18 @@ class KeyValuePairLogEvent { [[nodiscard]] auto get_utc_offset() const -> UtcOffset { return m_utc_offset; } + /** + * Serializes the log event into a `nlohmann::json` object. + * @return A result containing the serialized JSON object or an error code indicating the + * failure: + * - std::errc::protocol_error if a value in the log event couldn't be decoded or it couldn't be + * inserted into a JSON object. + * - std::errc::result_out_of_range if a node ID in the log event doesn't exist in the schema + * tree. + */ + [[nodiscard]] auto serialize_to_json( + ) const -> OUTCOME_V2_NAMESPACE::std_result; + private: // Constructor KeyValuePairLogEvent( diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index 6eec92673..af8314369 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -1133,12 +1133,14 @@ TEMPLATE_TEST_CASE( for (auto const& json_obj : serialized_json_objects) { auto const kv_log_event_result = deserializer.deserialize_to_next_log_event(reader); REQUIRE_FALSE(kv_log_event_result.has_error()); + auto const& kv_log_event = kv_log_event_result.value(); auto const num_leaves_in_json_obj = count_num_leaves(json_obj); auto const num_kv_pairs = kv_log_event.get_node_id_value_pairs().size(); REQUIRE((num_leaves_in_json_obj == num_kv_pairs)); - } - // TODO: Test validating the deserialized bytes once we've implemented a KeyValuePairLogEvent to - // JSON deserializer. + auto const serialized_json_result = kv_log_event.serialize_to_json(); + REQUIRE_FALSE(serialized_json_result.has_error()); + REQUIRE((json_obj == serialized_json_result.value())); + } } From b6de798631f02c55617969d8df52a39e4312b899 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:34:46 -0400 Subject: [PATCH 067/114] log-viewer-webui: Update to latest version of yscope-log-viewer to resolve out-of-sync package-lock.json file (#530) --- components/log-viewer-webui/yscope-log-viewer | 2 +- deps-tasks.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/log-viewer-webui/yscope-log-viewer b/components/log-viewer-webui/yscope-log-viewer index df996eac0..c939f7b55 160000 --- a/components/log-viewer-webui/yscope-log-viewer +++ b/components/log-viewer-webui/yscope-log-viewer @@ -1 +1 @@ -Subproject commit df996eac000823d02f9cd0b9eb4bb732dd634ae5 +Subproject commit c939f7b55b55b42f65226470d5277b15ac484665 diff --git a/deps-tasks.yml b/deps-tasks.yml index daf6186cd..bfe80d8b5 100644 --- a/deps-tasks.yml +++ b/deps-tasks.yml @@ -421,8 +421,8 @@ tasks: vars: DEST: "{{.DEST}}" FLAGS: "--extract" - SRC_NAME: "yscope-log-viewer-df996eac000823d02f9cd0b9eb4bb732dd634ae5" - SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/df996ea.zip" + SRC_NAME: "yscope-log-viewer-c939f7b55b55b42f65226470d5277b15ac484665" + SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/c939f7b.zip" # This command must be last - task: ":utils:compute-checksum" vars: From e88122c06c35b2ba3bb0ab16680e34c76479eb4d Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:27:54 -0400 Subject: [PATCH 068/114] ffi: Fix some missing errors and spelling mistakes in the KV-pair IR format docstrings. (#533) Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> --- components/core/src/clp/ffi/KeyValuePairLogEvent.hpp | 2 +- components/core/src/clp/ffi/SchemaTree.hpp | 4 +++- components/core/src/clp/ffi/ir_stream/Deserializer.hpp | 9 +++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp index e08128f49..120588569 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp @@ -33,7 +33,7 @@ class KeyValuePairLogEvent { * @param node_id_value_pairs * @param utc_offset * @return A result containing the key-value pair log event or an error code indicating the - * failure. See `valdiate_node_id_value_pairs` for the possible error codes. + * failure. See `validate_node_id_value_pairs` for the possible error codes. */ [[nodiscard]] static auto create( std::shared_ptr schema_tree, diff --git a/components/core/src/clp/ffi/SchemaTree.hpp b/components/core/src/clp/ffi/SchemaTree.hpp index 6683103c5..5b07e8a09 100644 --- a/components/core/src/clp/ffi/SchemaTree.hpp +++ b/components/core/src/clp/ffi/SchemaTree.hpp @@ -167,7 +167,9 @@ class SchemaTree { * Inserts a new node corresponding to the given locator. * @param locator * @return The ID of the inserted node. - * @throw OperationFailed if a node that corresponds to the given locator already exists. + * @throw OperationFailed if: + * - a node that corresponds to the given locator already exists. + * - the parent node identified by the locator is not an object. */ [[maybe_unused]] auto insert_node(NodeLocator const& locator) -> SchemaTreeNode::id_t; diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp index c7327fd5b..7ba7822da 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp @@ -50,12 +50,13 @@ class Deserializer { * @param reader * @return A result containing the deserialized log event or an error code indicating the * failure: - * - std::errc::result_out_of_range if the IR stream is truncated - * - std::errc::protocol_error if the IR stream is corrupted + * - std::errc::no_message_available if the IR stream has been fully consumed. + * - std::errc::result_out_of_range if the IR stream is truncated. + * - std::errc::protocol_error if the IR stream is corrupted. * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format - * or uses an unsupported version + * or uses an unsupported version. * - Same as `KeyValuePairLogEvent::create` if the intermediate deserialized result cannot - * construct a valid key-value pair log event + * construct a valid key-value pair log event. */ [[nodiscard]] auto deserialize_to_next_log_event(ReaderInterface& reader ) -> OUTCOME_V2_NAMESPACE::std_result; From a3196613b6df5aa8c1d8bf5523488ec688e41c33 Mon Sep 17 00:00:00 2001 From: zechenericduan <97798548+zechenericduan@users.noreply.github.com> Date: Mon, 9 Sep 2024 18:06:42 -0400 Subject: [PATCH 069/114] docs: Fix dependency install script path and add missing requirement for building the package. (#532) --- docs/src/dev-guide/building-package.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/dev-guide/building-package.md b/docs/src/dev-guide/building-package.md index 4cf4e5349..c0778b1c4 100644 --- a/docs/src/dev-guide/building-package.md +++ b/docs/src/dev-guide/building-package.md @@ -11,6 +11,7 @@ prebuilt version instead, check out the [releases](https://github.com/y-scope/cl * It should be possible to build a package for a different environment, it just requires a some extra configuration. * Python 3.8 or newer +* python3-dev * python3-venv * [Task](https://taskfile.dev/) @@ -25,7 +26,7 @@ tools/scripts/deps-download/init.sh Install CLP core's dependencies ```shell -components/core/tools/ubuntu-focal/install-all.sh +components/core/tools/scripts/lib_install/ubuntu-focal/install-all.sh ``` ## Build From 8ea88fc96a596b0b3b56b8a87d57ca77619c2e3c Mon Sep 17 00:00:00 2001 From: diy1 Date: Thu, 12 Sep 2024 22:57:23 -0400 Subject: [PATCH 070/114] Add OSDI'24 paper on JSON log handling to the README. (#538) Co-authored-by: Ding Yuan --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5d8d00f38..4a5c4a81d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ YScope's Compressed Log Processor (CLP) compresses your logs, and allows you to compressed logs without decompression. CLP supports both JSON logs and unstructured (i.e., free text) logs. It also supports real-time log compression within several logging libraries. CLP also includes purpose-built web interfaces for searching and viewing the compressed logs. To learn more -about it, you can read our [paper][clp-paper]. +about it, read our [2021 paper][clp-paper-21] about handling unstructured logs and our +[2024 paper][clp-paper-24] on extending it to JSON logs. # Benchmarks @@ -27,7 +28,7 @@ index-less design, so for a fair comparison, we disabled MongoDB and PostgreSQL' left them enabled, MongoDB and PostgreSQL's compression ratio would be worse. We didn't disable indexing for Elasticsearch or Splunk since these tools are fundamentally index-based (i.e., logs cannot be searched without indexes). More details about our experimental methodology can be found in -the [CLP paper][clp-paper]. +the [2021 paper][clp-paper-21] and the [2024 paper][clp-paper-24]. # System Overview @@ -94,7 +95,8 @@ If you would like a feature or want to report a bug, please file an issue and we [clp-ffi-go]: https://github.com/y-scope/clp-ffi-go [clp-ffi-py]: https://github.com/y-scope/clp-ffi-py [clp-loglib-py]: https://github.com/y-scope/clp-loglib-py -[clp-paper]: https://www.usenix.org/system/files/osdi21-rodrigues.pdf +[clp-paper-21]: https://www.usenix.org/system/files/osdi21-rodrigues.pdf +[clp-paper-24]: https://www.usenix.org/system/files/osdi24-wang-rui.pdf [core]: http://docs.yscope.com/clp/main/dev-guide/components-core [core-container]: http://docs.yscope.com/clp/main/user-guide/core-container [datasets]: https://docs.yscope.com/clp/main/user-guide/resources-datasets From 3ceb17ee51cc91026f156ce5b1905f84ef18d7a9 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:05:13 -0400 Subject: [PATCH 071/114] Linting: Upgrade to latest version of yscope-dev-utils and add C++ lint configs from yscope-dev-utils. (#537) --- components/core/.clang-format | 151 +--------------------------- lint-tasks.yml | 8 +- tools/scripts/deps-download/init.sh | 4 +- tools/yscope-dev-utils | 2 +- 4 files changed, 12 insertions(+), 153 deletions(-) diff --git a/components/core/.clang-format b/components/core/.clang-format index c282164b8..ff65adbae 100644 --- a/components/core/.clang-format +++ b/components/core/.clang-format @@ -1,75 +1,5 @@ -# yamllint disable-line rule:document-start ---- -ColumnLimit: 100 -IndentWidth: 4 -# yamllint disable-line rule:document-start ---- -Language: "Cpp" -AccessModifierOffset: -4 -AlignAfterOpenBracket: "BlockIndent" -AlignArrayOfStructures: "None" -AlignConsecutiveAssignments: "None" -AlignConsecutiveBitFields: "None" -AlignConsecutiveDeclarations: "None" -AlignConsecutiveMacros: "None" -AlignEscapedNewlines: "DontAlign" -AlignOperands: "Align" -AlignTrailingComments: - Kind: "Never" -AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowBreakBeforeNoexceptSpecifier: "OnlyWithParen" -AllowShortBlocksOnASingleLine: "Always" -AllowShortCaseLabelsOnASingleLine: false -AllowShortCompoundRequirementOnASingleLine: true -AllowShortEnumsOnASingleLine: false -AllowShortFunctionsOnASingleLine: "Inline" -AllowShortIfStatementsOnASingleLine: "Never" -AllowShortLambdasOnASingleLine: "All" -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterReturnType: "None" -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: "Yes" -BinPackArguments: false -BinPackParameters: false -BitFieldColonSpacing: "Both" -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: "MultiLine" - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterExternBlock: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyNamespace: false - SplitEmptyRecord: false -BreakAfterAttributes: "Never" -BreakBeforeBinaryOperators: "All" -BreakBeforeBraces: "Custom" -BreakBeforeConceptDeclarations: "Always" -BreakBeforeInlineASMColon: "OnlyMultiline" -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: "BeforeColon" -BreakInheritanceList: "BeforeColon" -BreakStringLiterals: true -CompactNamespaces: true -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -EmptyLineAfterAccessModifier: "Never" -EmptyLineBeforeAccessModifier: "LogicalBlock" -FixNamespaceComments: true -IncludeBlocks: "Regroup" +BasedOnStyle: "InheritParentConfig" + IncludeCategories: # NOTE: A header is grouped by first matching regex # Library headers. Update when adding new libraries. @@ -86,80 +16,3 @@ IncludeCategories: # Project headers - Regex: "^\".+\"" Priority: 4 -IndentAccessModifiers: false -IndentCaseBlocks: false -IndentCaseLabels: true -IndentExternBlock: "Indent" -IndentGotoLabels: false -IndentPPDirectives: "BeforeHash" -IndentRequiresClause: false -IndentWrappedFunctionNames: false -InsertBraces: true -InsertNewlineAtEOF: true -IntegerLiteralSeparator: - Binary: 4 - BinaryMinDigits: 4 - Decimal: 3 - DecimalMinDigits: 5 - Hex: 4 - HexMinDigits: 4 -KeepEmptyLinesAtTheStartOfBlocks: false -LambdaBodyIndentation: "Signature" -LineEnding: "LF" -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: "None" -PPIndentWidth: -1 -PackConstructorInitializers: "CurrentLine" -PenaltyBreakOpenParenthesis: 25 -PenaltyBreakBeforeFirstCallParameter: 25 -PenaltyReturnTypeOnItsOwnLine: 100 -PointerAlignment: "Left" -QualifierAlignment: "Custom" -QualifierOrder: - - "static" - - "friend" - - "inline" - # constexpr west as explained in https://www.youtube.com/watch?v=z6s6bacI424 - - "constexpr" - - "type" - - "const" - - "volatile" -ReferenceAlignment: "Pointer" -ReflowComments: true -RemoveBracesLLVM: false -RemoveSemicolon: true -RequiresClausePosition: "OwnLine" -RequiresExpressionIndentation: "OuterScope" -SeparateDefinitionBlocks: "Always" -ShortNamespaceLines: 0 -SortIncludes: "CaseInsensitive" -SortUsingDeclarations: "Lexicographic" -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceAroundPointerQualifiers: "Default" -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: "ControlStatements" -SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeSquareBrackets: false -SpaceInEmptyBlock: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInContainerLiterals: false -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParens: "Custom" -SpacesInParensOptions: - InConditionalStatements: false - InCStyleCasts: false - InEmptyParentheses: false - Other: false -SpacesInSquareBrackets: false -Standard: "Latest" -TabWidth: 4 -UseTab: "Never" diff --git a/lint-tasks.yml b/lint-tasks.yml index a3c86cc80..d1da57771 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -21,6 +21,8 @@ tasks: cpp-check: sources: &cpp_source_files + - "{{.ROOT_DIR}}/.clang-format" + - "{{.ROOT_DIR}}/.clang-tidy" - "{{.TASKFILE}}" - ".clang-format" - "src/**/*.cpp" @@ -119,7 +121,7 @@ tasks: requires: vars: ["FLAGS"] dir: "components/core" - deps: ["venv"] + deps: ["cpp-lint-configs", "venv"] cmds: - |- . "{{.G_LINT_VENV_DIR}}/bin/activate" @@ -129,6 +131,10 @@ tasks: -print0 | \ xargs -0 clang-format {{.FLAGS}} -Werror + cpp-lint-configs: + internal: true + cmd: "{{.ROOT_DIR}}/tools/yscope-dev-utils/lint-configs/symlink-cpp-lint-configs.sh" + js: internal: true requires: diff --git a/tools/scripts/deps-download/init.sh b/tools/scripts/deps-download/init.sh index 57fcd4594..fa626cc82 100755 --- a/tools/scripts/deps-download/init.sh +++ b/tools/scripts/deps-download/init.sh @@ -11,7 +11,7 @@ project_root_dir="$script_dir/../../../" download_dep_script="$script_dir/download-dep.py" python3 "${download_dep_script}" \ - https://github.com/y-scope/yscope-dev-utils/archive/ff1611e6.zip \ - yscope-dev-utils-ff1611e6f9b116da27dc7f8f71797829c22d0b1a \ + https://github.com/y-scope/yscope-dev-utils/archive/2caa3dcf.zip \ + yscope-dev-utils-2caa3dcfbbccff052d179e643a509d8ad05bc217 \ "${project_root_dir}/tools/yscope-dev-utils" \ --extract diff --git a/tools/yscope-dev-utils b/tools/yscope-dev-utils index ff1611e6f..2caa3dcfb 160000 --- a/tools/yscope-dev-utils +++ b/tools/yscope-dev-utils @@ -1 +1 @@ -Subproject commit ff1611e6f9b116da27dc7f8f71797829c22d0b1a +Subproject commit 2caa3dcfbbccff052d179e643a509d8ad05bc217 From 695a1f8016ac19a1c18a9ea814d255106ecaf59f Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:20:06 -0400 Subject: [PATCH 072/114] Temporarily lock clang-format to v18.x to resolve lint failures. (#546) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- lint-requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lint-requirements.txt b/lint-requirements.txt index 0c58ad2af..4b3bbe927 100644 --- a/lint-requirements.txt +++ b/lint-requirements.txt @@ -1,4 +1,5 @@ black>=24.4.2 -clang-format>=18.1.5 +# Lock to v18.x until we can upgrade our code to meet v19's formatting standards. +clang-format~=18.1 ruff>=0.4.4 yamllint>=1.35.1 From 7b921f156ce760989f9870385d5205531e488e3a Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 27 Sep 2024 22:41:56 -0400 Subject: [PATCH 073/114] ffi: Add `IrUnitHandlerInterface` to perform user-defined handling for deserialized IR units. (#540) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: davidlion --- components/core/CMakeLists.txt | 2 + .../ffi/ir_stream/IrUnitHandlerInterface.hpp | 62 ++++++++ .../tests/test-ffi_IrUnitHandlerInterface.cpp | 140 ++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp create mode 100644 components/core/tests/test-ffi_IrUnitHandlerInterface.cpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index a7c6d5a90..66901ae6c 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -333,6 +333,7 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/decoding_methods.inc src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp + src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp src/clp/ffi/ir_stream/protocol_constants.hpp src/clp/ffi/ir_stream/Serializer.cpp src/clp/ffi/ir_stream/Serializer.hpp @@ -498,6 +499,7 @@ set(SOURCE_FILES_unitTest tests/test-BufferedFileReader.cpp tests/test-EncodedVariableInterpreter.cpp tests/test-encoding_methods.cpp + tests/test-ffi_IrUnitHandlerInterface.cpp tests/test-ffi_KeyValuePairLogEvent.cpp tests/test-ffi_SchemaTree.cpp tests/test-FileDescriptorReader.cpp diff --git a/components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp b/components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp new file mode 100644 index 000000000..cb2f0ac18 --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp @@ -0,0 +1,62 @@ +#ifndef CLP_FFI_IR_STREAM_IRUNITHANDLERINTERFACE_HPP +#define CLP_FFI_IR_STREAM_IRUNITHANDLERINTERFACE_HPP + +#include +#include + +#include "../../time_types.hpp" +#include "../KeyValuePairLogEvent.hpp" +#include "../SchemaTree.hpp" +#include "decoding_methods.hpp" + +namespace clp::ffi::ir_stream { +/** + * Concept that defines the IR unit handler interface. + */ +template +concept IrUnitHandlerInterface = requires( + Handler handler, + KeyValuePairLogEvent&& log_event, + UtcOffset utc_offset_old, + UtcOffset utc_offset_new, + SchemaTree::NodeLocator schema_tree_node_locator +) { + /** + * Handles a log event IR unit. + * @param log_event The deserialized result from IR deserializer. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_log_event(std::forward(log_event)) + } -> std::same_as; + + /** + * Handles a UTC offset change IR unit. + * @param utc_offset_old The offset before the change. + * @param utc_offset_new The deserialized new offset. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_utc_offset_change(utc_offset_old, utc_offset_new) + } -> std::same_as; + + /** + * Handles a schema tree node insertion IR unit. + * @param schema_tree_node_locator The locator of the node to insert. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_schema_tree_node_insertion(schema_tree_node_locator) + } -> std::same_as; + + /** + * Handles an end-of-stream indicator IR unit. + * @return IRErrorCode::Success on success, user-defined error code on failures. + */ + { + handler.handle_end_of_stream() + } -> std::same_as; +}; +} // namespace clp::ffi::ir_stream + +#endif // CLP_FFI_IR_STREAM_IRUNITHANDLERINTERFACE_HPP diff --git a/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp b/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp new file mode 100644 index 000000000..976cb259a --- /dev/null +++ b/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include + +#include + +#include "../src/clp/ffi/ir_stream/decoding_methods.hpp" +#include "../src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp" +#include "../src/clp/ffi/KeyValuePairLogEvent.hpp" +#include "../src/clp/ffi/SchemaTree.hpp" +#include "../src/clp/ffi/SchemaTreeNode.hpp" +#include "../src/clp/time_types.hpp" + +namespace { +using clp::ffi::ir_stream::IRErrorCode; +using clp::ffi::KeyValuePairLogEvent; +using clp::ffi::SchemaTree; +using clp::ffi::SchemaTreeNode; +using clp::UtcOffset; + +constexpr UtcOffset cTestUtcOffset{100}; +constexpr UtcOffset cTestUtcOffsetDelta{1000}; +constexpr std::string_view cTestSchemaTreeNodeKeyName{"test_key"}; + +/** + * Class that implements `clp::ffi::ir_stream::IrUnitHandlerInterface` for testing purposes. + */ +class TrivialIrUnitHandler { +public: + // Implements `clp::ffi::ir_stream::IrUnitHandlerInterface` interface + [[nodiscard]] auto handle_log_event(KeyValuePairLogEvent&& log_event) -> IRErrorCode { + m_log_event.emplace(std::move(log_event)); + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto + handle_utc_offset_change(UtcOffset utc_offset_old, UtcOffset utc_offset_new) -> IRErrorCode { + m_utc_offset_delta = utc_offset_new - utc_offset_old; + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto handle_schema_tree_node_insertion( + SchemaTree::NodeLocator schema_tree_node_locator + ) -> IRErrorCode { + m_schema_tree_node_locator.emplace(schema_tree_node_locator); + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto handle_end_of_stream() -> IRErrorCode { + m_is_complete = true; + return IRErrorCode::IRErrorCode_Success; + } + + // Methods + [[nodiscard]] auto get_utc_offset_delta() const -> UtcOffset { return m_utc_offset_delta; } + + [[nodiscard]] auto is_complete() const -> bool { return m_is_complete; } + + [[nodiscard]] auto get_schema_tree_node_locator( + ) const -> std::optional const& { + return m_schema_tree_node_locator; + } + + [[nodiscard]] auto get_log_event() const -> std::optional const& { + return m_log_event; + } + +private: + UtcOffset m_utc_offset_delta{0}; + bool m_is_complete{false}; + std::optional m_schema_tree_node_locator; + std::optional m_log_event; +}; + +/** + * Class that inherits `TrivialIrUnitHandler` which also implements + * `clp::ffi::ir_stream::IrUnitHandlerInterface`. + */ +class TriviallyInheritedIrUnitHandler : public TrivialIrUnitHandler {}; + +/** + * Simulates the use of an IR unit handler. It calls every method required by + * `clp::ffi::ir_stream::IrUnitHandlerInterface` and ensure they don't return errors. + * @param handler + */ +auto test_ir_unit_handler_interface(clp::ffi::ir_stream::IrUnitHandlerInterface auto& handler +) -> void; + +auto test_ir_unit_handler_interface(clp::ffi::ir_stream::IrUnitHandlerInterface auto& handler +) -> void { + auto test_log_event_result{ + KeyValuePairLogEvent::create(std::make_shared(), {}, cTestUtcOffset) + }; + REQUIRE( + (false == test_log_event_result.has_error() + && IRErrorCode::IRErrorCode_Success + == handler.handle_log_event(std::move(test_log_event_result.value()))) + ); + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == handler.handle_utc_offset_change( + cTestUtcOffset, + cTestUtcOffset + cTestUtcOffsetDelta + )) + ); + REQUIRE( + (IRErrorCode::IRErrorCode_Success + == handler.handle_schema_tree_node_insertion( + {SchemaTree::cRootId, cTestSchemaTreeNodeKeyName, SchemaTreeNode::Type::Obj} + )) + ); + REQUIRE((IRErrorCode::IRErrorCode_Success == handler.handle_end_of_stream())); +} +} // namespace + +TEMPLATE_TEST_CASE( + "test_ir_unit_handler_interface_basic", + "[ffi][ir_stream]", + TrivialIrUnitHandler, + TriviallyInheritedIrUnitHandler +) { + TestType handler; + REQUIRE_FALSE(handler.is_complete()); + test_ir_unit_handler_interface(handler); + + REQUIRE((handler.get_utc_offset_delta() == cTestUtcOffsetDelta)); + auto const& optional_log_event{handler.get_log_event()}; + REQUIRE( + (optional_log_event.has_value() + && optional_log_event.value().get_utc_offset() == cTestUtcOffset + && optional_log_event.value().get_node_id_value_pairs().empty()) + ); + auto const& optional_schema_tree_locator{handler.get_schema_tree_node_locator()}; + REQUIRE( + (optional_schema_tree_locator.has_value() + && optional_schema_tree_locator.value().get_key_name() == cTestSchemaTreeNodeKeyName) + ); + REQUIRE(handler.is_complete()); +} From 54962a0708daa443c9bdfb3462ed464b65b62886 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:46:01 -0400 Subject: [PATCH 074/114] ffi: Extract IR unit deserialization methods from `Deserializer` into standalone functions to prepare for a templatized `Deserializer`. (#544) --- components/core/CMakeLists.txt | 2 + .../src/clp/ffi/ir_stream/Deserializer.cpp | 620 +----------------- .../src/clp/ffi/ir_stream/Deserializer.hpp | 6 +- .../ir_unit_deserialization_methods.cpp | 537 +++++++++++++++ .../ir_unit_deserialization_methods.hpp | 68 ++ .../core/src/clp/ffi/ir_stream/utils.cpp | 16 + .../core/src/clp/ffi/ir_stream/utils.hpp | 8 + .../core/tests/test-ir_encoding_methods.cpp | 5 + 8 files changed, 671 insertions(+), 591 deletions(-) create mode 100644 components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp create mode 100644 components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 66901ae6c..67eb80040 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -334,6 +334,8 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp + src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp + src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp src/clp/ffi/ir_stream/protocol_constants.hpp src/clp/ffi/ir_stream/Serializer.cpp src/clp/ffi/ir_stream/Serializer.hpp diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp index 453d58bcf..11034c4a6 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp @@ -1,8 +1,6 @@ #include "Deserializer.hpp" -#include #include -#include #include #include #include @@ -14,27 +12,16 @@ #include #include -#include "../../ErrorCode.hpp" -#include "../../ir/EncodedTextAst.hpp" -#include "../../ir/types.hpp" #include "../../ReaderInterface.hpp" #include "../../time_types.hpp" -#include "../../type_utils.hpp" #include "../KeyValuePairLogEvent.hpp" -#include "../SchemaTree.hpp" -#include "../SchemaTreeNode.hpp" -#include "../Value.hpp" #include "decoding_methods.hpp" +#include "ir_unit_deserialization_methods.hpp" #include "protocol_constants.hpp" #include "utils.hpp" namespace clp::ffi::ir_stream { namespace { -/** - * A collection of schema tree leaf node IDs. It represents the schema of a `KeyValuePairLogEvent`. - */ -using Schema = std::vector; - /** * Class to perform different actions depending on whether a transaction succeeds or fails. The * default state assumes the transaction fails. @@ -78,551 +65,15 @@ class TransactionManager { bool m_success{false}; }; -/** - * @param ir_error_code - * @return Equivalent `std::errc` code indicating the same error type. - */ -[[nodiscard]] auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc; - /** * @param tag * @return Whether the tag represents a schema tree node. */ [[nodiscard]] auto is_schema_tree_node_tag(encoded_tag_t tag) -> bool; -/** - * @param tag - * @return The corresponding schema tree node type on success. - * @return std::nullopt if the tag doesn't match to any defined schema tree node type. - */ -[[nodiscard]] auto schema_tree_node_tag_to_type(encoded_tag_t tag -) -> std::optional; - -/** - * Deserializes the parent ID of a schema tree node. - * @param reader - * @param parent_id Returns the deserialized result. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if the next packet in the stream isn't a parent ID. - * @return Same as `deserialize_tag` on any other failure. - */ -[[nodiscard]] auto deserialize_schema_tree_node_parent_id( - ReaderInterface& reader, - SchemaTreeNode::id_t& parent_id -) -> IRErrorCode; - -/** - * Deserializes the key name of a schema tree node. - * @param reader - * @param key_name Returns the deserialized key name. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return Same as `deserialize_tag` or `deserialize_string` on failure. - */ -[[nodiscard]] auto deserialize_schema_tree_node_key_name( - ReaderInterface& reader, - std::string& key_name -) -> IRErrorCode; - -/** - * Deserializes an integer value packet. - * @param reader - * @param tag - * @param val Returns the deserialized value. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if the given tag doesn't correspond to an integer - * packet. - */ -[[nodiscard]] auto -deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val) -> IRErrorCode; - -/** - * Deserializes a string packet. - * @param reader - * @param tag - * @param deserialized_str Returns the deserialized string. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if the given tag doesn't correspond to a string - * packet. - */ -[[nodiscard]] auto deserialize_string( - ReaderInterface& reader, - encoded_tag_t tag, - std::string& deserialized_str -) -> IRErrorCode; - -/** - * Deserializes all UTC offset packets until a non-UTC offset packet tag is read. - * @param reader - * @param tag Takes the current tag as input and returns the last tag read. - * @param utc_offset Returns the deserialized UTC offset. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return Same as `deserialize_utc_offset_change` or `deserialize_tag` on failure. - */ -[[nodiscard]] auto deserialize_utc_offset_changes( - ReaderInterface& reader, - encoded_tag_t& tag, - UtcOffset& utc_offset -) -> IRErrorCode; - -/** - * Deserializes all schema tree node packets and inserts them into the schema tree until a non- - * schema tree node tag is read. - * @param reader - * @param tag Takes the current tag as input and returns the last tag read. - * @param schema_tree Returns the schema tree with all new nodes inserted. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if the packet tag doesn't correspond to any known - * schema node type or the node being deserialized already exists in the current in-memory schema - * tree. - * @return Same as `deserialize_schema_tree_node_parent_id`, `deserialize_string`, or - * `deserialize_tag` on any other failure. - */ -[[nodiscard]] auto deserialize_schema_tree_nodes( - ReaderInterface& reader, - encoded_tag_t& tag, - SchemaTree& schema_tree -) -> IRErrorCode; - -/** - * Deserializes the IDs of all keys in a log event. - * @param reader - * @param tag Takes the current tag as input and returns the last tag read. - * @param schema Returns the deserialized schema. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return Same as `deserialize_tag` on any other failure. - */ -[[nodiscard]] auto -deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) -> IRErrorCode; - -/** - * Deserializes the next value and pushes the result into `node_id_value_pairs`. - * @param reader - * @param tag - * @param node_id The node ID that corresponds to the value. - * @param node_id_value_pairs Returns the ID-value pair constructed from the deserialized value. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if the tag doesn't correspond to any known value - * type. - * @return Same as `deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs` on any other - * failure. - */ -[[nodiscard]] auto deserialize_value_and_insert_to_node_id_value_pairs( - ReaderInterface& reader, - encoded_tag_t tag, - SchemaTreeNode::id_t node_id, - KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs -) -> IRErrorCode; - -/** - * Deserializes an encoded text AST and pushes the result into node_id_value_pairs. - * @tparam encoded_variable_t - * @param reader - * @param node_id The node ID that corresponds to the value. - * @param node_id_value_pairs Returns the ID-value pair constructed by the deserialized encoded text - * AST. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return Same as `deserialize_tag` or `deserialize_encoded_text_ast` on failure. - */ -template -requires(std::is_same_v - || std::is_same_v) -[[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( - ReaderInterface& reader, - SchemaTreeNode::id_t node_id, - KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs -) -> IRErrorCode; - -/** - * Deserializes values and constructs ID-value pairs according to the given schema. The number of - * values to deserialize is indicated by the size of the given schema. - * @param reader - * @param tag - * @param schema The log event's schema. - * @param node_id_value_pairs Returns the constructed ID-value pairs. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if a key is duplicated in the deserialized log - * event. - * @return Same as `deserialize_tag` or `deserialize_value_and_insert_to_node_id_value_pairs` on any - * other failure. - */ -[[nodiscard]] auto deserialize_value_and_construct_node_id_value_pairs( - ReaderInterface& reader, - encoded_tag_t tag, - Schema const& schema, - KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs -) -> IRErrorCode; - -auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc { - switch (ir_error_code) { - case IRErrorCode_Incomplete_IR: - return std::errc::result_out_of_range; - case IRErrorCode_Corrupted_IR: - case IRErrorCode_Decode_Error: - return std::errc::protocol_error; - case IRErrorCode_Eof: - return std::errc::no_message_available; - default: - return std::errc::not_supported; - } -} - auto is_schema_tree_node_tag(encoded_tag_t tag) -> bool { return (tag & cProtocol::Payload::SchemaTreeNodeMask) == cProtocol::Payload::SchemaTreeNodeMask; } - -auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { - switch (tag) { - case cProtocol::Payload::SchemaTreeNodeInt: - return SchemaTreeNode::Type::Int; - case cProtocol::Payload::SchemaTreeNodeFloat: - return SchemaTreeNode::Type::Float; - case cProtocol::Payload::SchemaTreeNodeBool: - return SchemaTreeNode::Type::Bool; - case cProtocol::Payload::SchemaTreeNodeStr: - return SchemaTreeNode::Type::Str; - case cProtocol::Payload::SchemaTreeNodeUnstructuredArray: - return SchemaTreeNode::Type::UnstructuredArray; - case cProtocol::Payload::SchemaTreeNodeObj: - return SchemaTreeNode::Type::Obj; - default: - return std::nullopt; - } -} - -auto deserialize_schema_tree_node_parent_id( - ReaderInterface& reader, - SchemaTreeNode::id_t& parent_id -) -> IRErrorCode { - encoded_tag_t tag{}; - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; - } - if (cProtocol::Payload::SchemaTreeNodeParentIdUByte == tag) { - uint8_t deserialized_id{}; - if (false == deserialize_int(reader, deserialized_id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - parent_id = static_cast(deserialized_id); - } else if (cProtocol::Payload::SchemaTreeNodeParentIdUShort == tag) { - uint16_t deserialized_id{}; - if (false == deserialize_int(reader, deserialized_id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - parent_id = static_cast(deserialized_id); - } else { - return IRErrorCode::IRErrorCode_Corrupted_IR; - } - return IRErrorCode_Success; -} - -auto deserialize_schema_tree_node_key_name(ReaderInterface& reader, std::string& key_name) - -> IRErrorCode { - encoded_tag_t str_packet_tag{}; - if (auto const err{deserialize_tag(reader, str_packet_tag)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - if (auto const err{deserialize_string(reader, str_packet_tag, key_name)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val) - -> IRErrorCode { - if (cProtocol::Payload::ValueInt8 == tag) { - int8_t deserialized_val{}; - if (false == deserialize_int(reader, deserialized_val)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - // NOLINTNEXTLINE(bugprone-signed-char-misuse,cert-str34-c) - val = deserialized_val; - } else if (cProtocol::Payload::ValueInt16 == tag) { - int16_t deserialized_val{}; - if (false == deserialize_int(reader, deserialized_val)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - val = deserialized_val; - } else if (cProtocol::Payload::ValueInt32 == tag) { - int32_t deserialized_val{}; - if (false == deserialize_int(reader, deserialized_val)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - val = deserialized_val; - } else if (cProtocol::Payload::ValueInt64 == tag) { - int64_t deserialized_val{}; - if (false == deserialize_int(reader, deserialized_val)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - val = deserialized_val; - } else { - return IRErrorCode::IRErrorCode_Corrupted_IR; - } - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_string(ReaderInterface& reader, encoded_tag_t tag, std::string& deserialized_str) - -> IRErrorCode { - size_t str_length{}; - if (cProtocol::Payload::StrLenUByte == tag) { - uint8_t length{}; - if (false == deserialize_int(reader, length)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - str_length = static_cast(length); - } else if (cProtocol::Payload::StrLenUShort == tag) { - uint16_t length{}; - if (false == deserialize_int(reader, length)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - str_length = static_cast(length); - } else if (cProtocol::Payload::StrLenUInt == tag) { - uint32_t length{}; - if (false == deserialize_int(reader, length)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - str_length = static_cast(length); - } else { - return IRErrorCode::IRErrorCode_Corrupted_IR; - } - if (clp::ErrorCode_Success != reader.try_read_string(str_length, deserialized_str)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_utc_offset_changes( - ReaderInterface& reader, - encoded_tag_t& tag, - UtcOffset& utc_offset -) -> IRErrorCode { - while (cProtocol::Payload::UtcOffsetChange == tag) { - if (auto const err{deserialize_utc_offset_change(reader, utc_offset)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; - } - } - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_schema_tree_nodes( - ReaderInterface& reader, - encoded_tag_t& tag, - SchemaTree& schema_tree -) -> IRErrorCode { - while (is_schema_tree_node_tag(tag)) { - auto const type{schema_tree_node_tag_to_type(tag)}; - if (false == type.has_value()) { - return IRErrorCode::IRErrorCode_Corrupted_IR; - } - - SchemaTreeNode::id_t parent_id{}; - if (auto const err{deserialize_schema_tree_node_parent_id(reader, parent_id)}; - IRErrorCode_Success != err) - { - return err; - } - - std::string key_name; - if (auto const err{deserialize_schema_tree_node_key_name(reader, key_name)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - - // Insert the node to the schema tree - SchemaTree::NodeLocator const locator{parent_id, key_name, type.value()}; - if (schema_tree.has_node(locator)) { - return IRErrorCode::IRErrorCode_Corrupted_IR; - } - std::ignore = schema_tree.insert_node(locator); - - // Read the next tag - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; - } - } - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) - -> IRErrorCode { - schema.clear(); - while (true) { - if (cProtocol::Payload::KeyIdUByte == tag) { - uint8_t id{}; - if (false == deserialize_int(reader, id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - schema.push_back(static_cast(id)); - } else if (cProtocol::Payload::KeyIdUShort == tag) { - uint16_t id{}; - if (false == deserialize_int(reader, id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - schema.push_back(static_cast(id)); - } else { - break; - } - - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; - } - } - - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_value_and_insert_to_node_id_value_pairs( - ReaderInterface& reader, - encoded_tag_t tag, - SchemaTreeNode::id_t node_id, - KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs -) -> IRErrorCode { - switch (tag) { - case cProtocol::Payload::ValueInt8: - case cProtocol::Payload::ValueInt16: - case cProtocol::Payload::ValueInt32: - case cProtocol::Payload::ValueInt64: { - value_int_t value_int{}; - if (auto const err{deserialize_int_val(reader, tag, value_int)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - node_id_value_pairs.emplace(node_id, Value{value_int}); - break; - } - case cProtocol::Payload::ValueFloat: { - uint64_t val{}; - if (false == deserialize_int(reader, val)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - node_id_value_pairs.emplace(node_id, Value{bit_cast(val)}); - break; - } - case cProtocol::Payload::ValueTrue: - node_id_value_pairs.emplace(node_id, Value{true}); - break; - case cProtocol::Payload::ValueFalse: - node_id_value_pairs.emplace(node_id, Value{false}); - break; - case cProtocol::Payload::StrLenUByte: - case cProtocol::Payload::StrLenUShort: - case cProtocol::Payload::StrLenUInt: { - std::string value_str; - if (auto const err{deserialize_string(reader, tag, value_str)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - node_id_value_pairs.emplace(node_id, Value{std::move(value_str)}); - break; - } - case cProtocol::Payload::ValueEightByteEncodingClpStr: - if (auto const err{deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs< - ir::eight_byte_encoded_variable_t>(reader, node_id, node_id_value_pairs)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - break; - case cProtocol::Payload::ValueFourByteEncodingClpStr: - if (auto const err{deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs< - ir::four_byte_encoded_variable_t>(reader, node_id, node_id_value_pairs)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - break; - case cProtocol::Payload::ValueNull: - node_id_value_pairs.emplace(node_id, Value{}); - break; - case cProtocol::Payload::ValueEmpty: - node_id_value_pairs.emplace(node_id, std::nullopt); - break; - default: - return IRErrorCode::IRErrorCode_Corrupted_IR; - } - return IRErrorCode::IRErrorCode_Success; -} - -template -requires(std::is_same_v - || std::is_same_v) -[[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( - ReaderInterface& reader, - SchemaTreeNode::id_t node_id, - KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs -) -> IRErrorCode { - encoded_tag_t tag{}; - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; - } - - std::string logtype; - std::vector encoded_vars; - std::vector dict_vars; - if (auto const err{deserialize_encoded_text_ast(reader, tag, logtype, encoded_vars, dict_vars)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - - node_id_value_pairs.emplace( - node_id, - Value{ir::EncodedTextAst{logtype, dict_vars, encoded_vars}} - ); - return IRErrorCode::IRErrorCode_Success; -} - -auto deserialize_value_and_construct_node_id_value_pairs( - ReaderInterface& reader, - encoded_tag_t tag, - Schema const& schema, - KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs -) -> IRErrorCode { - node_id_value_pairs.clear(); - node_id_value_pairs.reserve(schema.size()); - for (auto const node_id : schema) { - if (node_id_value_pairs.contains(node_id)) { - // The key should be unique in a schema - return IRErrorCode_Corrupted_IR; - } - - if (auto const err{deserialize_value_and_insert_to_node_id_value_pairs( - reader, - tag, - node_id, - node_id_value_pairs - )}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - - if (schema.size() != node_id_value_pairs.size()) { - if (auto const err{deserialize_tag(reader, tag)}; - IRErrorCode::IRErrorCode_Success != err) - { - return err; - } - } - } - return IRErrorCode::IRErrorCode_Success; -} } // namespace auto Deserializer::create(ReaderInterface& reader @@ -679,56 +130,49 @@ auto Deserializer::deserialize_to_next_log_event(clp::ReaderInterface& reader }; encoded_tag_t tag{}; - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return ir_error_code_to_errc(err); - } - - if (auto const err{deserialize_utc_offset_changes(reader, tag, m_utc_offset)}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); - } - - if (auto const err{deserialize_schema_tree_nodes(reader, tag, *m_schema_tree)}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); - } + std::string schema_tree_node_key_name; + while (true) { + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return ir_error_code_to_errc(err); + } - Schema schema; - if (auto const err{deserialize_schema(reader, tag, schema)}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); - } + if (cProtocol::Eof == tag) { + return std::errc::no_message_available; + } - KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs; - if (false == schema.empty()) { - if (auto const err{deserialize_value_and_construct_node_id_value_pairs( + if (is_schema_tree_node_tag(tag)) { + auto const result{deserialize_ir_unit_schema_tree_node_insertion( reader, tag, - schema, - node_id_value_pairs + schema_tree_node_key_name )}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); + if (result.has_error()) { + return result.error(); + } + auto const& locator{result.value()}; + if (m_schema_tree->has_node(locator)) { + return std::errc::protocol_error; + } + std::ignore = m_schema_tree->insert_node(locator); + continue; } - } else { - if (cProtocol::Payload::ValueEmpty != tag) { - return ir_error_code_to_errc(IRErrorCode::IRErrorCode_Corrupted_IR); + + if (cProtocol::Payload::UtcOffsetChange == tag) { + auto const result{deserialize_ir_unit_utc_offset_change(reader)}; + if (result.has_error()) { + return result.error(); + } + m_utc_offset = result.value(); + continue; } + + break; } - auto result{KeyValuePairLogEvent::create( - m_schema_tree, - std::move(node_id_value_pairs), - m_utc_offset - )}; + auto result{deserialize_ir_unit_kv_pair_log_event(reader, tag, m_schema_tree, m_utc_offset)}; if (false == result.has_error()) { revert_manager.mark_success(); } - return std::move(result); } } // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp index 7ba7822da..0fb7e8c83 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp @@ -46,7 +46,7 @@ class Deserializer { // Methods /** - * Deserializes the stream from the given reader up to and including the next log event. + * Deserializes the stream from the given reader up to and including the next log event IR unit. * @param reader * @return A result containing the deserialized log event or an error code indicating the * failure: @@ -55,8 +55,8 @@ class Deserializer { * - std::errc::protocol_error if the IR stream is corrupted. * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format * or uses an unsupported version. - * - Same as `KeyValuePairLogEvent::create` if the intermediate deserialized result cannot - * construct a valid key-value pair log event. + * - Forwards `KeyValuePairLogEvent::create`'s return values if the intermediate deserialized + * result cannot construct a valid key-value pair log event. */ [[nodiscard]] auto deserialize_to_next_log_event(ReaderInterface& reader ) -> OUTCOME_V2_NAMESPACE::std_result; diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp new file mode 100644 index 000000000..cfbe235d5 --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp @@ -0,0 +1,537 @@ +#include "ir_unit_deserialization_methods.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../../ErrorCode.hpp" +#include "../../ir/EncodedTextAst.hpp" +#include "../../ir/types.hpp" +#include "../../ReaderInterface.hpp" +#include "../../time_types.hpp" +#include "../../type_utils.hpp" +#include "../KeyValuePairLogEvent.hpp" +#include "../SchemaTree.hpp" +#include "../SchemaTreeNode.hpp" +#include "../Value.hpp" +#include "decoding_methods.hpp" +#include "protocol_constants.hpp" +#include "utils.hpp" + +namespace clp::ffi::ir_stream { +namespace { +/** + * A collection of schema tree leaf node IDs. It represents the schema of a `KeyValuePairLogEvent`. + */ +using Schema = std::vector; + +/** + * @param tag + * @return The corresponding schema tree node type on success. + * @return std::nullopt if the tag doesn't match to any defined schema tree node type. + */ +[[nodiscard]] auto schema_tree_node_tag_to_type(encoded_tag_t tag +) -> std::optional; + +/** + * Deserializes the parent ID of a schema tree node. + * @param reader + * @param parent_id Returns the deserialized result. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the next packet in the stream isn't a parent ID. + * @return Forwards `deserialize_tag`'s return values on any other failure. + */ +[[nodiscard]] auto deserialize_schema_tree_node_parent_id( + ReaderInterface& reader, + SchemaTreeNode::id_t& parent_id +) -> IRErrorCode; + +/** + * Deserializes the key name of a schema tree node. + * @param reader + * @param key_name Returns the deserialized key name. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return Forwards `deserialize_tag`'s return values on failure. + * @return Forwards `deserialize_string`'s return values on failure. + */ +[[nodiscard]] auto deserialize_schema_tree_node_key_name( + ReaderInterface& reader, + std::string& key_name +) -> IRErrorCode; + +/** + * Deserializes an integer value packet. + * @param reader + * @param tag + * @param val Returns the deserialized value. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the given tag doesn't correspond to an integer + * packet. + */ +[[nodiscard]] auto +deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val) -> IRErrorCode; + +/** + * Deserializes a string packet. + * @param reader + * @param tag + * @param deserialized_str Returns the deserialized string. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the given tag doesn't correspond to a string + * packet. + */ +[[nodiscard]] auto deserialize_string( + ReaderInterface& reader, + encoded_tag_t tag, + std::string& deserialized_str +) -> IRErrorCode; + +/** + * Deserializes the IDs of all keys in a log event. + * @param reader + * @param tag Takes the current tag as input and returns the last tag read. + * @param schema Returns the deserialized schema. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return Forwards `deserialize_tag`'s return values on any other failure. + */ +[[nodiscard]] auto +deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) -> IRErrorCode; + +/** + * Deserializes the next value and pushes the result into `node_id_value_pairs`. + * @param reader + * @param tag + * @param node_id The node ID that corresponds to the value. + * @param node_id_value_pairs Returns the ID-value pair constructed from the deserialized value. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if the tag doesn't correspond to any known value + * type. + * @return Forwards `deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs`'s return + * values on any other failure. + */ +[[nodiscard]] auto deserialize_value_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode; + +/** + * Deserializes an encoded text AST and pushes the result into node_id_value_pairs. + * @tparam encoded_variable_t + * @param reader + * @param node_id The node ID that corresponds to the value. + * @param node_id_value_pairs Returns the ID-value pair constructed by the deserialized encoded text + * AST. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return Forwards `deserialize_tag`'s return values on failure. + * @return Forwards `deserialize_encoded_text_ast`'s return values on failure. + */ +template +requires(std::is_same_v + || std::is_same_v) +[[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode; + +/** + * Deserializes values and constructs ID-value pairs according to the given schema. The number of + * values to deserialize is indicated by the size of the given schema. + * @param reader + * @param tag + * @param schema The log event's schema. + * @param node_id_value_pairs Returns the constructed ID-value pairs. + * @return IRErrorCode::IRErrorCode_Success on success. + * @return IRErrorCode::IRErrorCode_Corrupted_IR if a key is duplicated in the deserialized log + * event. + * @return Forwards `deserialize_tag`'s return values on failure. + * @return Forwards `deserialize_value_and_insert_to_node_id_value_pairs`'s return values on + * failure. + */ +[[nodiscard]] auto deserialize_value_and_construct_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + Schema const& schema, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode; + +auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { + switch (tag) { + case cProtocol::Payload::SchemaTreeNodeInt: + return SchemaTreeNode::Type::Int; + case cProtocol::Payload::SchemaTreeNodeFloat: + return SchemaTreeNode::Type::Float; + case cProtocol::Payload::SchemaTreeNodeBool: + return SchemaTreeNode::Type::Bool; + case cProtocol::Payload::SchemaTreeNodeStr: + return SchemaTreeNode::Type::Str; + case cProtocol::Payload::SchemaTreeNodeUnstructuredArray: + return SchemaTreeNode::Type::UnstructuredArray; + case cProtocol::Payload::SchemaTreeNodeObj: + return SchemaTreeNode::Type::Obj; + default: + return std::nullopt; + } +} + +auto deserialize_schema_tree_node_parent_id( + ReaderInterface& reader, + SchemaTreeNode::id_t& parent_id +) -> IRErrorCode { + encoded_tag_t tag{}; + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + if (cProtocol::Payload::SchemaTreeNodeParentIdUByte == tag) { + uint8_t deserialized_id{}; + if (false == deserialize_int(reader, deserialized_id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + parent_id = static_cast(deserialized_id); + } else if (cProtocol::Payload::SchemaTreeNodeParentIdUShort == tag) { + uint16_t deserialized_id{}; + if (false == deserialize_int(reader, deserialized_id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + parent_id = static_cast(deserialized_id); + } else { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + return IRErrorCode_Success; +} + +auto deserialize_schema_tree_node_key_name(ReaderInterface& reader, std::string& key_name) + -> IRErrorCode { + encoded_tag_t str_packet_tag{}; + if (auto const err{deserialize_tag(reader, str_packet_tag)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + if (auto const err{deserialize_string(reader, str_packet_tag, key_name)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val) + -> IRErrorCode { + if (cProtocol::Payload::ValueInt8 == tag) { + int8_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else if (cProtocol::Payload::ValueInt16 == tag) { + int16_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else if (cProtocol::Payload::ValueInt32 == tag) { + int32_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else if (cProtocol::Payload::ValueInt64 == tag) { + int64_t deserialized_val{}; + if (false == deserialize_int(reader, deserialized_val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + val = deserialized_val; + } else { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_string(ReaderInterface& reader, encoded_tag_t tag, std::string& deserialized_str) + -> IRErrorCode { + size_t str_length{}; + if (cProtocol::Payload::StrLenUByte == tag) { + uint8_t length{}; + if (false == deserialize_int(reader, length)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + str_length = static_cast(length); + } else if (cProtocol::Payload::StrLenUShort == tag) { + uint16_t length{}; + if (false == deserialize_int(reader, length)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + str_length = static_cast(length); + } else if (cProtocol::Payload::StrLenUInt == tag) { + uint32_t length{}; + if (false == deserialize_int(reader, length)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + str_length = static_cast(length); + } else { + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + if (clp::ErrorCode_Success != reader.try_read_string(str_length, deserialized_str)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) + -> IRErrorCode { + schema.clear(); + while (true) { + if (cProtocol::Payload::KeyIdUByte == tag) { + uint8_t id{}; + if (false == deserialize_int(reader, id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + schema.push_back(static_cast(id)); + } else if (cProtocol::Payload::KeyIdUShort == tag) { + uint16_t id{}; + if (false == deserialize_int(reader, id)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + schema.push_back(static_cast(id)); + } else { + break; + } + + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + } + + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_value_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode { + switch (tag) { + case cProtocol::Payload::ValueInt8: + case cProtocol::Payload::ValueInt16: + case cProtocol::Payload::ValueInt32: + case cProtocol::Payload::ValueInt64: { + value_int_t value_int{}; + if (auto const err{deserialize_int_val(reader, tag, value_int)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + node_id_value_pairs.emplace(node_id, Value{value_int}); + break; + } + case cProtocol::Payload::ValueFloat: { + uint64_t val{}; + if (false == deserialize_int(reader, val)) { + return IRErrorCode::IRErrorCode_Incomplete_IR; + } + node_id_value_pairs.emplace(node_id, Value{bit_cast(val)}); + break; + } + case cProtocol::Payload::ValueTrue: + node_id_value_pairs.emplace(node_id, Value{true}); + break; + case cProtocol::Payload::ValueFalse: + node_id_value_pairs.emplace(node_id, Value{false}); + break; + case cProtocol::Payload::StrLenUByte: + case cProtocol::Payload::StrLenUShort: + case cProtocol::Payload::StrLenUInt: { + std::string value_str; + if (auto const err{deserialize_string(reader, tag, value_str)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + node_id_value_pairs.emplace(node_id, Value{std::move(value_str)}); + break; + } + case cProtocol::Payload::ValueEightByteEncodingClpStr: + if (auto const err{deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs< + ir::eight_byte_encoded_variable_t>(reader, node_id, node_id_value_pairs)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + break; + case cProtocol::Payload::ValueFourByteEncodingClpStr: + if (auto const err{deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs< + ir::four_byte_encoded_variable_t>(reader, node_id, node_id_value_pairs)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + break; + case cProtocol::Payload::ValueNull: + node_id_value_pairs.emplace(node_id, Value{}); + break; + case cProtocol::Payload::ValueEmpty: + node_id_value_pairs.emplace(node_id, std::nullopt); + break; + default: + return IRErrorCode::IRErrorCode_Corrupted_IR; + } + return IRErrorCode::IRErrorCode_Success; +} + +template +requires(std::is_same_v + || std::is_same_v) +[[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( + ReaderInterface& reader, + SchemaTreeNode::id_t node_id, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode { + encoded_tag_t tag{}; + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return err; + } + + std::string logtype; + std::vector encoded_vars; + std::vector dict_vars; + if (auto const err{deserialize_encoded_text_ast(reader, tag, logtype, encoded_vars, dict_vars)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + + node_id_value_pairs.emplace( + node_id, + Value{ir::EncodedTextAst{logtype, dict_vars, encoded_vars}} + ); + return IRErrorCode::IRErrorCode_Success; +} + +auto deserialize_value_and_construct_node_id_value_pairs( + ReaderInterface& reader, + encoded_tag_t tag, + Schema const& schema, + KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs +) -> IRErrorCode { + node_id_value_pairs.clear(); + node_id_value_pairs.reserve(schema.size()); + for (auto const node_id : schema) { + if (node_id_value_pairs.contains(node_id)) { + // The key should be unique in a schema + return IRErrorCode_Corrupted_IR; + } + + if (auto const err{deserialize_value_and_insert_to_node_id_value_pairs( + reader, + tag, + node_id, + node_id_value_pairs + )}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + + if (schema.size() != node_id_value_pairs.size()) { + if (auto const err{deserialize_tag(reader, tag)}; + IRErrorCode::IRErrorCode_Success != err) + { + return err; + } + } + } + return IRErrorCode::IRErrorCode_Success; +} +} // namespace + +auto deserialize_ir_unit_schema_tree_node_insertion( + ReaderInterface& reader, + encoded_tag_t tag, + std::string& key_name +) -> OUTCOME_V2_NAMESPACE::std_result { + auto const type{schema_tree_node_tag_to_type(tag)}; + if (false == type.has_value()) { + return ir_error_code_to_errc(IRErrorCode::IRErrorCode_Corrupted_IR); + } + + SchemaTreeNode::id_t parent_id{}; + if (auto const err{deserialize_schema_tree_node_parent_id(reader, parent_id)}; + IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + if (auto const err{deserialize_schema_tree_node_key_name(reader, key_name)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + return SchemaTree::NodeLocator{parent_id, key_name, type.value()}; +} + +auto deserialize_ir_unit_utc_offset_change(ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result { + UtcOffset utc_offset{0}; + if (auto const err{deserialize_utc_offset_change(reader, utc_offset)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + return utc_offset; +} + +auto deserialize_ir_unit_kv_pair_log_event( + ReaderInterface& reader, + encoded_tag_t tag, + std::shared_ptr schema_tree, + UtcOffset utc_offset +) -> OUTCOME_V2_NAMESPACE::std_result { + Schema schema; + if (auto const err{deserialize_schema(reader, tag, schema)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs; + if (false == schema.empty()) { + if (auto const err{deserialize_value_and_construct_node_id_value_pairs( + reader, + tag, + schema, + node_id_value_pairs + )}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + } else { + if (cProtocol::Payload::ValueEmpty != tag) { + return ir_error_code_to_errc(IRErrorCode::IRErrorCode_Corrupted_IR); + } + } + + return KeyValuePairLogEvent::create( + std::move(schema_tree), + std::move(node_id_value_pairs), + utc_offset + ); +} +} // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp new file mode 100644 index 000000000..0ba21866c --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp @@ -0,0 +1,68 @@ +#ifndef CLP_FFI_IR_STREAM_IR_UNIT_DESERIALIZATION_METHODS_HPP +#define CLP_FFI_IR_STREAM_IR_UNIT_DESERIALIZATION_METHODS_HPP + +#include +#include + +#include + +#include "../../ReaderInterface.hpp" +#include "../../time_types.hpp" +#include "../KeyValuePairLogEvent.hpp" +#include "../SchemaTree.hpp" +#include "decoding_methods.hpp" + +namespace clp::ffi::ir_stream { +/** + * Deserializes a schema tree node insertion IR unit. + * @param reader + * @param tag + * @param key_name Returns the key name of the deserialized new node. This should be the underlying + * storage of the returned schema tree node locator. + * @return A result containing the locator of the inserted schema tree node or an error code + * indicating the failure: + * - std::errc::result_out_of_range if the IR stream is truncated. + * - std::errc::protocol_error if the deserialized node type isn't supported. + * - Forwards `deserialize_schema_tree_node_key_name`'s return values. + * - Forwards `deserialize_schema_tree_node_parent_id`'s return values. + */ +[[nodiscard]] auto deserialize_ir_unit_schema_tree_node_insertion( + ReaderInterface& reader, + encoded_tag_t tag, + std::string& key_name +) -> OUTCOME_V2_NAMESPACE::std_result; + +/** + * Deserializes a UTC offset change IR unit. + * @param reader + * @return A result containing the new UTC offset or an error code indicating the failure: + * - std::errc::result_out_of_range if the IR stream is truncated. + * - Forwards `clp::ffi::ir_stream::deserialize_utc_offset_change`'s return values. + */ +[[nodiscard]] auto deserialize_ir_unit_utc_offset_change(ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result; + +/** + * Deserializes a key-value pair log event IR unit. + * @param reader + * @param tag + * @param schema_tree Schema tree used to construct the KV-pair log event. + * @param utc_offset UTC offset used to construct the KV-pair log event. + * @return A result containing the deserialized log event or an error code indicating the + * failure: + * - std::errc::result_out_of_range if the IR stream is truncated. + * - std::errc::protocol_error if the IR stream is corrupted. + * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format + * or uses an unsupported version. + * - Forwards `KeyValuePairLogEvent::create`'s return values if the intermediate deserialized result + * cannot construct a valid key-value pair log event. + */ +[[nodiscard]] auto deserialize_ir_unit_kv_pair_log_event( + ReaderInterface& reader, + encoded_tag_t tag, + std::shared_ptr schema_tree, + UtcOffset utc_offset +) -> OUTCOME_V2_NAMESPACE::std_result; +} // namespace clp::ffi::ir_stream + +#endif // CLP_FFI_IR_STREAM_IR_UNIT_DESERIALIZATION_METHODS_HPP diff --git a/components/core/src/clp/ffi/ir_stream/utils.cpp b/components/core/src/clp/ffi/ir_stream/utils.cpp index 66277720c..cfbc9d5a9 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.cpp +++ b/components/core/src/clp/ffi/ir_stream/utils.cpp @@ -2,11 +2,13 @@ #include #include +#include #include #include #include "../../type_utils.hpp" +#include "decoding_methods.hpp" #include "protocol_constants.hpp" namespace clp::ffi::ir_stream { @@ -49,4 +51,18 @@ auto serialize_string(std::string_view str, std::vector& output_buf) -> output_buf.insert(output_buf.cend(), str.cbegin(), str.cend()); return true; } + +auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc { + switch (ir_error_code) { + case IRErrorCode_Incomplete_IR: + return std::errc::result_out_of_range; + case IRErrorCode_Corrupted_IR: + case IRErrorCode_Decode_Error: + return std::errc::protocol_error; + case IRErrorCode_Eof: + return std::errc::no_message_available; + default: + return std::errc::not_supported; + } +} } // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/utils.hpp b/components/core/src/clp/ffi/ir_stream/utils.hpp index b816c6385..4e68ca67a 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.hpp +++ b/components/core/src/clp/ffi/ir_stream/utils.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -13,6 +14,7 @@ #include "../../ir/types.hpp" #include "../../ReaderInterface.hpp" #include "byteswap.hpp" +#include "decoding_methods.hpp" #include "encoding_methods.hpp" #include "protocol_constants.hpp" @@ -68,6 +70,12 @@ template */ [[nodiscard]] auto serialize_string(std::string_view str, std::vector& output_buf) -> bool; +/** + * @param ir_error_code + * @return Equivalent `std::errc` code indicating the same error type. + */ +[[nodiscard]] auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc; + template auto serialize_int(integer_t value, std::vector& output_buf) -> void { integer_t value_big_endian{}; diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index af8314369..ba8c59280 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -1123,6 +1123,7 @@ TEMPLATE_TEST_CASE( } flush_and_clear_serializer_buffer(serializer, ir_buf); + ir_buf.push_back(clp::ffi::ir_stream::cProtocol::Eof); // Deserialize the results BufferReader reader{size_checked_pointer_cast(ir_buf.data()), ir_buf.size()}; @@ -1143,4 +1144,8 @@ TEMPLATE_TEST_CASE( REQUIRE_FALSE(serialized_json_result.has_error()); REQUIRE((json_obj == serialized_json_result.value())); } + + auto const eof_result{deserializer.deserialize_to_next_log_event(reader)}; + REQUIRE(eof_result.has_error()); + REQUIRE((std::errc::no_message_available == eof_result.error())); } From 9202761a315232692ea653076faa577b066971e4 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:46:29 -0400 Subject: [PATCH 075/114] gh-actions: Remove pre-installed Go binaries that conflict with brew's installs on macOS (fixes #551). (#552) --- .github/workflows/clp-core-build-macos.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/clp-core-build-macos.yaml b/.github/workflows/clp-core-build-macos.yaml index 2398b14a2..dfcc46d31 100644 --- a/.github/workflows/clp-core-build-macos.yaml +++ b/.github/workflows/clp-core-build-macos.yaml @@ -49,6 +49,7 @@ jobs: - name: "Remove preinstalled binaries which conflict with brew's installs" run: | rm -f /usr/local/bin/2to3* + rm -f /usr/local/bin/go* rm -f /usr/local/bin/idle3* rm -f /usr/local/bin/pydoc3* rm -f /usr/local/bin/python3* From 035449a932690214b6df77a2c2e5d118dacb6c87 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:45:42 -0400 Subject: [PATCH 076/114] core: Extract `TransactionManager` from `clp::ffi::ir_stream::Deserializer`; Improve class' docs and require nothrow for its handlers. (#548) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 1 + .../core/src/clp/TransactionManager.hpp | 51 +++++++++++++++++++ .../src/clp/ffi/ir_stream/Deserializer.cpp | 49 ++---------------- 3 files changed, 55 insertions(+), 46 deletions(-) create mode 100644 components/core/src/clp/TransactionManager.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 67eb80040..178f3e529 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -480,6 +480,7 @@ set(SOURCE_FILES_unitTest src/clp/TimestampPattern.cpp src/clp/TimestampPattern.hpp src/clp/TraceableException.hpp + src/clp/TransactionManager.hpp src/clp/type_utils.hpp src/clp/utf8_utils.cpp src/clp/utf8_utils.hpp diff --git a/components/core/src/clp/TransactionManager.hpp b/components/core/src/clp/TransactionManager.hpp new file mode 100644 index 000000000..fe70f5547 --- /dev/null +++ b/components/core/src/clp/TransactionManager.hpp @@ -0,0 +1,51 @@ +#ifndef CLP_TRANSACTIONMANAGER_HPP +#define CLP_TRANSACTIONMANAGER_HPP + +#include + +namespace clp { +/** + * A class that on destruction, performs different actions depending on whether a transaction + * succeeds or fails. The default state assumes the transaction fails. + * @tparam SuccessHandler A cleanup lambda to call on success. + * @tparam FailureHandler A cleanup lambda to call on failure. + */ +template +requires(std::is_nothrow_invocable_v && std::is_nothrow_invocable_v) +class TransactionManager { +public: + // Constructor + TransactionManager(SuccessHandler success_handler, FailureHandler failure_handler) + : m_success_handler{success_handler}, + m_failure_handler{failure_handler} {} + + // Delete copy/move constructor and assignment + TransactionManager(TransactionManager const&) = delete; + TransactionManager(TransactionManager&&) = delete; + auto operator=(TransactionManager const&) -> TransactionManager& = delete; + auto operator=(TransactionManager&&) -> TransactionManager& = delete; + + // Destructor + ~TransactionManager() { + if (m_success) { + m_success_handler(); + } else { + m_failure_handler(); + } + } + + // Methods + /** + * Marks the transaction as successful. + */ + auto mark_success() -> void { m_success = true; } + +private: + // Variables + SuccessHandler m_success_handler; + FailureHandler m_failure_handler; + bool m_success{false}; +}; +} // namespace clp + +#endif // CLP_TRANSACTIONMANAGER_HPP diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp index 11034c4a6..5402f9b98 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -14,6 +13,7 @@ #include "../../ReaderInterface.hpp" #include "../../time_types.hpp" +#include "../../TransactionManager.hpp" #include "../KeyValuePairLogEvent.hpp" #include "decoding_methods.hpp" #include "ir_unit_deserialization_methods.hpp" @@ -22,49 +22,6 @@ namespace clp::ffi::ir_stream { namespace { -/** - * Class to perform different actions depending on whether a transaction succeeds or fails. The - * default state assumes the transaction fails. - * @tparam SuccessHandler A cleanup lambda to call on success. - * @tparam FailureHandler A cleanup lambda to call on failure. - */ -template -requires(std::is_invocable_v && std::is_invocable_v) -class TransactionManager { -public: - // Constructor - TransactionManager(SuccessHandler success_handler, FailureHandler failure_handler) - : m_success_handler{success_handler}, - m_failure_handler{failure_handler} {} - - // Delete copy/move constructor and assignment - TransactionManager(TransactionManager const&) = delete; - TransactionManager(TransactionManager&&) = delete; - auto operator=(TransactionManager const&) -> TransactionManager& = delete; - auto operator=(TransactionManager&&) -> TransactionManager& = delete; - - // Destructor - ~TransactionManager() { - if (m_success) { - m_success_handler(); - } else { - m_failure_handler(); - } - } - - // Methods - /** - * Marks the transaction as successful. - */ - auto mark_success() -> void { m_success = true; } - -private: - // Variables - SuccessHandler m_success_handler; - FailureHandler m_failure_handler; - bool m_success{false}; -}; - /** * @param tag * @return Whether the tag represents a schema tree node. @@ -122,8 +79,8 @@ auto Deserializer::deserialize_to_next_log_event(clp::ReaderInterface& reader auto const utc_offset_snapshot{m_utc_offset}; m_schema_tree->take_snapshot(); TransactionManager revert_manager{ - []() -> void {}, - [&]() -> void { + []() noexcept -> void {}, + [&]() noexcept -> void { m_utc_offset = utc_offset_snapshot; m_schema_tree->revert(); } From 7826d7312aa0cea784bfe5371a608094fca10d06 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Mon, 7 Oct 2024 10:20:01 -0400 Subject: [PATCH 077/114] clp-s: Add support for projecting of a subset of columns during search. (#510) Co-authored-by: wraymo <37269683+wraymo@users.noreply.github.com> Co-authored-by: Kirk Rodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/src/clp_s/ArchiveReader.cpp | 1 + components/core/src/clp_s/ArchiveReader.hpp | 8 ++ components/core/src/clp_s/CMakeLists.txt | 2 + .../core/src/clp_s/CommandLineArguments.cpp | 8 ++ .../core/src/clp_s/CommandLineArguments.hpp | 3 + components/core/src/clp_s/JsonSerializer.hpp | 8 +- components/core/src/clp_s/SchemaReader.cpp | 12 ++- components/core/src/clp_s/SchemaReader.hpp | 5 ++ components/core/src/clp_s/clp-s.cpp | 21 +++++ .../core/src/clp_s/search/Projection.cpp | 88 +++++++++++++++++++ .../core/src/clp_s/search/Projection.hpp | 82 +++++++++++++++++ 11 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 components/core/src/clp_s/search/Projection.cpp create mode 100644 components/core/src/clp_s/search/Projection.hpp diff --git a/components/core/src/clp_s/ArchiveReader.cpp b/components/core/src/clp_s/ArchiveReader.cpp index f211a0707..1bdc0baae 100644 --- a/components/core/src/clp_s/ArchiveReader.cpp +++ b/components/core/src/clp_s/ArchiveReader.cpp @@ -235,6 +235,7 @@ void ArchiveReader::initialize_schema_reader( auto& schema = (*m_schema_map)[schema_id]; reader.reset( m_schema_tree, + m_projection, schema_id, schema.get_ordered_schema_view(), m_id_to_table_metadata[schema_id].num_messages, diff --git a/components/core/src/clp_s/ArchiveReader.hpp b/components/core/src/clp_s/ArchiveReader.hpp index 91fcc1a94..97966131f 100644 --- a/components/core/src/clp_s/ArchiveReader.hpp +++ b/components/core/src/clp_s/ArchiveReader.hpp @@ -12,6 +12,7 @@ #include "DictionaryReader.hpp" #include "ReaderUtils.hpp" #include "SchemaReader.hpp" +#include "search/Projection.hpp" #include "TimestampDictionaryReader.hpp" #include "Utils.hpp" @@ -133,6 +134,10 @@ class ArchiveReader { */ [[nodiscard]] std::vector const& get_schema_ids() const { return m_schema_ids; } + void set_projection(std::shared_ptr projection) { + m_projection = projection; + } + private: /** * Initializes a schema reader passed by reference to become a reader for a given schema. @@ -182,6 +187,9 @@ class ArchiveReader { std::shared_ptr m_schema_map; std::vector m_schema_ids; std::map m_id_to_table_metadata; + std::shared_ptr m_projection{ + std::make_shared(search::ProjectionMode::ReturnAllColumns) + }; FileReader m_tables_file_reader; FileReader m_table_metadata_file_reader; diff --git a/components/core/src/clp_s/CMakeLists.txt b/components/core/src/clp_s/CMakeLists.txt index c8cf08b22..625972de7 100644 --- a/components/core/src/clp_s/CMakeLists.txt +++ b/components/core/src/clp_s/CMakeLists.txt @@ -145,6 +145,8 @@ set( search/Output.hpp search/OutputHandler.cpp search/OutputHandler.hpp + search/Projection.cpp + search/Projection.hpp search/SchemaMatch.cpp search/SchemaMatch.hpp search/SearchUtils.cpp diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index 4cfe017ac..553f17c39 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -425,6 +425,14 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { "archive-id", po::value(&m_archive_id)->value_name("ID"), "Limit search to the archive with the given ID" + )( + "projection", + po::value>(&m_projection_columns) + ->multitoken() + ->value_name("COLUMN_A COLUMN_B ..."), + "Project only the given set of columns for matching results. This option must be" + " specified after all positional options. Values that are objects or structured" + " arrays are currently unsupported." ); // clang-format on search_options.add(match_options); diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 0f3d8c556..030ff8b99 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -108,6 +108,8 @@ class CommandLineArguments { size_t get_ordered_chunk_size() const { return m_ordered_chunk_size; } + std::vector const& get_projection_columns() const { return m_projection_columns; } + private: // Methods /** @@ -192,6 +194,7 @@ class CommandLineArguments { std::optional m_search_begin_ts; std::optional m_search_end_ts; bool m_ignore_case{false}; + std::vector m_projection_columns; // Decompression and search variables std::string m_archive_id; diff --git a/components/core/src/clp_s/JsonSerializer.hpp b/components/core/src/clp_s/JsonSerializer.hpp index 01a8a1e74..ff46dfa24 100644 --- a/components/core/src/clp_s/JsonSerializer.hpp +++ b/components/core/src/clp_s/JsonSerializer.hpp @@ -75,7 +75,13 @@ class JsonSerializer { void begin_document() { m_json_string += "{"; } - void end_document() { m_json_string[m_json_string.size() - 1] = '}'; } + void end_document() { + if ('{' != m_json_string.back()) { + m_json_string[m_json_string.size() - 1] = '}'; + } else { + m_json_string += '}'; + } + } void end_object() { if (m_op_list[m_op_list_index - 2] != BeginObject diff --git a/components/core/src/clp_s/SchemaReader.cpp b/components/core/src/clp_s/SchemaReader.cpp index 03edebf69..d2c7739da 100644 --- a/components/core/src/clp_s/SchemaReader.cpp +++ b/components/core/src/clp_s/SchemaReader.cpp @@ -548,19 +548,25 @@ void SchemaReader::initialize_serializer() { m_serializer_initialized = true; for (int32_t global_column_id : m_ordered_schema) { - generate_local_tree(global_column_id); + if (m_projection->matches_node(global_column_id)) { + generate_local_tree(global_column_id); + } } for (auto it = m_global_id_to_unordered_object.begin(); it != m_global_id_to_unordered_object.end(); ++it) { - generate_local_tree(it->first); + if (m_projection->matches_node(it->first)) { + generate_local_tree(it->first); + } } // TODO: this code will have to change once we allow mixing log lines parsed by different // parsers. - generate_json_template(0); + if (false == m_local_schema_tree.get_nodes().empty()) { + generate_json_template(m_local_schema_tree.get_root_node_id()); + } } void SchemaReader::generate_json_template(int32_t id) { diff --git a/components/core/src/clp_s/SchemaReader.hpp b/components/core/src/clp_s/SchemaReader.hpp index 3639560f6..d72b2c3b6 100644 --- a/components/core/src/clp_s/SchemaReader.hpp +++ b/components/core/src/clp_s/SchemaReader.hpp @@ -11,6 +11,7 @@ #include "FileReader.hpp" #include "JsonSerializer.hpp" #include "SchemaTree.hpp" +#include "search/Projection.hpp" #include "ZstdDecompressor.hpp" namespace clp_s { @@ -71,6 +72,7 @@ class SchemaReader { * to accept append_column calls for the new schema. * * @param schema_tree + * @param projection * @param schema_id * @param ordered_schema * @param num_messages @@ -78,6 +80,7 @@ class SchemaReader { */ void reset( std::shared_ptr schema_tree, + std::shared_ptr projection, int32_t schema_id, std::span ordered_schema, uint64_t num_messages, @@ -100,6 +103,7 @@ class SchemaReader { m_local_schema_tree.clear(); m_json_serializer.clear(); m_global_schema_tree = std::move(schema_tree); + m_projection = std::move(projection); m_should_marshal_records = should_marshal_records; } @@ -291,6 +295,7 @@ class SchemaReader { JsonSerializer m_json_serializer; bool m_should_marshal_records{true}; bool m_serializer_initialized{false}; + std::shared_ptr m_projection; std::map>> m_global_id_to_unordered_object; }; diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 0e0401ad1..8e37ca769 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -29,6 +29,7 @@ #include "search/OrOfAndForm.hpp" #include "search/Output.hpp" #include "search/OutputHandler.hpp" +#include "search/Projection.hpp" #include "search/SchemaMatch.hpp" #include "TimestampPattern.hpp" #include "TraceableException.hpp" @@ -39,6 +40,7 @@ using clp_s::cArchiveFormatDevelopmentVersionFlag; using clp_s::cEpochTimeMax; using clp_s::cEpochTimeMin; using clp_s::CommandLineArguments; +using clp_s::StringUtils; namespace { /** @@ -179,6 +181,25 @@ bool search_archive( return true; } + // Populate projection + auto projection = std::make_shared( + command_line_arguments.get_projection_columns().empty() + ? ProjectionMode::ReturnAllColumns + : ProjectionMode::ReturnSelectedColumns + ); + try { + for (auto const& column : command_line_arguments.get_projection_columns()) { + std::vector descriptor_tokens; + StringUtils::tokenize_column_descriptor(column, descriptor_tokens); + projection->add_column(ColumnDescriptor::create(descriptor_tokens)); + } + } catch (clp_s::TraceableException& e) { + SPDLOG_ERROR("{}", e.what()); + return false; + } + projection->resolve_columns(archive_reader->get_schema_tree()); + archive_reader->set_projection(projection); + std::unique_ptr output_handler; try { switch (command_line_arguments.get_output_handler_type()) { diff --git a/components/core/src/clp_s/search/Projection.cpp b/components/core/src/clp_s/search/Projection.cpp new file mode 100644 index 000000000..69836e312 --- /dev/null +++ b/components/core/src/clp_s/search/Projection.cpp @@ -0,0 +1,88 @@ +#include "Projection.hpp" + +#include + +#include "SearchUtils.hpp" + +namespace clp_s::search { +void Projection::add_column(std::shared_ptr column) { + if (column->is_unresolved_descriptor()) { + throw OperationFailed(ErrorCodeBadParam, __FILE__, __LINE__); + } + if (ProjectionMode::ReturnAllColumns == m_projection_mode) { + throw OperationFailed(ErrorCodeUnsupported, __FILE__, __LINE__); + } + if (m_selected_columns.end() + != std::find_if( + m_selected_columns.begin(), + m_selected_columns.end(), + [column](auto const& rhs) -> bool { return *column == *rhs; } + )) + { + // no duplicate columns in projection + throw OperationFailed(ErrorCodeBadParam, __FILE__, __LINE__); + } + m_selected_columns.push_back(column); +} + +void Projection::resolve_columns(std::shared_ptr tree) { + for (auto& column : m_selected_columns) { + resolve_column(tree, column); + } +} + +void Projection::resolve_column( + std::shared_ptr tree, + std::shared_ptr column +) { + /** + * Ideally we would reuse the code from SchemaMatch for resolving columns, but unfortunately we + * can not. + * + * The main reason is that here we don't want to allow projection to travel inside unstructured + * objects -- it may be possible to support such a thing in the future, but it poses some extra + * challenges (e.g. deciding what to do when projecting repeated elements in a structure). + * + * It would be possible to create code that can handle our use-case and SchemaMatch's use-case + * in an elegant way, but it's a significant refactor. In particular, if we extend our column + * type system to be one-per-token instead of one-per-column we can make it so that intermediate + * tokens will not match certain kinds of MPT nodes (like the node for structured arrays). + * + * In light of that we implement a simple version of column resolution here that does exactly + * what we need. + */ + + auto cur_node_id = tree->get_root_node_id(); + auto it = column->descriptor_begin(); + while (it != column->descriptor_end()) { + bool matched_any{false}; + auto cur_it = it++; + bool last_token = it == column->descriptor_end(); + auto const& cur_node = tree->get_node(cur_node_id); + for (int32_t child_node_id : cur_node.get_children_ids()) { + auto const& child_node = tree->get_node(child_node_id); + + // Intermediate nodes must be objects + if (false == last_token && child_node.get_type() != NodeType::Object) { + continue; + } + + if (child_node.get_key_name() != cur_it->get_token()) { + continue; + } + + matched_any = true; + if (last_token && column->matches_type(node_to_literal_type(child_node.get_type()))) { + m_matching_nodes.insert(child_node_id); + } else if (false == last_token) { + cur_node_id = child_node_id; + break; + } + } + + if (false == matched_any) { + break; + } + } +} +} // namespace clp_s::search diff --git a/components/core/src/clp_s/search/Projection.hpp b/components/core/src/clp_s/search/Projection.hpp new file mode 100644 index 000000000..74fece742 --- /dev/null +++ b/components/core/src/clp_s/search/Projection.hpp @@ -0,0 +1,82 @@ +#ifndef CLP_S_SEARCH_PROJECTION_HPP +#define CLP_S_SEARCH_PROJECTION_HPP + +#include + +#include + +#include "../SchemaTree.hpp" +#include "../TraceableException.hpp" +#include "ColumnDescriptor.hpp" + +namespace clp_s::search { +enum ProjectionMode : uint8_t { + ReturnAllColumns, + ReturnSelectedColumns +}; + +/** + * This class describes the set of columns that should be included in the projected results. + * + * After adding columns and before calling matches_node the caller is responsible for calling + * resolve_columns. + */ +class Projection { +public: + class OperationFailed : public TraceableException { + public: + // Constructors + OperationFailed(ErrorCode error_code, char const* const filename, int line_number) + : TraceableException(error_code, filename, line_number) {} + }; + + explicit Projection(ProjectionMode mode) : m_projection_mode{mode} {} + + /** + * Adds a column to the set of columns that should be included in the projected results + * @param column + * @throws OperationFailed if `column` contains a wildcard + * @throws OperationFailed if this instance of Projection is in mode ReturnAllColumns + * @throws OperationFailed if `column` is identical to a previously added column + */ + void add_column(std::shared_ptr column); + + /** + * Resolves all columns for the purpose of projection. This key resolution implementation is + * more limited than the one in schema matching. In particular, this version of key resolution + * only allows resolving keys that do not contain wildcards and does not allow resolving to + * objects within arrays. + * + * Note: we could try to generalize column resolution code/move it to the schema tree. It is + * probably best to write a simpler version dedicated to projection for now since types are + * leaf-only. The type-per-token idea solves this problem (in the absence of wildcards). + * + * @param tree + */ + void resolve_columns(std::shared_ptr tree); + + /** + * Checks whether a column corresponding to given leaf node should be included in the output + * @param node_id + * @return true if the column should be included in the output, false otherwise + */ + bool matches_node(int32_t node_id) const { + return ProjectionMode::ReturnAllColumns == m_projection_mode + || m_matching_nodes.contains(node_id); + } + +private: + /** + * Resolves an individual column as described by the `resolve_columns` method. + * @param tree + * @param column + */ + void resolve_column(std::shared_ptr tree, std::shared_ptr column); + + std::vector> m_selected_columns; + absl::flat_hash_set m_matching_nodes; + ProjectionMode m_projection_mode{ProjectionMode::ReturnAllColumns}; +}; +} // namespace clp_s::search + +#endif // CLP_S_SEARCH_PROJECTION_HPP From 1c679083a54f9ea54b7107768cb1daebd3b655f1 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:03:39 -0400 Subject: [PATCH 078/114] ffi: Redesign `Deserializer` API to deserialize key-value pair IR streams one IR unit at a time (fixes #539). (#549) --- components/core/CMakeLists.txt | 2 +- .../src/clp/ffi/ir_stream/Deserializer.cpp | 135 ----------- .../src/clp/ffi/ir_stream/Deserializer.hpp | 222 ++++++++++++++++-- .../core/src/clp/ffi/ir_stream/IrUnitType.hpp | 18 ++ .../ir_unit_deserialization_methods.cpp | 39 +++ .../ir_unit_deserialization_methods.hpp | 9 + .../core/tests/test-ir_encoding_methods.cpp | 87 +++++-- 7 files changed, 346 insertions(+), 166 deletions(-) delete mode 100644 components/core/src/clp/ffi/ir_stream/Deserializer.cpp create mode 100644 components/core/src/clp/ffi/ir_stream/IrUnitType.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 178f3e529..09577fa31 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -326,7 +326,6 @@ set(SOURCE_FILES_unitTest src/clp/ffi/encoding_methods.hpp src/clp/ffi/encoding_methods.inc src/clp/ffi/ir_stream/byteswap.hpp - src/clp/ffi/ir_stream/Deserializer.cpp src/clp/ffi/ir_stream/Deserializer.hpp src/clp/ffi/ir_stream/decoding_methods.cpp src/clp/ffi/ir_stream/decoding_methods.hpp @@ -334,6 +333,7 @@ set(SOURCE_FILES_unitTest src/clp/ffi/ir_stream/encoding_methods.cpp src/clp/ffi/ir_stream/encoding_methods.hpp src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp + src/clp/ffi/ir_stream/IrUnitType.hpp src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp src/clp/ffi/ir_stream/protocol_constants.hpp diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp b/components/core/src/clp/ffi/ir_stream/Deserializer.cpp deleted file mode 100644 index 5402f9b98..000000000 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "Deserializer.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../../ReaderInterface.hpp" -#include "../../time_types.hpp" -#include "../../TransactionManager.hpp" -#include "../KeyValuePairLogEvent.hpp" -#include "decoding_methods.hpp" -#include "ir_unit_deserialization_methods.hpp" -#include "protocol_constants.hpp" -#include "utils.hpp" - -namespace clp::ffi::ir_stream { -namespace { -/** - * @param tag - * @return Whether the tag represents a schema tree node. - */ -[[nodiscard]] auto is_schema_tree_node_tag(encoded_tag_t tag) -> bool; - -auto is_schema_tree_node_tag(encoded_tag_t tag) -> bool { - return (tag & cProtocol::Payload::SchemaTreeNodeMask) == cProtocol::Payload::SchemaTreeNodeMask; -} -} // namespace - -auto Deserializer::create(ReaderInterface& reader -) -> OUTCOME_V2_NAMESPACE::std_result { - bool is_four_byte_encoded{}; - if (auto const err{get_encoding_type(reader, is_four_byte_encoded)}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); - } - - std::vector metadata; - encoded_tag_t metadata_type{}; - if (auto const err{deserialize_preamble(reader, metadata_type, metadata)}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); - } - - if (cProtocol::Metadata::EncodingJson != metadata_type) { - return std::errc::protocol_not_supported; - } - - auto metadata_json = nlohmann::json::parse(metadata, nullptr, false); - if (metadata_json.is_discarded()) { - return std::errc::protocol_error; - } - auto const version_iter{metadata_json.find(cProtocol::Metadata::VersionKey)}; - if (metadata_json.end() == version_iter || false == version_iter->is_string()) { - return std::errc::protocol_error; - } - auto const version = version_iter->get_ref(); - // TODO: Just before the KV-pair IR format is formally released, we should replace this - // hard-coded version check with `ffi::ir_stream::validate_protocol_version`. - if (std::string_view{static_cast(cProtocol::Metadata::BetaVersionValue)} - != version) - { - return std::errc::protocol_not_supported; - } - - return Deserializer{}; -} - -auto Deserializer::deserialize_to_next_log_event(clp::ReaderInterface& reader -) -> OUTCOME_V2_NAMESPACE::std_result { - auto const utc_offset_snapshot{m_utc_offset}; - m_schema_tree->take_snapshot(); - TransactionManager revert_manager{ - []() noexcept -> void {}, - [&]() noexcept -> void { - m_utc_offset = utc_offset_snapshot; - m_schema_tree->revert(); - } - }; - - encoded_tag_t tag{}; - std::string schema_tree_node_key_name; - while (true) { - if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return ir_error_code_to_errc(err); - } - - if (cProtocol::Eof == tag) { - return std::errc::no_message_available; - } - - if (is_schema_tree_node_tag(tag)) { - auto const result{deserialize_ir_unit_schema_tree_node_insertion( - reader, - tag, - schema_tree_node_key_name - )}; - if (result.has_error()) { - return result.error(); - } - auto const& locator{result.value()}; - if (m_schema_tree->has_node(locator)) { - return std::errc::protocol_error; - } - std::ignore = m_schema_tree->insert_node(locator); - continue; - } - - if (cProtocol::Payload::UtcOffsetChange == tag) { - auto const result{deserialize_ir_unit_utc_offset_change(reader)}; - if (result.has_error()) { - return result.error(); - } - m_utc_offset = result.value(); - continue; - } - - break; - } - - auto result{deserialize_ir_unit_kv_pair_log_event(reader, tag, m_schema_tree, m_utc_offset)}; - if (false == result.has_error()) { - revert_manager.mark_success(); - } - return std::move(result); -} -} // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp index 0fb7e8c83..c1fc13c85 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp @@ -1,37 +1,55 @@ #ifndef CLP_FFI_IR_STREAM_DESERIALIZER_HPP #define CLP_FFI_IR_STREAM_DESERIALIZER_HPP +#include +#include #include +#include +#include +#include +#include +#include #include #include "../../ReaderInterface.hpp" #include "../../time_types.hpp" #include "../KeyValuePairLogEvent.hpp" #include "../SchemaTree.hpp" +#include "decoding_methods.hpp" +#include "ir_unit_deserialization_methods.hpp" +#include "IrUnitHandlerInterface.hpp" +#include "IrUnitType.hpp" +#include "protocol_constants.hpp" +#include "utils.hpp" namespace clp::ffi::ir_stream { /** - * A deserializer for log events from a CLP kv-pair IR stream. The class ensures any internal state - * remains consistent even when a deserialization failure occurs (i.e., it's transactional). + * A deserializer for reading IR units from a CLP kv-pair IR stream. An IR unit handler should be + * provided to perform user-defined operations on each deserialized IR unit. * * NOTE: This class is designed only to provide deserialization functionalities. Callers are * responsible for maintaining a `ReaderInterface` to input IR bytes from an I/O stream. + * + * @tparam IrUnitHandler */ +template +requires(std::move_constructible) class Deserializer { public: // Factory function /** * Creates a deserializer by reading the stream's preamble from the given reader. * @param reader + * @param ir_unit_handler * @return A result containing the deserializer or an error code indicating the failure: * - std::errc::result_out_of_range if the IR stream is truncated * - std::errc::protocol_error if the IR stream is corrupted * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format * or uses an unsupported version */ - [[nodiscard]] static auto create(ReaderInterface& reader - ) -> OUTCOME_V2_NAMESPACE::std_result; + [[nodiscard]] static auto create(ReaderInterface& reader, IrUnitHandler ir_unit_handler) + -> OUTCOME_V2_NAMESPACE::std_result; // Delete copy constructor and assignment Deserializer(Deserializer const&) = delete; @@ -48,27 +66,199 @@ class Deserializer { /** * Deserializes the stream from the given reader up to and including the next log event IR unit. * @param reader - * @return A result containing the deserialized log event or an error code indicating the - * failure: - * - std::errc::no_message_available if the IR stream has been fully consumed. - * - std::errc::result_out_of_range if the IR stream is truncated. - * - std::errc::protocol_error if the IR stream is corrupted. - * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format - * or uses an unsupported version. - * - Forwards `KeyValuePairLogEvent::create`'s return values if the intermediate deserialized - * result cannot construct a valid key-value pair log event. + * @return std::errc::no_message_available if no tag bytes can be read to determine the next IR + * unit type. + * @return std::errc::protocol_not_supported if the IR unit type is not supported. + * @return std::errc::operation_not_permitted if the deserializer already reached the end of + * stream by deserializing an end-of-stream IR unit in the previous calls. + * @return IRUnitType::LogEvent if a log event IR unit is deserialized, or an error code + * indicating the failure: + * - Forwards `deserialize_ir_unit_kv_pair_log_event`'s return values if it failed to + * deserialize and construct the log event. + * - Forwards `handle_log_event`'s return values from the user-defined IR unit handler on + * unit handling failure. + * @return IRUnitType::SchemaTreeNodeInsertion if a schema tree node insertion IR unit is + * deserialized, or an error code indicating the failure: + * - Forwards `deserialize_ir_unit_schema_tree_node_insertion`'s return values if it failed to + * deserialize and construct the schema tree node locator. + * - Forwards `handle_schema_tree_node_insertion`'s return values from the user-defined IR unit + * handler on unit handling failure. + * - std::errc::protocol_error if the deserialized schema tree node already exists in the schema + * tree. + * @return IRUnitType::UtcOffsetChange if a UTC offset change IR unit is deserialized, or an + * error code indicating the failure: + * - Forwards `deserialize_ir_unit_utc_offset_change`'s return values if it failed to + * deserialize the UTC offset. + * - Forwards `handle_utc_offset_change`'s return values from the user-defined IR unit handler + * on unit handling failure. + * @return IRUnitType::EndOfStream if an end-of-stream IR unit is deserialized, or an error code + * indicating the failure: + * - Forwards `handle_end_of_stream`'s return values from the user-defined IR unit handler on + * unit handling failure. */ - [[nodiscard]] auto deserialize_to_next_log_event(ReaderInterface& reader - ) -> OUTCOME_V2_NAMESPACE::std_result; + [[nodiscard]] auto deserialize_next_ir_unit(ReaderInterface& reader + ) -> OUTCOME_V2_NAMESPACE::std_result; + + /** + * @return Whether the stream has completed. A stream is considered completed if an + * end-of-stream IR unit has already been deserialized. + */ + [[nodiscard]] auto is_stream_completed() const -> bool { return m_is_complete; } + + [[nodiscard]] auto get_ir_unit_handler() const -> IrUnitHandler const& { + return m_ir_unit_handler; + } + + [[nodiscard]] auto get_ir_unit_handler() -> IrUnitHandler& { return m_ir_unit_handler; } private: // Constructor - Deserializer() = default; + Deserializer(IrUnitHandler ir_unit_handler) : m_ir_unit_handler{std::move(ir_unit_handler)} {} // Variables std::shared_ptr m_schema_tree{std::make_shared()}; UtcOffset m_utc_offset{0}; + IrUnitHandler m_ir_unit_handler; + bool m_is_complete{false}; }; + +template +requires(std::move_constructible) +auto Deserializer::create(ReaderInterface& reader, IrUnitHandler ir_unit_handler) + -> OUTCOME_V2_NAMESPACE::std_result { + bool is_four_byte_encoded{}; + if (auto const err{get_encoding_type(reader, is_four_byte_encoded)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + std::vector metadata; + encoded_tag_t metadata_type{}; + if (auto const err{deserialize_preamble(reader, metadata_type, metadata)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + if (cProtocol::Metadata::EncodingJson != metadata_type) { + return std::errc::protocol_not_supported; + } + + auto metadata_json = nlohmann::json::parse(metadata, nullptr, false); + if (metadata_json.is_discarded()) { + return std::errc::protocol_error; + } + auto const version_iter{metadata_json.find(cProtocol::Metadata::VersionKey)}; + if (metadata_json.end() == version_iter || false == version_iter->is_string()) { + return std::errc::protocol_error; + } + auto const version = version_iter->get_ref(); + // TODO: Just before the KV-pair IR format is formally released, we should replace this + // hard-coded version check with `ffi::ir_stream::validate_protocol_version`. + if (std::string_view{static_cast(cProtocol::Metadata::BetaVersionValue)} + != version) + { + return std::errc::protocol_not_supported; + } + + return Deserializer{std::move(ir_unit_handler)}; +} + +template +requires(std::move_constructible) +auto Deserializer::deserialize_next_ir_unit(ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result { + if (is_stream_completed()) { + return std::errc::operation_not_permitted; + } + + encoded_tag_t tag{}; + if (IRErrorCode::IRErrorCode_Success != deserialize_tag(reader, tag)) { + return std::errc::no_message_available; + } + + auto const optional_ir_unit_type{get_ir_unit_type_from_tag(tag)}; + if (false == optional_ir_unit_type.has_value()) { + return std::errc::protocol_not_supported; + } + + auto const ir_unit_type{optional_ir_unit_type.value()}; + switch (ir_unit_type) { + case IrUnitType::LogEvent: { + auto result{ + deserialize_ir_unit_kv_pair_log_event(reader, tag, m_schema_tree, m_utc_offset) + }; + if (result.has_error()) { + return result.error(); + } + + if (auto const err{m_ir_unit_handler.handle_log_event(std::move(result.value()))}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + break; + } + + case IrUnitType::SchemaTreeNodeInsertion: { + std::string key_name; + auto const result{deserialize_ir_unit_schema_tree_node_insertion(reader, tag, key_name) + }; + if (result.has_error()) { + return result.error(); + } + + auto const node_locator{result.value()}; + if (m_schema_tree->has_node(node_locator)) { + return std::errc::protocol_error; + } + + if (auto const err{m_ir_unit_handler.handle_schema_tree_node_insertion(node_locator)}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + std::ignore = m_schema_tree->insert_node(node_locator); + break; + } + + case IrUnitType::UtcOffsetChange: { + auto const result{deserialize_ir_unit_utc_offset_change(reader)}; + if (result.has_error()) { + return result.error(); + } + + auto const new_utc_offset{result.value()}; + if (auto const err{ + m_ir_unit_handler.handle_utc_offset_change(m_utc_offset, new_utc_offset) + }; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + + m_utc_offset = new_utc_offset; + break; + } + + case IrUnitType::EndOfStream: { + if (auto const err{m_ir_unit_handler.handle_end_of_stream()}; + IRErrorCode::IRErrorCode_Success != err) + { + return ir_error_code_to_errc(err); + } + m_is_complete = true; + break; + } + + default: + return std::errc::protocol_not_supported; + } + + return ir_unit_type; +} } // namespace clp::ffi::ir_stream #endif // CLP_FFI_IR_STREAM_DESERIALIZER_HPP diff --git a/components/core/src/clp/ffi/ir_stream/IrUnitType.hpp b/components/core/src/clp/ffi/ir_stream/IrUnitType.hpp new file mode 100644 index 000000000..1ac38750f --- /dev/null +++ b/components/core/src/clp/ffi/ir_stream/IrUnitType.hpp @@ -0,0 +1,18 @@ +#ifndef CLP_FFI_IR_STREAM_IRUNITTYPE_HPP +#define CLP_FFI_IR_STREAM_IRUNITTYPE_HPP + +#include + +namespace clp::ffi::ir_stream { +/** + * Enum defining the possible IR unit types in CLP kv-pair IR stream. + */ +enum class IrUnitType : uint8_t { + LogEvent = 0, + SchemaTreeNodeInsertion, + UtcOffsetChange, + EndOfStream, +}; +} // namespace clp::ffi::ir_stream + +#endif // CLP_FFI_IR_STREAM_IRUNITTYPE_HPP diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp index cfbe235d5..3e9986d46 100644 --- a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp @@ -22,6 +22,7 @@ #include "../SchemaTreeNode.hpp" #include "../Value.hpp" #include "decoding_methods.hpp" +#include "IrUnitType.hpp" #include "protocol_constants.hpp" #include "utils.hpp" @@ -169,6 +170,11 @@ requires(std::is_same_v KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs ) -> IRErrorCode; +/** + * @return Whether the given tag can be a valid leading tag of a log event IR unit. + */ +[[nodiscard]] auto is_log_event_ir_unit_tag(encoded_tag_t tag) -> bool; + auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { switch (tag) { case cProtocol::Payload::SchemaTreeNodeInt: @@ -458,8 +464,41 @@ auto deserialize_value_and_construct_node_id_value_pairs( } return IRErrorCode::IRErrorCode_Success; } + +auto is_log_event_ir_unit_tag(encoded_tag_t tag) -> bool { + if (cProtocol::Payload::ValueEmpty == tag) { + // The log event is an empty object + return true; + } + if (cProtocol::Payload::KeyIdUByte == tag || cProtocol::Payload::KeyIdUShort == tag) { + // If not empty, the log event must start with a tag byte indicating the key ID + return true; + } + return false; +} } // namespace +auto get_ir_unit_type_from_tag(encoded_tag_t tag) -> std::optional { + // First, we check the tags that have one-to-one IR unit mapping + if (cProtocol::Eof == tag) { + return IrUnitType::EndOfStream; + } + if (cProtocol::Payload::UtcOffsetChange == tag) { + return IrUnitType::UtcOffsetChange; + } + + // Then, check tags that may match any byte within a continuous range + if ((tag & cProtocol::Payload::SchemaTreeNodeMask) == cProtocol::Payload::SchemaTreeNodeMask) { + return IrUnitType::SchemaTreeNodeInsertion; + } + + if (is_log_event_ir_unit_tag(tag)) { + return IrUnitType::LogEvent; + } + + return std::nullopt; +} + auto deserialize_ir_unit_schema_tree_node_insertion( ReaderInterface& reader, encoded_tag_t tag, diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp index 0ba21866c..454676cf5 100644 --- a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp @@ -2,6 +2,7 @@ #define CLP_FFI_IR_STREAM_IR_UNIT_DESERIALIZATION_METHODS_HPP #include +#include #include #include @@ -11,8 +12,16 @@ #include "../KeyValuePairLogEvent.hpp" #include "../SchemaTree.hpp" #include "decoding_methods.hpp" +#include "IrUnitType.hpp" namespace clp::ffi::ir_stream { +/** + * @param tag + * @return The IR unit type of indicated by the given tag on success. + * @return std::nullopt if the tag doesn't represent a valid IR unit. + */ +[[nodiscard]] auto get_ir_unit_type_from_tag(encoded_tag_t tag) -> std::optional; + /** * Deserializes a schema tree node insertion IR unit. * @param reader diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index ba8c59280..5c27a6fab 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -16,8 +16,11 @@ #include "../src/clp/ffi/ir_stream/decoding_methods.hpp" #include "../src/clp/ffi/ir_stream/Deserializer.hpp" #include "../src/clp/ffi/ir_stream/encoding_methods.hpp" +#include "../src/clp/ffi/ir_stream/IrUnitType.hpp" #include "../src/clp/ffi/ir_stream/protocol_constants.hpp" #include "../src/clp/ffi/ir_stream/Serializer.hpp" +#include "../src/clp/ffi/KeyValuePairLogEvent.hpp" +#include "../src/clp/ffi/SchemaTree.hpp" #include "../src/clp/ir/LogEventDeserializer.hpp" #include "../src/clp/ir/types.hpp" #include "../src/clp/time_types.hpp" @@ -42,6 +45,7 @@ using clp::ffi::ir_stream::IRErrorCode; using clp::ffi::ir_stream::serialize_utc_offset_change; using clp::ffi::ir_stream::Serializer; using clp::ffi::ir_stream::validate_protocol_version; +using clp::ffi::KeyValuePairLogEvent; using clp::ffi::wildcard_query_matches_any_encoded_var; using clp::ir::eight_byte_encoded_variable_t; using clp::ir::epoch_time_ms_t; @@ -82,6 +86,47 @@ class UnstructuredLogEvent { UtcOffset m_utc_offset{0}; }; +/** + * Class that implements `clp::ffi::ir_stream::IrUnitHandlerInterface` for testing purposes. + */ +class IrUnitHandler { +public: + // Implements `clp::ffi::ir_stream::IrUnitHandlerInterface` interface + [[nodiscard]] auto handle_log_event(KeyValuePairLogEvent&& log_event) -> IRErrorCode { + m_deserialized_log_events.emplace_back(std::move(log_event)); + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] static auto handle_utc_offset_change( + [[maybe_unused]] UtcOffset utc_offset_old, + [[maybe_unused]] UtcOffset utc_offset_new + ) -> IRErrorCode { + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] static auto handle_schema_tree_node_insertion( + [[maybe_unused]] clp::ffi::SchemaTree::NodeLocator schema_tree_node_locator + ) -> IRErrorCode { + return IRErrorCode::IRErrorCode_Success; + } + + [[nodiscard]] auto handle_end_of_stream() -> IRErrorCode { + m_is_complete = true; + return IRErrorCode::IRErrorCode_Success; + } + + // Methods + [[nodiscard]] auto is_complete() const -> bool { return m_is_complete; } + + [[nodiscard]] auto get_deserialized_log_events() const -> vector const& { + return m_deserialized_log_events; + } + +private: + vector m_deserialized_log_events; + bool m_is_complete{false}; +}; + /** * Serializes the given log events into an IR buffer. * @tparam encoded_variable_t Type of the encoded variables. @@ -1127,25 +1172,39 @@ TEMPLATE_TEST_CASE( // Deserialize the results BufferReader reader{size_checked_pointer_cast(ir_buf.data()), ir_buf.size()}; - auto deserializer_result = Deserializer::create(reader); + auto deserializer_result{Deserializer::create(reader, IrUnitHandler{})}; REQUIRE_FALSE(deserializer_result.has_error()); auto& deserializer = deserializer_result.value(); - - for (auto const& json_obj : serialized_json_objects) { - auto const kv_log_event_result = deserializer.deserialize_to_next_log_event(reader); - REQUIRE_FALSE(kv_log_event_result.has_error()); - - auto const& kv_log_event = kv_log_event_result.value(); - auto const num_leaves_in_json_obj = count_num_leaves(json_obj); - auto const num_kv_pairs = kv_log_event.get_node_id_value_pairs().size(); + while (true) { + auto const result{deserializer.deserialize_next_ir_unit(reader)}; + REQUIRE_FALSE(result.has_error()); + if (result.value() == clp::ffi::ir_stream::IrUnitType::EndOfStream) { + break; + } + } + auto const& ir_unit_handler{deserializer.get_ir_unit_handler()}; + + // Check the stream is complete + REQUIRE(ir_unit_handler.is_complete()); + REQUIRE(deserializer.is_stream_completed()); + // Check the number of log events deserialized matches the number of log events serialized + auto const& deserialized_log_events{ir_unit_handler.get_deserialized_log_events()}; + REQUIRE((serialized_json_objects.size() == deserialized_log_events.size())); + + auto const num_log_events{serialized_json_objects.size()}; + for (size_t idx{0}; idx < num_log_events; ++idx) { + auto const& expect{serialized_json_objects.at(idx)}; + auto const& deserialized_log_event{deserialized_log_events.at(idx)}; + + auto const num_leaves_in_json_obj{count_num_leaves(expect)}; + auto const num_kv_pairs{deserialized_log_event.get_node_id_value_pairs().size()}; REQUIRE((num_leaves_in_json_obj == num_kv_pairs)); - auto const serialized_json_result = kv_log_event.serialize_to_json(); + auto const serialized_json_result{deserialized_log_event.serialize_to_json()}; REQUIRE_FALSE(serialized_json_result.has_error()); - REQUIRE((json_obj == serialized_json_result.value())); + REQUIRE((expect == serialized_json_result.value())); } - auto const eof_result{deserializer.deserialize_to_next_log_event(reader)}; - REQUIRE(eof_result.has_error()); - REQUIRE((std::errc::no_message_available == eof_result.error())); + auto const eof_result{deserializer.deserialize_next_ir_unit(reader)}; + REQUIRE((eof_result.has_error() && std::errc::operation_not_permitted == eof_result.error())); } From 0f42e980b1a894af10eeb0c3bd15c1743fa9b278 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 11 Oct 2024 18:28:02 -0400 Subject: [PATCH 079/114] Temporarily lock Sphinx to v8.0.2 to resolve docs build failure. (#555) --- docs/requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index ed28263a9..84466dcae 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,7 +2,9 @@ myst-parser>=2.0.0 # Locked to avoid pydata/pydata-sphinx-theme#1676 until its fix is released in a version above # 0.15.2 pydata-sphinx-theme==0.14.4 -sphinx>=7.3.7 +# Locked to avoid the following issue until a fix is released: +# https://github.com/sphinx-doc/sphinx/issues/13002 +sphinx==8.0.2 sphinx_design>=0.5.0 sphinx-copybutton>=0.5.2 sphinxcontrib-mermaid>=0.9.2 From de2cf07f04620fe0a9f90d69857435343b9683cc Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 11 Oct 2024 22:25:43 -0400 Subject: [PATCH 080/114] ffi: Move `SchemaTreeNode` into `SchemaTree`; Use an `optional` for the parent ID in the schema tree node to track nodes which have no parents (the root). (#554) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/CMakeLists.txt | 1 - .../core/src/clp/ffi/KeyValuePairLogEvent.cpp | 81 ++++----- .../core/src/clp/ffi/KeyValuePairLogEvent.hpp | 3 +- components/core/src/clp/ffi/SchemaTree.cpp | 28 ++-- components/core/src/clp/ffi/SchemaTree.hpp | 156 +++++++++++++++--- .../core/src/clp/ffi/SchemaTreeNode.hpp | 88 ---------- .../core/src/clp/ffi/ir_stream/Serializer.cpp | 61 ++++--- .../core/src/clp/ffi/ir_stream/Serializer.hpp | 5 +- .../ir_unit_deserialization_methods.cpp | 41 +++-- .../tests/test-ffi_IrUnitHandlerInterface.cpp | 4 +- .../tests/test-ffi_KeyValuePairLogEvent.cpp | 42 +++-- components/core/tests/test-ffi_SchemaTree.cpp | 86 ++++++---- 12 files changed, 316 insertions(+), 280 deletions(-) delete mode 100644 components/core/src/clp/ffi/SchemaTreeNode.hpp diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 09577fa31..83e5c7630 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -345,7 +345,6 @@ set(SOURCE_FILES_unitTest src/clp/ffi/KeyValuePairLogEvent.hpp src/clp/ffi/SchemaTree.cpp src/clp/ffi/SchemaTree.hpp - src/clp/ffi/SchemaTreeNode.hpp src/clp/ffi/search/CompositeWildcardToken.cpp src/clp/ffi/search/CompositeWildcardToken.hpp src/clp/ffi/search/ExactVariableToken.cpp diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp index 4b528c039..2a84795f7 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp @@ -17,7 +17,6 @@ #include "../ir/EncodedTextAst.hpp" #include "../time_types.hpp" #include "SchemaTree.hpp" -#include "SchemaTreeNode.hpp" #include "Value.hpp" using clp::ir::EightByteEncodedTextAst; @@ -49,7 +48,7 @@ class JsonSerializationIterator { public: // Constructor JsonSerializationIterator( - SchemaTreeNode const* schema_tree_node, + SchemaTree::Node const* schema_tree_node, vector const& schema_subtree_bitmap, nlohmann::json::object_t* parent_json_obj, JsonExceptionHandler json_exception_callback @@ -76,7 +75,7 @@ class JsonSerializationIterator { try { // If the current node is the root, then replace the `parent` with this node's JSON // object. Otherwise, add this node's JSON object as a child of the parent JSON object. - if (m_schema_tree_node->get_id() == SchemaTree::cRootId) { + if (m_schema_tree_node->is_root()) { *m_parent_json_obj = std::move(m_json_obj); } else { m_parent_json_obj->emplace( @@ -100,16 +99,16 @@ class JsonSerializationIterator { * Gets the next child schema tree node and advances the iterator. * @return The next child schema tree node. */ - [[nodiscard]] auto get_next_child_schema_tree_node() -> SchemaTreeNode::id_t { + [[nodiscard]] auto get_next_child_schema_tree_node() -> SchemaTree::Node::id_t { return *(m_child_schema_tree_node_it++); } [[nodiscard]] auto get_json_obj() -> nlohmann::json::object_t& { return m_json_obj; } private: - SchemaTreeNode const* m_schema_tree_node; - vector m_child_schema_tree_nodes; - vector::const_iterator m_child_schema_tree_node_it; + SchemaTree::Node const* m_schema_tree_node; + vector m_child_schema_tree_nodes; + vector::const_iterator m_child_schema_tree_node_it; nlohmann::json::object_t* m_parent_json_obj; nlohmann::json::object_t m_json_obj; JsonExceptionHandler m_json_exception_callback; @@ -121,7 +120,7 @@ class JsonSerializationIterator { * @return Whether the given schema tree node type matches the given value's type. */ [[nodiscard]] auto -node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> bool; +node_type_matches_value_type(SchemaTree::Node::Type type, Value const& value) -> bool; /** * Validates whether the given node-ID value pairs are leaf nodes in the `SchemaTree` forming a @@ -150,7 +149,7 @@ node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> b */ [[nodiscard]] auto is_leaf_node( SchemaTree const& schema_tree, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs ) -> bool; @@ -176,7 +175,7 @@ node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> b * @return Whether the insertion was successful. */ [[nodiscard]] auto insert_kv_pair_into_json_obj( - SchemaTreeNode const& node, + SchemaTree::Node const& node, std::optional const& optional_val, nlohmann::json::object_t& json_obj ) -> bool; @@ -190,19 +189,19 @@ node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> b */ [[nodiscard]] auto decode_as_encoded_text_ast(Value const& val) -> std::optional; -auto node_type_matches_value_type(SchemaTreeNode::Type type, Value const& value) -> bool { +auto node_type_matches_value_type(SchemaTree::Node::Type type, Value const& value) -> bool { switch (type) { - case SchemaTreeNode::Type::Obj: + case SchemaTree::Node::Type::Obj: return value.is_null(); - case SchemaTreeNode::Type::Int: + case SchemaTree::Node::Type::Int: return value.is(); - case SchemaTreeNode::Type::Float: + case SchemaTree::Node::Type::Float: return value.is(); - case SchemaTreeNode::Type::Bool: + case SchemaTree::Node::Type::Bool: return value.is(); - case SchemaTreeNode::Type::UnstructuredArray: + case SchemaTree::Node::Type::UnstructuredArray: return value.is() || value.is(); - case SchemaTreeNode::Type::Str: + case SchemaTree::Node::Type::Str: return value.is() || value.is() || value.is(); default: @@ -215,25 +214,25 @@ auto validate_node_id_value_pairs( KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs ) -> std::errc { try { - std::unordered_map> + std::unordered_map> parent_node_id_to_key_names; for (auto const& [node_id, value] : node_id_value_pairs) { - if (SchemaTree::cRootId == node_id) { + auto const& node{schema_tree.get_node(node_id)}; + if (node.is_root()) { return std::errc::operation_not_permitted; } - auto const& node{schema_tree.get_node(node_id)}; auto const node_type{node.get_type()}; if (false == value.has_value()) { // Value is an empty object (`{}`, which is not the same as `null`) - if (SchemaTreeNode::Type::Obj != node_type) { + if (SchemaTree::Node::Type::Obj != node_type) { return std::errc::protocol_error; } } else if (false == node_type_matches_value_type(node_type, value.value())) { return std::errc::protocol_error; } - if (SchemaTreeNode::Type::Obj == node_type + if (SchemaTree::Node::Type::Obj == node_type && false == is_leaf_node(schema_tree, node_id, node_id_value_pairs)) { // The node's value is `null` or `{}` but its descendants appear in @@ -241,7 +240,9 @@ auto validate_node_id_value_pairs( return std::errc::operation_not_permitted; } - auto const parent_node_id{node.get_parent_id()}; + // We checked that the node isn't the root above, so we can query the underlying ID + // safely without a repeated check. + auto const parent_node_id{node.get_parent_id_unsafe()}; auto const key_name{node.get_key_name()}; if (parent_node_id_to_key_names.contains(parent_node_id)) { auto const [it, new_key_inserted]{ @@ -263,10 +264,10 @@ auto validate_node_id_value_pairs( auto is_leaf_node( SchemaTree const& schema_tree, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs ) -> bool { - vector dfs_stack; + vector dfs_stack; dfs_stack.reserve(schema_tree.get_size()); dfs_stack.push_back(node_id); while (false == dfs_stack.empty()) { @@ -294,24 +295,28 @@ auto get_schema_subtree_bitmap( schema_subtree_bitmap[node_id] = true; // Iteratively mark the parents as true - auto parent_id{schema_tree.get_node(node_id).get_parent_id()}; + auto optional_parent_id{schema_tree.get_node(node_id).get_parent_id()}; while (true) { + // Ideally, we'd use this if statement as the loop condition, but clang-tidy will + // complain about an unchecked `optional` access. + if (false == optional_parent_id.has_value()) { + // Reached the root + break; + } + auto const parent_id{optional_parent_id.value()}; if (schema_subtree_bitmap[parent_id]) { // Parent already set by other child break; } schema_subtree_bitmap[parent_id] = true; - if (SchemaTree::cRootId == parent_id) { - break; - } - parent_id = schema_tree.get_node(parent_id).get_parent_id(); + optional_parent_id = schema_tree.get_node(parent_id).get_parent_id(); } } return schema_subtree_bitmap; } auto insert_kv_pair_into_json_obj( - SchemaTreeNode const& node, + SchemaTree::Node const& node, std::optional const& optional_val, nlohmann::json::object_t& json_obj ) -> bool { @@ -325,16 +330,16 @@ auto insert_kv_pair_into_json_obj( try { auto const& val{optional_val.value()}; switch (type) { - case SchemaTreeNode::Type::Int: + case SchemaTree::Node::Type::Int: json_obj.emplace(key_name, val.get_immutable_view()); break; - case SchemaTreeNode::Type::Float: + case SchemaTree::Node::Type::Float: json_obj.emplace(key_name, val.get_immutable_view()); break; - case SchemaTreeNode::Type::Bool: + case SchemaTree::Node::Type::Bool: json_obj.emplace(key_name, val.get_immutable_view()); break; - case SchemaTreeNode::Type::Str: + case SchemaTree::Node::Type::Str: if (val.is()) { json_obj.emplace(key_name, string{val.get_immutable_view()}); } else { @@ -345,7 +350,7 @@ auto insert_kv_pair_into_json_obj( json_obj.emplace(key_name, decoded_result.value()); } break; - case SchemaTreeNode::Type::UnstructuredArray: { + case SchemaTree::Node::Type::UnstructuredArray: { auto const decoded_result{decode_as_encoded_text_ast(val)}; if (false == decoded_result.has_value()) { return false; @@ -353,7 +358,7 @@ auto insert_kv_pair_into_json_obj( json_obj.emplace(key_name, nlohmann::json::parse(decoded_result.value())); break; } - case SchemaTreeNode::Type::Obj: + case SchemaTree::Node::Type::Obj: json_obj.emplace(key_name, nullptr); break; default: @@ -421,7 +426,7 @@ auto KeyValuePairLogEvent::serialize_to_json( // // On the way up, add the current node's `nlohmann::json::object_t` to the parent's // `nlohmann::json::object_t`. - auto const& root_schema_tree_node{m_schema_tree->get_node(SchemaTree::cRootId)}; + auto const& root_schema_tree_node{m_schema_tree->get_root()}; auto root_json_obj = nlohmann::json::object_t(); dfs_stack.emplace( diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp index 120588569..04fd31c9e 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp @@ -11,7 +11,6 @@ #include "../time_types.hpp" #include "SchemaTree.hpp" -#include "SchemaTreeNode.hpp" #include "Value.hpp" namespace clp::ffi { @@ -25,7 +24,7 @@ namespace clp::ffi { class KeyValuePairLogEvent { public: // Types - using NodeIdValuePairs = std::unordered_map>; + using NodeIdValuePairs = std::unordered_map>; // Factory functions /** diff --git a/components/core/src/clp/ffi/SchemaTree.cpp b/components/core/src/clp/ffi/SchemaTree.cpp index 5cc45ac65..08c1c4169 100644 --- a/components/core/src/clp/ffi/SchemaTree.cpp +++ b/components/core/src/clp/ffi/SchemaTree.cpp @@ -5,10 +5,9 @@ #include #include "../ErrorCode.hpp" -#include "SchemaTreeNode.hpp" namespace clp::ffi { -auto SchemaTree::get_node(SchemaTreeNode::id_t id) const -> SchemaTreeNode const& { +auto SchemaTree::get_node(Node::id_t id) const -> Node const& { if (m_tree_nodes.size() <= static_cast(id)) { throw OperationFailed( ErrorCode_OutOfBounds, @@ -20,13 +19,12 @@ auto SchemaTree::get_node(SchemaTreeNode::id_t id) const -> SchemaTreeNode const return m_tree_nodes[id]; } -auto SchemaTree::try_get_node_id(NodeLocator const& locator -) const -> std::optional { +auto SchemaTree::try_get_node_id(NodeLocator const& locator) const -> std::optional { auto const parent_id{static_cast(locator.get_parent_id())}; if (m_tree_nodes.size() <= parent_id) { - return false; + return std::nullopt; } - std::optional node_id; + std::optional node_id; for (auto const child_id : m_tree_nodes[parent_id].get_children_ids()) { auto const& node{m_tree_nodes[child_id]}; if (node.get_key_name() == locator.get_key_name() && node.get_type() == locator.get_type()) @@ -38,19 +36,14 @@ auto SchemaTree::try_get_node_id(NodeLocator const& locator return node_id; } -auto SchemaTree::insert_node(NodeLocator const& locator) -> SchemaTreeNode::id_t { +auto SchemaTree::insert_node(NodeLocator const& locator) -> Node::id_t { if (try_get_node_id(locator).has_value()) { throw OperationFailed(ErrorCode_Failure, __FILE__, __LINE__, "Node already exists."); } - auto const node_id{static_cast(m_tree_nodes.size())}; - m_tree_nodes.emplace_back( - node_id, - locator.get_parent_id(), - locator.get_key_name(), - locator.get_type() - ); + auto const node_id{static_cast(m_tree_nodes.size())}; + m_tree_nodes.emplace_back(Node::create(node_id, locator)); auto& parent_node{m_tree_nodes[locator.get_parent_id()]}; - if (SchemaTreeNode::Type::Obj != parent_node.get_type()) { + if (Node::Type::Obj != parent_node.get_type()) { throw OperationFailed( ErrorCode_Failure, __FILE__, @@ -68,7 +61,10 @@ auto SchemaTree::revert() -> void { } while (m_tree_nodes.size() != m_snapshot_size) { auto const& node{m_tree_nodes.back()}; - m_tree_nodes[node.get_parent_id()].remove_last_appended_child(); + auto const optional_parent_id{node.get_parent_id()}; + if (optional_parent_id.has_value()) { + m_tree_nodes[optional_parent_id.value()].remove_last_appended_child(); + } m_tree_nodes.pop_back(); } m_snapshot_size.reset(); diff --git a/components/core/src/clp/ffi/SchemaTree.hpp b/components/core/src/clp/ffi/SchemaTree.hpp index 5b07e8a09..46494fa71 100644 --- a/components/core/src/clp/ffi/SchemaTree.hpp +++ b/components/core/src/clp/ffi/SchemaTree.hpp @@ -2,6 +2,7 @@ #define CLP_FFI_SCHEMATREE_HPP #include +#include #include #include #include @@ -10,7 +11,6 @@ #include "../ErrorCode.hpp" #include "../TraceableException.hpp" -#include "SchemaTreeNode.hpp" namespace clp::ffi { /** @@ -91,6 +91,122 @@ class SchemaTree { std::string m_message; }; + // Forward declared types + class Node; + class NodeLocator; + + /** + * A node in clp::ffi::SchemaTree. It stores the node's key name, type, parent's ID, and the IDs + * of all its children. + */ + class Node { + public: + // Types + using id_t = uint32_t; + + /** + * Enum defining the possible node types. + */ + enum class Type : uint8_t { + Int = 0, + Float, + Bool, + Str, + UnstructuredArray, + Obj + }; + + // Disable copy constructor/assignment operator + Node(Node const&) = delete; + auto operator=(Node const&) -> Node& = delete; + + // Define default move constructor/assignment operator + Node(Node&&) = default; + auto operator=(Node&&) -> Node& = default; + + // Destructor + ~Node() = default; + + // Methods + [[nodiscard]] auto get_id() const -> id_t { return m_id; } + + [[nodiscard]] auto is_root() const -> bool { return false == m_parent_id.has_value(); } + + /** + * @return The ID of the parent node in the schema tree, if the node is not the root. + * @return std::nullopt if the node is the root. + */ + [[nodiscard]] auto get_parent_id() const -> std::optional { return m_parent_id; } + + /** + * Gets the parent ID without checking if it's `std::nullopt`. + * NOTE: This method should only be used if the caller has checked the node is not the root. + * @return The ID of the parent node in the schema tree. + */ + [[nodiscard]] auto get_parent_id_unsafe() const -> id_t { + // NOLINTNEXTLINE(bugprone-unchecked-optional-access) + return m_parent_id.value(); + } + + [[nodiscard]] auto get_key_name() const -> std::string_view { return m_key_name; } + + [[nodiscard]] auto get_type() const -> Type { return m_type; } + + [[nodiscard]] auto get_children_ids() const -> std::vector const& { + return m_children_ids; + } + + /** + * Appends a child using its node ID. + * NOTE: This method doesn't check if a child with the given ID already exists. + * @param child_id The child node's ID. + */ + auto append_new_child(id_t child_id) -> void { m_children_ids.push_back(child_id); } + + /** + * Removes the last appended child ID (if any). + */ + auto remove_last_appended_child() -> void { + if (m_children_ids.empty()) { + return; + } + m_children_ids.pop_back(); + } + + private: + friend SchemaTree; + + // Factory functions + /** + * Creates a non-root tree node. + * @param id + * @param locator + */ + [[nodiscard]] static auto create(id_t id, NodeLocator const& locator) -> Node { + return {id, locator.get_parent_id(), locator.get_key_name(), locator.get_type()}; + } + + /** + * Creates a root node. + */ + [[nodiscard]] static auto create_root() -> Node { + return {cRootId, std::nullopt, {}, Type::Obj}; + } + + // Constructors + Node(id_t id, std::optional parent_id, std::string_view key_name, Type type) + : m_id{id}, + m_parent_id{parent_id}, + m_key_name{key_name.begin(), key_name.end()}, + m_type{type} {} + + id_t m_id; + std::optional m_parent_id; + std::vector m_children_ids; + std::string m_key_name; + Type m_type; + }; + /** * A triple---parent ID, key name, and node type---that uniquely identifies a node. * NOTE: We use the term "Locator" to avoid terms like "Key" or "Identifier" that are already in @@ -98,32 +214,28 @@ class SchemaTree { */ class NodeLocator { public: - NodeLocator( - SchemaTreeNode::id_t parent_id, - std::string_view key_name, - SchemaTreeNode::Type type - ) + NodeLocator(Node::id_t parent_id, std::string_view key_name, Node::Type type) : m_parent_id{parent_id}, m_key_name{key_name}, m_type{type} {} - [[nodiscard]] auto get_parent_id() const -> SchemaTreeNode::id_t { return m_parent_id; } + [[nodiscard]] auto get_parent_id() const -> Node::id_t { return m_parent_id; } [[nodiscard]] auto get_key_name() const -> std::string_view { return m_key_name; } - [[nodiscard]] auto get_type() const -> SchemaTreeNode::Type { return m_type; } + [[nodiscard]] auto get_type() const -> Node::Type { return m_type; } private: - SchemaTreeNode::id_t m_parent_id; + Node::id_t m_parent_id; std::string_view m_key_name; - SchemaTreeNode::Type m_type; + Node::Type m_type; }; // Constants - static constexpr SchemaTreeNode::id_t cRootId{0}; + static constexpr Node::id_t cRootId{0}; // Constructors - SchemaTree() { m_tree_nodes.emplace_back(cRootId, cRootId, "", SchemaTreeNode::Type::Obj); } + SchemaTree() { m_tree_nodes.emplace_back(Node::create_root()); } // Disable copy constructor/assignment operator SchemaTree(SchemaTree const&) = delete; @@ -139,12 +251,14 @@ class SchemaTree { // Methods [[nodiscard]] auto get_size() const -> size_t { return m_tree_nodes.size(); } + [[nodiscard]] auto get_root() const -> Node const& { return m_tree_nodes[cRootId]; } + /** * @param id * @return The node with the given ID. * @throw OperationFailed if a node with the given ID doesn't exist in the tree. */ - [[nodiscard]] auto get_node(SchemaTreeNode::id_t id) const -> SchemaTreeNode const&; + [[nodiscard]] auto get_node(Node::id_t id) const -> Node const&; /** * Tries to get the ID of a node corresponding to the given locator, if the node exists. @@ -153,7 +267,7 @@ class SchemaTree { * @return std::nullopt otherwise. */ [[nodiscard]] auto try_get_node_id(NodeLocator const& locator - ) const -> std::optional; + ) const -> std::optional; /** * @param locator @@ -171,7 +285,7 @@ class SchemaTree { * - a node that corresponds to the given locator already exists. * - the parent node identified by the locator is not an object. */ - [[maybe_unused]] auto insert_node(NodeLocator const& locator) -> SchemaTreeNode::id_t; + [[maybe_unused]] auto insert_node(NodeLocator const& locator) -> Node::id_t; /** * Takes a snapshot of the current schema tree (to allow recovery on failure). @@ -184,18 +298,10 @@ class SchemaTree { */ auto revert() -> void; - /** - * Resets the schema tree by removing all nodes except the root. - */ - auto reset() -> void { - m_snapshot_size.reset(); - m_tree_nodes.clear(); - m_tree_nodes.emplace_back(cRootId, cRootId, "", SchemaTreeNode::Type::Obj); - } - private: + // Variables std::optional m_snapshot_size; - std::vector m_tree_nodes; + std::vector m_tree_nodes; }; } // namespace clp::ffi #endif diff --git a/components/core/src/clp/ffi/SchemaTreeNode.hpp b/components/core/src/clp/ffi/SchemaTreeNode.hpp deleted file mode 100644 index 7bbe2a06a..000000000 --- a/components/core/src/clp/ffi/SchemaTreeNode.hpp +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef CLP_FFI_SCHEMATREENODE_HPP -#define CLP_FFI_SCHEMATREENODE_HPP - -#include -#include -#include -#include - -namespace clp::ffi { -/** - * A node in clp::ffi::SchemaTree. It stores the node's key name, type, parent's ID, and the IDs of - * all its children. - */ -class SchemaTreeNode { -public: - // Types - using id_t = uint32_t; - - /** - * Enum defining the possible node types. - */ - enum class Type : uint8_t { - Int = 0, - Float, - Bool, - Str, - UnstructuredArray, - Obj - }; - - // Constructors - SchemaTreeNode(id_t id, id_t parent_id, std::string_view key_name, Type type) - : m_id{id}, - m_parent_id{parent_id}, - m_key_name{key_name.begin(), key_name.end()}, - m_type{type} {} - - // Disable copy constructor/assignment operator - SchemaTreeNode(SchemaTreeNode const&) = delete; - auto operator=(SchemaTreeNode const&) -> SchemaTreeNode& = delete; - - // Define default move constructor/assignment operator - SchemaTreeNode(SchemaTreeNode&&) = default; - auto operator=(SchemaTreeNode&&) -> SchemaTreeNode& = default; - - // Destructor - ~SchemaTreeNode() = default; - - // Methods - [[nodiscard]] auto get_id() const -> id_t { return m_id; } - - [[nodiscard]] auto get_parent_id() const -> id_t { return m_parent_id; } - - [[nodiscard]] auto get_key_name() const -> std::string_view { return m_key_name; } - - [[nodiscard]] auto get_type() const -> Type { return m_type; } - - [[nodiscard]] auto get_children_ids() const -> std::vector const& { - return m_children_ids; - } - - /** - * Appends a child using its node ID. - * NOTE: This method doesn't check if a child with the given ID already exists. - * @param child_id The child node's ID. - */ - auto append_new_child(id_t child_id) -> void { m_children_ids.push_back(child_id); } - - /** - * Removes the last appended child ID (if any). - */ - auto remove_last_appended_child() -> void { - if (m_children_ids.empty()) { - return; - } - m_children_ids.pop_back(); - } - -private: - id_t m_id; - id_t m_parent_id; - std::vector m_children_ids; - std::string m_key_name; - Type m_type; -}; -} // namespace clp::ffi - -#endif diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp index 5a9325553..e86b45078 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -19,7 +19,6 @@ #include "../../type_utils.hpp" #include "../encoding_methods.hpp" #include "../SchemaTree.hpp" -#include "../SchemaTreeNode.hpp" #include "encoding_methods.hpp" #include "protocol_constants.hpp" #include "utils.hpp" @@ -44,7 +43,7 @@ class MsgpackMapIterator { using Child = msgpack::object_kv; // Constructors - MsgpackMapIterator(SchemaTreeNode::id_t schema_tree_node_id, span children) + MsgpackMapIterator(SchemaTree::Node::id_t schema_tree_node_id, span children) : m_schema_tree_node_id{schema_tree_node_id}, m_children{children}, m_curr_child_it{m_children.begin()} {} @@ -53,7 +52,7 @@ class MsgpackMapIterator { /** * @return This map's ID in the schema tree. */ - [[nodiscard]] auto get_schema_tree_node_id() const -> SchemaTreeNode::id_t { + [[nodiscard]] auto get_schema_tree_node_id() const -> SchemaTree::Node::id_t { return m_schema_tree_node_id; } @@ -71,7 +70,7 @@ class MsgpackMapIterator { [[nodiscard]] auto get_next_child() -> Child const& { return *(m_curr_child_it++); } private: - SchemaTreeNode::id_t m_schema_tree_node_id; + SchemaTree::Node::id_t m_schema_tree_node_id; span m_children; span::iterator m_curr_child_it; }; @@ -83,7 +82,7 @@ class MsgpackMapIterator { * @return std::nullopt if the value doesn't match any of the supported schema-tree node types. */ [[nodiscard]] auto get_schema_tree_node_type_from_msgpack_val(msgpack::object const& val -) -> optional; +) -> optional; /** * Serializes an empty object. @@ -147,29 +146,29 @@ template ) -> bool; auto get_schema_tree_node_type_from_msgpack_val(msgpack::object const& val -) -> optional { - optional ret_val; +) -> optional { + optional ret_val; switch (val.type) { case msgpack::type::POSITIVE_INTEGER: case msgpack::type::NEGATIVE_INTEGER: - ret_val.emplace(SchemaTreeNode::Type::Int); + ret_val.emplace(SchemaTree::Node::Type::Int); break; case msgpack::type::FLOAT32: case msgpack::type::FLOAT64: - ret_val.emplace(SchemaTreeNode::Type::Float); + ret_val.emplace(SchemaTree::Node::Type::Float); break; case msgpack::type::STR: - ret_val.emplace(SchemaTreeNode::Type::Str); + ret_val.emplace(SchemaTree::Node::Type::Str); break; case msgpack::type::BOOLEAN: - ret_val.emplace(SchemaTreeNode::Type::Bool); + ret_val.emplace(SchemaTree::Node::Type::Bool); break; case msgpack::type::NIL: case msgpack::type::MAP: - ret_val.emplace(SchemaTreeNode::Type::Obj); + ret_val.emplace(SchemaTree::Node::Type::Obj); break; case msgpack::type::ARRAY: - ret_val.emplace(SchemaTreeNode::Type::UnstructuredArray); + ret_val.emplace(SchemaTree::Node::Type::UnstructuredArray); break; default: return std::nullopt; @@ -381,22 +380,22 @@ auto Serializer::serialize_schema_tree_node( SchemaTree::NodeLocator const& locator ) -> bool { switch (locator.get_type()) { - case SchemaTreeNode::Type::Int: + case SchemaTree::Node::Type::Int: m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeInt); break; - case SchemaTreeNode::Type::Float: + case SchemaTree::Node::Type::Float: m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeFloat); break; - case SchemaTreeNode::Type::Bool: + case SchemaTree::Node::Type::Bool: m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeBool); break; - case SchemaTreeNode::Type::Str: + case SchemaTree::Node::Type::Str: m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeStr); break; - case SchemaTreeNode::Type::UnstructuredArray: + case SchemaTree::Node::Type::UnstructuredArray: m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeUnstructuredArray); break; - case SchemaTreeNode::Type::Obj: + case SchemaTree::Node::Type::Obj: m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeObj); break; default: @@ -420,7 +419,7 @@ auto Serializer::serialize_schema_tree_node( } template -auto Serializer::serialize_key(SchemaTreeNode::id_t id) -> bool { +auto Serializer::serialize_key(SchemaTree::Node::id_t id) -> bool { if (id <= UINT8_MAX) { m_key_group_buf.push_back(cProtocol::Payload::KeyIdUByte); m_key_group_buf.push_back(bit_cast(static_cast(id))); @@ -436,10 +435,10 @@ auto Serializer::serialize_key(SchemaTreeNode::id_t id) -> b template auto Serializer::serialize_val( msgpack::object const& val, - SchemaTreeNode::Type schema_tree_node_type + SchemaTree::Node::Type schema_tree_node_type ) -> bool { switch (schema_tree_node_type) { - case SchemaTreeNode::Type::Int: + case SchemaTree::Node::Type::Int: if (msgpack::type::POSITIVE_INTEGER == val.type && static_cast(INT64_MAX) < val.as()) { @@ -448,15 +447,15 @@ auto Serializer::serialize_val( serialize_value_int(val.as(), m_value_group_buf); break; - case SchemaTreeNode::Type::Float: + case SchemaTree::Node::Type::Float: serialize_value_float(val.as(), m_value_group_buf); break; - case SchemaTreeNode::Type::Bool: + case SchemaTree::Node::Type::Bool: serialize_value_bool(val.as(), m_value_group_buf); break; - case SchemaTreeNode::Type::Str: + case SchemaTree::Node::Type::Str: if (false == serialize_value_string( val.as(), @@ -468,14 +467,14 @@ auto Serializer::serialize_val( } break; - case SchemaTreeNode::Type::Obj: + case SchemaTree::Node::Type::Obj: if (msgpack::type::NIL != val.type) { return false; } serialize_value_null(m_value_group_buf); break; - case SchemaTreeNode::Type::UnstructuredArray: + case SchemaTree::Node::Type::UnstructuredArray: if (false == serialize_value_array(val, m_logtype_buf, m_value_group_buf)) { @@ -516,17 +515,17 @@ template auto Serializer::serialize_schema_tree_no SchemaTree::NodeLocator const& locator ) -> bool; -template auto Serializer::serialize_key(SchemaTreeNode::id_t id +template auto Serializer::serialize_key(SchemaTree::Node::id_t id ) -> bool; -template auto Serializer::serialize_key(SchemaTreeNode::id_t id +template auto Serializer::serialize_key(SchemaTree::Node::id_t id ) -> bool; template auto Serializer::serialize_val( msgpack::object const& val, - SchemaTreeNode::Type schema_tree_node_type + SchemaTree::Node::Type schema_tree_node_type ) -> bool; template auto Serializer::serialize_val( msgpack::object const& val, - SchemaTreeNode::Type schema_tree_node_type + SchemaTree::Node::Type schema_tree_node_type ) -> bool; } // namespace clp::ffi::ir_stream diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp index 950d8481f..dca9604db 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -11,7 +11,6 @@ #include "../../time_types.hpp" #include "../SchemaTree.hpp" -#include "../SchemaTreeNode.hpp" namespace clp::ffi::ir_stream { /** @@ -107,7 +106,7 @@ class Serializer { * @return true on success. * @return false if the ID exceeds the representable range. */ - [[nodiscard]] auto serialize_key(SchemaTreeNode::id_t id) -> bool; + [[nodiscard]] auto serialize_key(SchemaTree::Node::id_t id) -> bool; /** * Serializes the given MessagePack value into `m_value_group_buf`. @@ -116,7 +115,7 @@ class Serializer { * @return Whether serialization succeeded. */ [[nodiscard]] auto - serialize_val(msgpack::object const& val, SchemaTreeNode::Type schema_tree_node_type) -> bool; + serialize_val(msgpack::object const& val, SchemaTree::Node::Type schema_tree_node_type) -> bool; UtcOffset m_curr_utc_offset{0}; Buffer m_ir_buf; diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp index 3e9986d46..d475ad196 100644 --- a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp @@ -19,7 +19,6 @@ #include "../../type_utils.hpp" #include "../KeyValuePairLogEvent.hpp" #include "../SchemaTree.hpp" -#include "../SchemaTreeNode.hpp" #include "../Value.hpp" #include "decoding_methods.hpp" #include "IrUnitType.hpp" @@ -31,7 +30,7 @@ namespace { /** * A collection of schema tree leaf node IDs. It represents the schema of a `KeyValuePairLogEvent`. */ -using Schema = std::vector; +using Schema = std::vector; /** * @param tag @@ -39,7 +38,7 @@ using Schema = std::vector; * @return std::nullopt if the tag doesn't match to any defined schema tree node type. */ [[nodiscard]] auto schema_tree_node_tag_to_type(encoded_tag_t tag -) -> std::optional; +) -> std::optional; /** * Deserializes the parent ID of a schema tree node. @@ -52,7 +51,7 @@ using Schema = std::vector; */ [[nodiscard]] auto deserialize_schema_tree_node_parent_id( ReaderInterface& reader, - SchemaTreeNode::id_t& parent_id + SchemaTree::Node::id_t& parent_id ) -> IRErrorCode; /** @@ -125,7 +124,7 @@ deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) [[nodiscard]] auto deserialize_value_and_insert_to_node_id_value_pairs( ReaderInterface& reader, encoded_tag_t tag, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs ) -> IRErrorCode; @@ -145,7 +144,7 @@ requires(std::is_same_v || std::is_same_v) [[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( ReaderInterface& reader, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs ) -> IRErrorCode; @@ -175,20 +174,20 @@ requires(std::is_same_v */ [[nodiscard]] auto is_log_event_ir_unit_tag(encoded_tag_t tag) -> bool; -auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { +auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { switch (tag) { case cProtocol::Payload::SchemaTreeNodeInt: - return SchemaTreeNode::Type::Int; + return SchemaTree::Node::Type::Int; case cProtocol::Payload::SchemaTreeNodeFloat: - return SchemaTreeNode::Type::Float; + return SchemaTree::Node::Type::Float; case cProtocol::Payload::SchemaTreeNodeBool: - return SchemaTreeNode::Type::Bool; + return SchemaTree::Node::Type::Bool; case cProtocol::Payload::SchemaTreeNodeStr: - return SchemaTreeNode::Type::Str; + return SchemaTree::Node::Type::Str; case cProtocol::Payload::SchemaTreeNodeUnstructuredArray: - return SchemaTreeNode::Type::UnstructuredArray; + return SchemaTree::Node::Type::UnstructuredArray; case cProtocol::Payload::SchemaTreeNodeObj: - return SchemaTreeNode::Type::Obj; + return SchemaTree::Node::Type::Obj; default: return std::nullopt; } @@ -196,7 +195,7 @@ auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional IRErrorCode { encoded_tag_t tag{}; if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { @@ -207,13 +206,13 @@ auto deserialize_schema_tree_node_parent_id( if (false == deserialize_int(reader, deserialized_id)) { return IRErrorCode::IRErrorCode_Incomplete_IR; } - parent_id = static_cast(deserialized_id); + parent_id = static_cast(deserialized_id); } else if (cProtocol::Payload::SchemaTreeNodeParentIdUShort == tag) { uint16_t deserialized_id{}; if (false == deserialize_int(reader, deserialized_id)) { return IRErrorCode::IRErrorCode_Incomplete_IR; } - parent_id = static_cast(deserialized_id); + parent_id = static_cast(deserialized_id); } else { return IRErrorCode::IRErrorCode_Corrupted_IR; } @@ -307,13 +306,13 @@ auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& sch if (false == deserialize_int(reader, id)) { return IRErrorCode::IRErrorCode_Incomplete_IR; } - schema.push_back(static_cast(id)); + schema.push_back(static_cast(id)); } else if (cProtocol::Payload::KeyIdUShort == tag) { uint16_t id{}; if (false == deserialize_int(reader, id)) { return IRErrorCode::IRErrorCode_Incomplete_IR; } - schema.push_back(static_cast(id)); + schema.push_back(static_cast(id)); } else { break; } @@ -329,7 +328,7 @@ auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& sch auto deserialize_value_and_insert_to_node_id_value_pairs( ReaderInterface& reader, encoded_tag_t tag, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs ) -> IRErrorCode { switch (tag) { @@ -405,7 +404,7 @@ requires(std::is_same_v || std::is_same_v) [[nodiscard]] auto deserialize_encoded_text_ast_and_insert_to_node_id_value_pairs( ReaderInterface& reader, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs& node_id_value_pairs ) -> IRErrorCode { encoded_tag_t tag{}; @@ -509,7 +508,7 @@ auto deserialize_ir_unit_schema_tree_node_insertion( return ir_error_code_to_errc(IRErrorCode::IRErrorCode_Corrupted_IR); } - SchemaTreeNode::id_t parent_id{}; + SchemaTree::Node::id_t parent_id{}; if (auto const err{deserialize_schema_tree_node_parent_id(reader, parent_id)}; IRErrorCode_Success != err) { diff --git a/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp b/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp index 976cb259a..5b8ad82cd 100644 --- a/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp +++ b/components/core/tests/test-ffi_IrUnitHandlerInterface.cpp @@ -9,14 +9,12 @@ #include "../src/clp/ffi/ir_stream/IrUnitHandlerInterface.hpp" #include "../src/clp/ffi/KeyValuePairLogEvent.hpp" #include "../src/clp/ffi/SchemaTree.hpp" -#include "../src/clp/ffi/SchemaTreeNode.hpp" #include "../src/clp/time_types.hpp" namespace { using clp::ffi::ir_stream::IRErrorCode; using clp::ffi::KeyValuePairLogEvent; using clp::ffi::SchemaTree; -using clp::ffi::SchemaTreeNode; using clp::UtcOffset; constexpr UtcOffset cTestUtcOffset{100}; @@ -107,7 +105,7 @@ auto test_ir_unit_handler_interface(clp::ffi::ir_stream::IrUnitHandlerInterface REQUIRE( (IRErrorCode::IRErrorCode_Success == handler.handle_schema_tree_node_insertion( - {SchemaTree::cRootId, cTestSchemaTreeNodeKeyName, SchemaTreeNode::Type::Obj} + {SchemaTree::cRootId, cTestSchemaTreeNodeKeyName, SchemaTree::Node::Type::Obj} )) ); REQUIRE((IRErrorCode::IRErrorCode_Success == handler.handle_end_of_stream())); diff --git a/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp b/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp index 4820a5af1..2e9cfb691 100644 --- a/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp +++ b/components/core/tests/test-ffi_KeyValuePairLogEvent.cpp @@ -15,7 +15,6 @@ #include "../src/clp/ffi/encoding_methods.hpp" #include "../src/clp/ffi/KeyValuePairLogEvent.hpp" #include "../src/clp/ffi/SchemaTree.hpp" -#include "../src/clp/ffi/SchemaTreeNode.hpp" #include "../src/clp/ffi/Value.hpp" #include "../src/clp/ir/EncodedTextAst.hpp" #include "../src/clp/ir/types.hpp" @@ -23,7 +22,6 @@ using clp::ffi::KeyValuePairLogEvent; using clp::ffi::SchemaTree; -using clp::ffi::SchemaTreeNode; using clp::ffi::Value; using clp::ffi::value_bool_t; using clp::ffi::value_float_t; @@ -79,7 +77,7 @@ auto test_value_get_immutable_view(Value const& value, Type const& typed_value) */ auto insert_invalid_node_id_value_pairs_with_node_type_errors( SchemaTree const& schema_tree, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs& invalid_node_id_value_pairs ) -> void; @@ -167,23 +165,23 @@ auto test_value_get_immutable_view(Value const& value, Type const& typed_value) auto insert_invalid_node_id_value_pairs_with_node_type_errors( SchemaTree const& schema_tree, - SchemaTreeNode::id_t node_id, + SchemaTree::Node::id_t node_id, KeyValuePairLogEvent::NodeIdValuePairs& invalid_node_id_value_pairs ) -> void { REQUIRE((node_id < schema_tree.get_size())); auto const node_type{schema_tree.get_node(node_id).get_type()}; - if (SchemaTreeNode::Type::Int != node_type) { + if (SchemaTree::Node::Type::Int != node_type) { invalid_node_id_value_pairs.emplace(node_id, Value{static_cast(0)}); } - if (SchemaTreeNode::Type::Float != node_type) { + if (SchemaTree::Node::Type::Float != node_type) { invalid_node_id_value_pairs.emplace(node_id, Value{static_cast(0.0)}); } - if (SchemaTreeNode::Type::Bool != node_type) { + if (SchemaTree::Node::Type::Bool != node_type) { invalid_node_id_value_pairs.emplace(node_id, Value{static_cast(false)}); } - if (SchemaTreeNode::Type::Str != node_type) { + if (SchemaTree::Node::Type::Str != node_type) { invalid_node_id_value_pairs.emplace(node_id, Value{static_cast("Test")}); - if (SchemaTreeNode::Type::UnstructuredArray != node_type) { + if (SchemaTree::Node::Type::UnstructuredArray != node_type) { invalid_node_id_value_pairs.emplace( node_id, Value{get_encoded_text_ast(cStringToEncode)} @@ -194,7 +192,7 @@ auto insert_invalid_node_id_value_pairs_with_node_type_errors( ); } } - if (SchemaTreeNode::Type::Obj != node_type) { + if (SchemaTree::Node::Type::Obj != node_type) { invalid_node_id_value_pairs.emplace(node_id, std::nullopt); invalid_node_id_value_pairs.emplace(node_id, Value{}); } @@ -266,17 +264,17 @@ TEST_CASE("ffi_KeyValuePairLogEvent_create", "[ffi]") { */ auto const schema_tree{std::make_shared()}; std::vector const locators{ - {SchemaTree::cRootId, "a", SchemaTreeNode::Type::Obj}, - {SchemaTree::cRootId, "a", SchemaTreeNode::Type::Int}, - {1, "b", SchemaTreeNode::Type::Obj}, - {3, "c", SchemaTreeNode::Type::Obj}, - {3, "d", SchemaTreeNode::Type::Str}, - {3, "d", SchemaTreeNode::Type::Bool}, - {4, "a", SchemaTreeNode::Type::UnstructuredArray}, - {4, "d", SchemaTreeNode::Type::Str}, - {4, "d", SchemaTreeNode::Type::Float}, - {3, "e", SchemaTreeNode::Type::Obj}, - {4, "f", SchemaTreeNode::Type::Obj} + {SchemaTree::cRootId, "a", SchemaTree::Node::Type::Obj}, + {SchemaTree::cRootId, "a", SchemaTree::Node::Type::Int}, + {1, "b", SchemaTree::Node::Type::Obj}, + {3, "c", SchemaTree::Node::Type::Obj}, + {3, "d", SchemaTree::Node::Type::Str}, + {3, "d", SchemaTree::Node::Type::Bool}, + {4, "a", SchemaTree::Node::Type::UnstructuredArray}, + {4, "d", SchemaTree::Node::Type::Str}, + {4, "d", SchemaTree::Node::Type::Float}, + {3, "e", SchemaTree::Node::Type::Obj}, + {4, "f", SchemaTree::Node::Type::Obj} }; for (auto const& locator : locators) { REQUIRE_NOTHROW(schema_tree->insert_node(locator)); @@ -439,7 +437,7 @@ TEST_CASE("ffi_KeyValuePairLogEvent_create", "[ffi]") { SECTION("Test out-of-bound node ID") { KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs_out_of_bound; node_id_value_pairs_out_of_bound.emplace( - static_cast(schema_tree->get_size()), + static_cast(schema_tree->get_size()), Value{} ); auto const out_of_bound_result{KeyValuePairLogEvent::create( diff --git a/components/core/tests/test-ffi_SchemaTree.cpp b/components/core/tests/test-ffi_SchemaTree.cpp index bbae502e6..2808e03c0 100644 --- a/components/core/tests/test-ffi_SchemaTree.cpp +++ b/components/core/tests/test-ffi_SchemaTree.cpp @@ -1,14 +1,11 @@ -#include #include #include #include #include "../src/clp/ffi/SchemaTree.hpp" -#include "../src/clp/ffi/SchemaTreeNode.hpp" using clp::ffi::SchemaTree; -using clp::ffi::SchemaTreeNode; namespace { /** @@ -19,41 +16,63 @@ namespace { */ [[nodiscard]] auto insert_node( SchemaTree& schema_tree, - SchemaTree::NodeLocator locator, - SchemaTreeNode::id_t expected_id + SchemaTree::NodeLocator const& locator, + SchemaTree::Node::id_t expected_id ) -> bool; /** * @param schema_tree * @param locator * @param expected_id - * @return Whether the node exists and its ID matches the expected ID. + * @return Whether an ID could be found for a non root node matching the locator, the ID matches the + * expected ID, the corresponding node is not the root, and it matches the locator. */ -[[nodiscard]] auto check_node( +[[nodiscard]] auto check_non_root_node( SchemaTree const& schema_tree, - SchemaTree::NodeLocator locator, - SchemaTreeNode::id_t expected_id + SchemaTree::NodeLocator const& locator, + SchemaTree::Node::id_t expected_id ) -> bool; auto insert_node( SchemaTree& schema_tree, - SchemaTree::NodeLocator locator, - SchemaTreeNode::id_t expected_id + SchemaTree::NodeLocator const& locator, + SchemaTree::Node::id_t expected_id ) -> bool { return false == schema_tree.has_node(locator) && expected_id == schema_tree.insert_node(locator); } -auto check_node( +auto check_non_root_node( SchemaTree const& schema_tree, - SchemaTree::NodeLocator locator, - SchemaTreeNode::id_t expected_id + SchemaTree::NodeLocator const& locator, + SchemaTree::Node::id_t expected_id ) -> bool { auto const node_id{schema_tree.try_get_node_id(locator)}; - return node_id.has_value() && node_id.value() == expected_id; + if (false == node_id.has_value() || node_id.value() != expected_id) { + // The node's ID doesn't match. + return false; + } + auto const& node{schema_tree.get_node(expected_id)}; + if (node.is_root()) { + // Any nodes added after the tree was constructed must not be the root. + return false; + } + auto const optional_parent_id{node.get_parent_id()}; + if (false == optional_parent_id.has_value()) { + // Non-root nodes must have a parent ID. + return false; + } + if (optional_parent_id.value() != locator.get_parent_id() + || node.get_type() != locator.get_type() || node.get_key_name() != locator.get_key_name()) + { + // The node information doesn't match the locator. + return false; + } + return true; } } // namespace +// NOLINTNEXTLINE(readability-function-cognitive-complexity) TEST_CASE("ffi_schema_tree", "[ffi]") { /* * <0:root:Obj> @@ -69,39 +88,46 @@ TEST_CASE("ffi_schema_tree", "[ffi]") { * |--> <6:d:Bool> |--> <8:d:Str> */ SchemaTree schema_tree; + + // Check the root node + auto const& root{schema_tree.get_root()}; + REQUIRE((SchemaTree::cRootId == root.get_id())); + REQUIRE(root.is_root()); + REQUIRE_FALSE(root.get_parent_id().has_value()); + std::vector const locators{ - {SchemaTree::cRootId, "a", SchemaTreeNode::Type::Obj}, - {SchemaTree::cRootId, "a", SchemaTreeNode::Type::Int}, - {1, "b", SchemaTreeNode::Type::Obj}, - {3, "c", SchemaTreeNode::Type::Obj}, - {3, "d", SchemaTreeNode::Type::Int}, - {3, "d", SchemaTreeNode::Type::Bool}, - {4, "d", SchemaTreeNode::Type::UnstructuredArray}, - {4, "d", SchemaTreeNode::Type::Str} + {SchemaTree::cRootId, "a", SchemaTree::Node::Type::Obj}, + {SchemaTree::cRootId, "a", SchemaTree::Node::Type::Int}, + {1, "b", SchemaTree::Node::Type::Obj}, + {3, "c", SchemaTree::Node::Type::Obj}, + {3, "d", SchemaTree::Node::Type::Int}, + {3, "d", SchemaTree::Node::Type::Bool}, + {4, "d", SchemaTree::Node::Type::UnstructuredArray}, + {4, "d", SchemaTree::Node::Type::Str} }; - auto const snapshot_idx{static_cast(locators.size() / 2)}; + auto const snapshot_idx{static_cast(locators.size() / 2)}; - for (SchemaTreeNode::id_t id_to_insert{1}; id_to_insert <= locators.size(); ++id_to_insert) { + for (SchemaTree::Node::id_t id_to_insert{1}; id_to_insert <= locators.size(); ++id_to_insert) { REQUIRE(insert_node(schema_tree, locators[id_to_insert - 1], id_to_insert)); if (snapshot_idx == id_to_insert) { schema_tree.take_snapshot(); } } - for (SchemaTreeNode::id_t id_to_check{1}; id_to_check <= locators.size(); ++id_to_check) { - REQUIRE(check_node(schema_tree, locators[id_to_check - 1], id_to_check)); + for (SchemaTree::Node::id_t id_to_check{1}; id_to_check <= locators.size(); ++id_to_check) { + REQUIRE(check_non_root_node(schema_tree, locators[id_to_check - 1], id_to_check)); } schema_tree.revert(); - for (SchemaTreeNode::id_t id_to_insert{snapshot_idx + 1}; id_to_insert <= locators.size(); + for (SchemaTree::Node::id_t id_to_insert{snapshot_idx + 1}; id_to_insert <= locators.size(); ++id_to_insert) { REQUIRE(insert_node(schema_tree, locators[id_to_insert - 1], id_to_insert)); } - for (SchemaTreeNode::id_t id_to_check{1}; id_to_check <= locators.size(); ++id_to_check) { - REQUIRE(check_node(schema_tree, locators[id_to_check - 1], id_to_check)); + for (SchemaTree::Node::id_t id_to_check{1}; id_to_check <= locators.size(); ++id_to_check) { + REQUIRE(check_non_root_node(schema_tree, locators[id_to_check - 1], id_to_check)); } } From e21672b906641c4724a25ea74f13857afdebe0e8 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 18 Oct 2024 02:23:13 -0400 Subject: [PATCH 081/114] ffi: Add support for serializing/deserializing auto-generated and user-generated schema tree node IDs. (#557) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../core/src/clp/ffi/ir_stream/Serializer.cpp | 34 ++-- .../core/src/clp/ffi/ir_stream/Serializer.hpp | 3 +- .../ir_unit_deserialization_methods.cpp | 142 ++++++++-------- .../ir_unit_deserialization_methods.hpp | 3 + .../clp/ffi/ir_stream/protocol_constants.hpp | 12 +- .../core/src/clp/ffi/ir_stream/utils.cpp | 2 + .../core/src/clp/ffi/ir_stream/utils.hpp | 151 +++++++++++++++++- components/core/src/clp/type_utils.hpp | 12 ++ .../core/tests/test-ir_encoding_methods.cpp | 76 +++++++++ 9 files changed, 337 insertions(+), 98 deletions(-) diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp index e86b45078..01215eb9d 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -403,15 +403,16 @@ auto Serializer::serialize_schema_tree_node( return false; } - auto const parent_id{locator.get_parent_id()}; - if (parent_id <= UINT8_MAX) { - m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeParentIdUByte); - m_schema_tree_node_buf.push_back(bit_cast(static_cast(parent_id))); - } else if (parent_id <= UINT16_MAX) { - m_schema_tree_node_buf.push_back(cProtocol::Payload::SchemaTreeNodeParentIdUShort); - serialize_int(static_cast(parent_id), m_schema_tree_node_buf); - } else { - // Out of range + if (false + == encode_and_serialize_schema_tree_node_id< + false, + cProtocol::Payload::EncodedSchemaTreeNodeParentIdByte, + cProtocol::Payload::EncodedSchemaTreeNodeParentIdShort, + cProtocol::Payload::EncodedSchemaTreeNodeParentIdInt>( + locator.get_parent_id(), + m_schema_tree_node_buf + )) + { return false; } @@ -420,16 +421,11 @@ auto Serializer::serialize_schema_tree_node( template auto Serializer::serialize_key(SchemaTree::Node::id_t id) -> bool { - if (id <= UINT8_MAX) { - m_key_group_buf.push_back(cProtocol::Payload::KeyIdUByte); - m_key_group_buf.push_back(bit_cast(static_cast(id))); - } else if (id <= UINT16_MAX) { - m_key_group_buf.push_back(cProtocol::Payload::KeyIdUShort); - serialize_int(static_cast(id), m_key_group_buf); - } else { - return false; - } - return true; + return encode_and_serialize_schema_tree_node_id< + false, + cProtocol::Payload::EncodedSchemaTreeNodeIdByte, + cProtocol::Payload::EncodedSchemaTreeNodeIdShort, + cProtocol::Payload::EncodedSchemaTreeNodeIdInt>(id, m_key_group_buf); } template diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp index dca9604db..292b360a3 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -103,8 +103,7 @@ class Serializer { /** * Serializes the given key ID into `m_key_group_buf`. * @param id - * @return true on success. - * @return false if the ID exceeds the representable range. + * @return Forwards `encode_and_serialize_schema_tree_node_id`'s return values. */ [[nodiscard]] auto serialize_key(SchemaTree::Node::id_t id) -> bool; diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp index d475ad196..5e1813a3e 100644 --- a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -43,16 +44,16 @@ using Schema = std::vector; /** * Deserializes the parent ID of a schema tree node. * @param reader - * @param parent_id Returns the deserialized result. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return IRErrorCode::IRErrorCode_Corrupted_IR if the next packet in the stream isn't a parent ID. - * @return Forwards `deserialize_tag`'s return values on any other failure. + * @return A result containing a pair or an error code indicating the failure: + * - The pair: + * - Whether the node ID is for an auto-generated node. + * - The decoded node ID. + * - The possible error codes: + * - Forwards `deserialize_tag`'s return values. + * @return Forwards `deserialize_and_decode_schema_tree_node_id`'s return values. */ -[[nodiscard]] auto deserialize_schema_tree_node_parent_id( - ReaderInterface& reader, - SchemaTree::Node::id_t& parent_id -) -> IRErrorCode; +[[nodiscard]] auto deserialize_schema_tree_node_parent_id(ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result>; /** * Deserializes the key name of a schema tree node. @@ -100,13 +101,14 @@ deserialize_int_val(ReaderInterface& reader, encoded_tag_t tag, value_int_t& val * Deserializes the IDs of all keys in a log event. * @param reader * @param tag Takes the current tag as input and returns the last tag read. - * @param schema Returns the deserialized schema. - * @return IRErrorCode::IRErrorCode_Success on success. - * @return IRErrorCode::IRErrorCode_Incomplete_IR if the stream is truncated. - * @return Forwards `deserialize_tag`'s return values on any other failure. + * @return A result containing the deserialized schema or an error code indicating the failure: + * - std::err::protocol_not_supported if the IR stream contains auto-generated keys (TODO: Remove + * this once auto-generated keys are fully supported). + * - Forwards `deserialize_tag`'s return values. + * - Forwards `deserialize_and_decode_schema_tree_node_id`'s return values. */ -[[nodiscard]] auto -deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) -> IRErrorCode; +[[nodiscard]] auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag) + -> OUTCOME_V2_NAMESPACE::std_result; /** * Deserializes the next value and pushes the result into `node_id_value_pairs`. @@ -170,10 +172,17 @@ requires(std::is_same_v ) -> IRErrorCode; /** + * @param tag * @return Whether the given tag can be a valid leading tag of a log event IR unit. */ [[nodiscard]] auto is_log_event_ir_unit_tag(encoded_tag_t tag) -> bool; +/** + * @param tag + * @return Whether the given tag represents a valid encoded key ID. + */ +[[nodiscard]] auto is_encoded_key_id_tag(encoded_tag_t tag) -> bool; + auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional { switch (tag) { case cProtocol::Payload::SchemaTreeNodeInt: @@ -193,30 +202,16 @@ auto schema_tree_node_tag_to_type(encoded_tag_t tag) -> std::optional IRErrorCode { +auto deserialize_schema_tree_node_parent_id(ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result> { encoded_tag_t tag{}; if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; - } - if (cProtocol::Payload::SchemaTreeNodeParentIdUByte == tag) { - uint8_t deserialized_id{}; - if (false == deserialize_int(reader, deserialized_id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - parent_id = static_cast(deserialized_id); - } else if (cProtocol::Payload::SchemaTreeNodeParentIdUShort == tag) { - uint16_t deserialized_id{}; - if (false == deserialize_int(reader, deserialized_id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - parent_id = static_cast(deserialized_id); - } else { - return IRErrorCode::IRErrorCode_Corrupted_IR; + return ir_error_code_to_errc(err); } - return IRErrorCode_Success; + return deserialize_and_decode_schema_tree_node_id< + cProtocol::Payload::EncodedSchemaTreeNodeParentIdByte, + cProtocol::Payload::EncodedSchemaTreeNodeParentIdShort, + cProtocol::Payload::EncodedSchemaTreeNodeParentIdInt>(tag, reader); } auto deserialize_schema_tree_node_key_name(ReaderInterface& reader, std::string& key_name) @@ -297,32 +292,35 @@ auto deserialize_string(ReaderInterface& reader, encoded_tag_t tag, std::string& return IRErrorCode::IRErrorCode_Success; } -auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag, Schema& schema) - -> IRErrorCode { - schema.clear(); +auto deserialize_schema(ReaderInterface& reader, encoded_tag_t& tag) + -> OUTCOME_V2_NAMESPACE::std_result { + Schema schema; while (true) { - if (cProtocol::Payload::KeyIdUByte == tag) { - uint8_t id{}; - if (false == deserialize_int(reader, id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - schema.push_back(static_cast(id)); - } else if (cProtocol::Payload::KeyIdUShort == tag) { - uint16_t id{}; - if (false == deserialize_int(reader, id)) { - return IRErrorCode::IRErrorCode_Incomplete_IR; - } - schema.push_back(static_cast(id)); - } else { + if (false == is_encoded_key_id_tag(tag)) { + // The log event must be an empty value. break; } + auto const schema_tree_node_id_result{deserialize_and_decode_schema_tree_node_id< + cProtocol::Payload::EncodedSchemaTreeNodeIdByte, + cProtocol::Payload::EncodedSchemaTreeNodeIdShort, + cProtocol::Payload::EncodedSchemaTreeNodeIdInt>(tag, reader)}; + if (schema_tree_node_id_result.has_error()) { + return schema_tree_node_id_result.error(); + } + auto const [is_auto_generated, node_id]{schema_tree_node_id_result.value()}; + if (is_auto_generated) { + // Currently, we don't support auto-generated keys. + return std::errc::protocol_not_supported; + } + schema.push_back(node_id); + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { - return err; + return ir_error_code_to_errc(err); } } - return IRErrorCode::IRErrorCode_Success; + return schema; } auto deserialize_value_and_insert_to_node_id_value_pairs( @@ -469,12 +467,24 @@ auto is_log_event_ir_unit_tag(encoded_tag_t tag) -> bool { // The log event is an empty object return true; } - if (cProtocol::Payload::KeyIdUByte == tag || cProtocol::Payload::KeyIdUShort == tag) { + if (is_encoded_key_id_tag(tag)) { // If not empty, the log event must start with a tag byte indicating the key ID return true; } return false; } + +auto is_encoded_key_id_tag(encoded_tag_t tag) -> bool { + // Ideally, we could check whether the tag is within the range of + // [EncodedKeyIdByte, EncodedKeyIdInt], but we don't for two reasons: + // - We optimize for streams that have few key IDs, meaning we can short circuit in the first + // branch below. + // - Using a range check assumes all length indicators are defined continuously, in order, but + // we don't have static checks for this assumption. + return cProtocol::Payload::EncodedSchemaTreeNodeIdByte == tag + || cProtocol::Payload::EncodedSchemaTreeNodeIdShort == tag + || cProtocol::Payload::EncodedSchemaTreeNodeIdInt == tag; +} } // namespace auto get_ir_unit_type_from_tag(encoded_tag_t tag) -> std::optional { @@ -508,11 +518,14 @@ auto deserialize_ir_unit_schema_tree_node_insertion( return ir_error_code_to_errc(IRErrorCode::IRErrorCode_Corrupted_IR); } - SchemaTree::Node::id_t parent_id{}; - if (auto const err{deserialize_schema_tree_node_parent_id(reader, parent_id)}; - IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); + auto const parent_node_id_result{deserialize_schema_tree_node_parent_id(reader)}; + if (parent_node_id_result.has_error()) { + return parent_node_id_result.error(); + } + auto const [is_auto_generated, parent_id]{parent_node_id_result.value()}; + if (is_auto_generated) { + // Currently, we don't support auto-generated keys. + return std::errc::protocol_not_supported; } if (auto const err{deserialize_schema_tree_node_key_name(reader, key_name)}; @@ -541,12 +554,11 @@ auto deserialize_ir_unit_kv_pair_log_event( std::shared_ptr schema_tree, UtcOffset utc_offset ) -> OUTCOME_V2_NAMESPACE::std_result { - Schema schema; - if (auto const err{deserialize_schema(reader, tag, schema)}; - IRErrorCode::IRErrorCode_Success != err) - { - return ir_error_code_to_errc(err); + auto const schema_result{deserialize_schema(reader, tag)}; + if (schema_result.has_error()) { + return schema_result.error(); } + auto const& schema{schema_result.value()}; KeyValuePairLogEvent::NodeIdValuePairs node_id_value_pairs; if (false == schema.empty()) { diff --git a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp index 454676cf5..68ed4408b 100644 --- a/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp +++ b/components/core/src/clp/ffi/ir_stream/ir_unit_deserialization_methods.hpp @@ -32,6 +32,8 @@ namespace clp::ffi::ir_stream { * indicating the failure: * - std::errc::result_out_of_range if the IR stream is truncated. * - std::errc::protocol_error if the deserialized node type isn't supported. + * - std::errc::protocol_not_supported if the IR stream contains auto-generated keys (TODO: Remove + * this once auto-generated keys are fully supported). * - Forwards `deserialize_schema_tree_node_key_name`'s return values. * - Forwards `deserialize_schema_tree_node_parent_id`'s return values. */ @@ -63,6 +65,7 @@ namespace clp::ffi::ir_stream { * - std::errc::protocol_error if the IR stream is corrupted. * - std::errc::protocol_not_supported if the IR stream contains an unsupported metadata format * or uses an unsupported version. + * - Forwards `deserialize_schema`'s return values. * - Forwards `KeyValuePairLogEvent::create`'s return values if the intermediate deserialized result * cannot construct a valid key-value pair log event. */ diff --git a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp index 915a8a56d..c6fd92397 100644 --- a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp +++ b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp @@ -13,7 +13,7 @@ constexpr int8_t LengthUShort = 0x12; constexpr char VersionKey[] = "VERSION"; constexpr char VersionValue[] = "0.0.2"; -constexpr char BetaVersionValue[] = "0.1.0-beta"; +constexpr char BetaVersionValue[] = "0.1.0-beta.1"; // The following regex can be used to validate a Semantic Versioning string. The source of the // regex can be found here: https://semver.org/ @@ -67,11 +67,13 @@ constexpr int8_t ValueEightByteEncodingClpStr = 0x5A; constexpr int8_t ValueEmpty = 0x5E; constexpr int8_t ValueNull = 0x5F; -constexpr int8_t SchemaTreeNodeParentIdUByte = 0x60; -constexpr int8_t SchemaTreeNodeParentIdUShort = 0x61; +constexpr int8_t EncodedSchemaTreeNodeParentIdByte = 0x60; +constexpr int8_t EncodedSchemaTreeNodeParentIdShort = 0x61; +constexpr int8_t EncodedSchemaTreeNodeParentIdInt = 0x62; -constexpr int8_t KeyIdUByte = 0x65; -constexpr int8_t KeyIdUShort = 0x66; +constexpr int8_t EncodedSchemaTreeNodeIdByte = 0x65; +constexpr int8_t EncodedSchemaTreeNodeIdShort = 0x66; +constexpr int8_t EncodedSchemaTreeNodeIdInt = 0x67; constexpr int8_t SchemaTreeNodeMask = 0x70; diff --git a/components/core/src/clp/ffi/ir_stream/utils.cpp b/components/core/src/clp/ffi/ir_stream/utils.cpp index cfbc9d5a9..371d7cfba 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.cpp +++ b/components/core/src/clp/ffi/ir_stream/utils.cpp @@ -54,6 +54,8 @@ auto serialize_string(std::string_view str, std::vector& output_buf) -> auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc { switch (ir_error_code) { + case IRErrorCode_Success: + return {}; case IRErrorCode_Incomplete_IR: return std::errc::result_out_of_range; case IRErrorCode_Corrupted_IR: diff --git a/components/core/src/clp/ffi/ir_stream/utils.hpp b/components/core/src/clp/ffi/ir_stream/utils.hpp index 4e68ca67a..3e545c4fe 100644 --- a/components/core/src/clp/ffi/ir_stream/utils.hpp +++ b/components/core/src/clp/ffi/ir_stream/utils.hpp @@ -6,13 +6,17 @@ #include #include #include +#include #include #include +#include #include "../../ErrorCode.hpp" #include "../../ir/types.hpp" #include "../../ReaderInterface.hpp" +#include "../../type_utils.hpp" +#include "../SchemaTree.hpp" #include "byteswap.hpp" #include "decoding_methods.hpp" #include "encoding_methods.hpp" @@ -34,7 +38,7 @@ serialize_metadata(nlohmann::json& metadata, std::vector& output_buf) -> * @param value * @param output_buf */ -template +template auto serialize_int(integer_t value, std::vector& output_buf) -> void; /** @@ -44,7 +48,7 @@ auto serialize_int(integer_t value, std::vector& output_buf) -> void; * @param value Returns the deserialized integer * @return Whether the reader contained enough data to deserialize. */ -template +template [[nodiscard]] auto deserialize_int(ReaderInterface& reader, integer_t& value) -> bool; /** @@ -70,17 +74,73 @@ template */ [[nodiscard]] auto serialize_string(std::string_view str, std::vector& output_buf) -> bool; +/** + * @tparam T + * @param int_val + * @return One's complement of `int_val`. + */ +template +[[nodiscard]] auto get_ones_complement(T int_val) -> T; + +/** + * Encodes and serializes a schema tree node ID. + * @tparam is_auto_generated_node Whether the schema tree node ID is from the auto-generated or the + * user-generated schema tree. + * @tparam one_byte_length_indicator_tag Tag for one-byte node ID encoding. + * @tparam two_byte_length_indicator_tag Tag for two-byte node ID encoding. + * @tparam four_byte_length_indicator_tag Tag for four-byte node ID encoding. + * @param node_id + * @param output_buf + * @return true on success. + * @return false if the ID exceeds the representable range. + */ +template < + bool is_auto_generated_node, + int8_t one_byte_length_indicator_tag, + int8_t two_byte_length_indicator_tag, + int8_t four_byte_length_indicator_tag> +[[nodiscard]] auto encode_and_serialize_schema_tree_node_id( + SchemaTree::Node::id_t node_id, + std::vector& output_buf +) -> bool; + +/** + * Deserializes and decodes a schema tree node ID. + * @tparam one_byte_length_indicator_tag Tag for one-byte node ID encoding. + * @tparam two_byte_length_indicator_tag Tag for two-byte node ID encoding. + * @tparam four_byte_length_indicator_tag Tag for four-byte node ID encoding. + * @param length_indicator_tag + * @param reader + * @return A result containing a pair or an error code indicating the failure: + * - The pair: + * - Whether the node ID is for an auto-generated node. + * - The decoded node ID. + * - The possible error codes: + * - std::errc::protocol_error if the given length indicator is unknown. + * @return Forwards `size_dependent_deserialize_and_decode_schema_tree_node_id`'s return values. + */ +template < + int8_t one_byte_length_indicator_tag, + int8_t two_byte_length_indicator_tag, + int8_t four_byte_length_indicator_tag> +[[nodiscard]] auto deserialize_and_decode_schema_tree_node_id( + encoded_tag_t length_indicator_tag, + ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result>; + /** * @param ir_error_code * @return Equivalent `std::errc` code indicating the same error type. */ [[nodiscard]] auto ir_error_code_to_errc(IRErrorCode ir_error_code) -> std::errc; -template +template auto serialize_int(integer_t value, std::vector& output_buf) -> void { integer_t value_big_endian{}; - static_assert(sizeof(integer_t) == 2 || sizeof(integer_t) == 4 || sizeof(integer_t) == 8); - if constexpr (sizeof(value) == 2) { + if constexpr (sizeof(value) == 1) { + output_buf.push_back(bit_cast(value)); + return; + } else if constexpr (sizeof(value) == 2) { value_big_endian = bswap_16(value); } else if constexpr (sizeof(value) == 4) { value_big_endian = bswap_32(value); @@ -92,7 +152,7 @@ auto serialize_int(integer_t value, std::vector& output_buf) -> void { output_buf.insert(output_buf.end(), data_view.begin(), data_view.end()); } -template +template auto deserialize_int(ReaderInterface& reader, integer_t& value) -> bool { integer_t value_little_endian; if (reader.try_read_numeric_value(value_little_endian) != clp::ErrorCode_Success) { @@ -100,7 +160,6 @@ auto deserialize_int(ReaderInterface& reader, integer_t& value) -> bool { } constexpr auto cReadSize = sizeof(integer_t); - static_assert(cReadSize == 1 || cReadSize == 2 || cReadSize == 4 || cReadSize == 8); if constexpr (cReadSize == 1) { value = value_little_endian; } else if constexpr (cReadSize == 2) { @@ -133,5 +192,83 @@ template } return succeeded; } + +template +auto get_ones_complement(T int_val) -> T { + // Explicit cast to undo the implicit integer promotion + return static_cast(~int_val); +} + +template < + bool is_auto_generated_node, + int8_t one_byte_length_indicator_tag, + int8_t two_byte_length_indicator_tag, + int8_t four_byte_length_indicator_tag> +auto encode_and_serialize_schema_tree_node_id( + SchemaTree::Node::id_t node_id, + std::vector& output_buf +) -> bool { + auto size_dependent_encode_and_serialize_schema_tree_node_id + = [&output_buf, + &node_id](int8_t length_indicator_tag) -> void { + output_buf.push_back(length_indicator_tag); + if constexpr (is_auto_generated_node) { + serialize_int(get_ones_complement(static_cast(node_id)), output_buf); + } else { + serialize_int(static_cast(node_id), output_buf); + } + }; + + if (node_id <= static_cast(INT8_MAX)) { + size_dependent_encode_and_serialize_schema_tree_node_id.template operator( + )(one_byte_length_indicator_tag); + } else if (node_id <= static_cast(INT16_MAX)) { + size_dependent_encode_and_serialize_schema_tree_node_id.template operator( + )(two_byte_length_indicator_tag); + } else if (node_id <= static_cast(INT32_MAX)) { + size_dependent_encode_and_serialize_schema_tree_node_id.template operator( + )(four_byte_length_indicator_tag); + } else { + return false; + } + return true; +} + +template < + int8_t one_byte_length_indicator_tag, + int8_t two_byte_length_indicator_tag, + int8_t four_byte_length_indicator_tag> +auto deserialize_and_decode_schema_tree_node_id( + encoded_tag_t length_indicator_tag, + ReaderInterface& reader +) -> OUTCOME_V2_NAMESPACE::std_result> { + auto size_dependent_deserialize_and_decode_schema_tree_node_id + = [&reader]( + ) -> OUTCOME_V2_NAMESPACE::std_result> { + encoded_node_id_t encoded_node_id{}; + if (false == deserialize_int(reader, encoded_node_id)) { + return std::errc::result_out_of_range; + } + if (0 > encoded_node_id) { + return {true, static_cast(get_ones_complement(encoded_node_id)) + }; + } + return {false, static_cast(encoded_node_id)}; + }; + + if (one_byte_length_indicator_tag == length_indicator_tag) { + return size_dependent_deserialize_and_decode_schema_tree_node_id.template operator( + )(); + } + if (two_byte_length_indicator_tag == length_indicator_tag) { + return size_dependent_deserialize_and_decode_schema_tree_node_id.template operator( + )(); + } + if (four_byte_length_indicator_tag == length_indicator_tag) { + return size_dependent_deserialize_and_decode_schema_tree_node_id.template operator( + )(); + } + return std::errc::protocol_error; +} } // namespace clp::ffi::ir_stream #endif diff --git a/components/core/src/clp/type_utils.hpp b/components/core/src/clp/type_utils.hpp index e8934490c..44cfcc521 100644 --- a/components/core/src/clp/type_utils.hpp +++ b/components/core/src/clp/type_utils.hpp @@ -93,6 +93,18 @@ struct is_in_type_tuple; template struct is_in_type_tuple> : std::disjunction...> {}; + +/** + * Concept for integer types. + */ +template +concept IntegerType = std::is_integral_v && false == std::is_same_v; + +/** + * Concept for signed integer types. + */ +template +concept SignedIntegerType = IntegerType && std::is_signed_v; } // namespace clp #endif // CLP_TYPE_UTILS_HPP diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index 5c27a6fab..b4f0257c1 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -19,6 +21,7 @@ #include "../src/clp/ffi/ir_stream/IrUnitType.hpp" #include "../src/clp/ffi/ir_stream/protocol_constants.hpp" #include "../src/clp/ffi/ir_stream/Serializer.hpp" +#include "../src/clp/ffi/ir_stream/utils.hpp" #include "../src/clp/ffi/KeyValuePairLogEvent.hpp" #include "../src/clp/ffi/SchemaTree.hpp" #include "../src/clp/ir/LogEventDeserializer.hpp" @@ -1208,3 +1211,76 @@ TEMPLATE_TEST_CASE( auto const eof_result{deserializer.deserialize_next_ir_unit(reader)}; REQUIRE((eof_result.has_error() && std::errc::operation_not_permitted == eof_result.error())); } + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +TEMPLATE_TEST_CASE( + "ffi_ir_stream_serialize_schema_tree_node_id", + "[clp][ffi][ir_stream]", + std::true_type, + std::false_type +) { + constexpr bool cIsAutoGeneratedNode{TestType{}}; + constexpr int8_t cOneByteLengthIndicatorTag{ + clp::ffi::ir_stream::cProtocol::Payload::EncodedSchemaTreeNodeIdByte + }; + constexpr int8_t cTwoByteLengthIndicatorTag{ + clp::ffi::ir_stream::cProtocol::Payload::EncodedSchemaTreeNodeIdShort + }; + constexpr int8_t cFourByteLengthIndicatorTag{ + clp::ffi::ir_stream::cProtocol::Payload::EncodedSchemaTreeNodeIdInt + }; + constexpr auto cMaxNodeId{static_cast(INT32_MAX)}; + + constexpr auto cSerializationMethodToTest + = clp::ffi::ir_stream::encode_and_serialize_schema_tree_node_id< + cIsAutoGeneratedNode, + cOneByteLengthIndicatorTag, + cTwoByteLengthIndicatorTag, + cFourByteLengthIndicatorTag>; + constexpr auto cDeserializationMethodToTest + = clp::ffi::ir_stream::deserialize_and_decode_schema_tree_node_id< + cOneByteLengthIndicatorTag, + cTwoByteLengthIndicatorTag, + cFourByteLengthIndicatorTag>; + + std::vector output_buf; + std::unordered_set valid_node_ids_to_test; + + // Add some boundary node IDs + valid_node_ids_to_test.emplace(0); + valid_node_ids_to_test.emplace(static_cast(INT8_MAX - 1)); + valid_node_ids_to_test.emplace(static_cast(INT8_MAX)); + valid_node_ids_to_test.emplace(static_cast(INT8_MAX + 1)); + valid_node_ids_to_test.emplace(static_cast(INT16_MAX - 1)); + valid_node_ids_to_test.emplace(static_cast(INT16_MAX)); + valid_node_ids_to_test.emplace(static_cast(INT16_MAX + 1)); + valid_node_ids_to_test.emplace(static_cast(INT32_MAX - 1)); + valid_node_ids_to_test.emplace(static_cast(INT32_MAX)); + + // Generate some more "random" valid node IDs + for (clp::ffi::SchemaTree::Node::id_t node_id{1}, step{1}; node_id <= cMaxNodeId; + node_id += step, step += 1) + { + valid_node_ids_to_test.emplace(node_id); + } + + for (auto const node_id : valid_node_ids_to_test) { + output_buf.clear(); + REQUIRE(cSerializationMethodToTest(node_id, output_buf)); + + BufferReader reader{size_checked_pointer_cast(output_buf.data()), output_buf.size()}; + encoded_tag_t tag{}; + REQUIRE((IRErrorCode::IRErrorCode_Success == deserialize_tag(reader, tag))); + auto const result{cDeserializationMethodToTest(tag, reader)}; + REQUIRE_FALSE(result.has_error()); + auto const [is_auto_generated, deserialized_node_id]{result.value()}; + REQUIRE((cIsAutoGeneratedNode == is_auto_generated)); + REQUIRE((deserialized_node_id == node_id)); + } + + // Test against the first invalid node ID + REQUIRE_FALSE(cSerializationMethodToTest( + static_cast(INT32_MAX) + 1, + output_buf + )); +} From 65b231b66230e3a542cfefbdd2acec00fa7f6ca9 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:26:14 -0400 Subject: [PATCH 082/114] clp: Add missing C++ standard library includes in IR parsing files. (#561) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- components/core/src/clp/ir/parsing.cpp | 4 ++++ components/core/src/clp/ir/parsing.hpp | 3 ++- components/core/src/clp/ir/parsing.inc | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/components/core/src/clp/ir/parsing.cpp b/components/core/src/clp/ir/parsing.cpp index 2082f0640..2a54fb6a6 100644 --- a/components/core/src/clp/ir/parsing.cpp +++ b/components/core/src/clp/ir/parsing.cpp @@ -1,5 +1,9 @@ #include "parsing.hpp" +#include +#include +#include + #include #include "../type_utils.hpp" diff --git a/components/core/src/clp/ir/parsing.hpp b/components/core/src/clp/ir/parsing.hpp index c962cf46c..26171a624 100644 --- a/components/core/src/clp/ir/parsing.hpp +++ b/components/core/src/clp/ir/parsing.hpp @@ -9,8 +9,9 @@ * the placement of the methods in this file. */ +#include +#include #include -#include namespace clp::ir { /** diff --git a/components/core/src/clp/ir/parsing.inc b/components/core/src/clp/ir/parsing.inc index 5cb8f87f0..cafd9f77c 100644 --- a/components/core/src/clp/ir/parsing.inc +++ b/components/core/src/clp/ir/parsing.inc @@ -1,6 +1,7 @@ #ifndef CLP_IR_PARSING_INC #define CLP_IR_PARSING_INC +#include #include #include From f549df04d62b36b392c33cb3a206e58151d64209 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Thu, 24 Oct 2024 10:56:34 -0400 Subject: [PATCH 083/114] log-viewer-webui: Update `yscope-log-viewer` to the latest version (which uses `clp-ffi-js`). (#562) --- components/log-viewer-webui/client/src/App.jsx | 2 +- .../log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js | 2 +- components/log-viewer-webui/client/src/ui/QueryStatus.jsx | 2 +- components/log-viewer-webui/yscope-log-viewer | 2 +- deps-tasks.yml | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/log-viewer-webui/client/src/App.jsx b/components/log-viewer-webui/client/src/App.jsx index 6d7a65e45..ef032f85c 100644 --- a/components/log-viewer-webui/client/src/App.jsx +++ b/components/log-viewer-webui/client/src/App.jsx @@ -11,7 +11,7 @@ import QueryStatus from "./ui/QueryStatus.jsx"; */ const App = () => { return ( - + ); diff --git a/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js b/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js index c1dc19979..3218b9f48 100644 --- a/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js +++ b/components/log-viewer-webui/client/src/typings/LOCAL_STORAGE_KEY.js @@ -2,7 +2,7 @@ * Enum of `window.localStorage` keys. */ const LOCAL_STORAGE_KEY = Object.freeze({ - UI_THEME: "uiTheme", + THEME: "theme", }); export default LOCAL_STORAGE_KEY; diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx index 84f367d0e..c1ad9eb9e 100644 --- a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -52,7 +52,7 @@ const QueryStatus = () => { const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + - `#logEventIdx=${innerLogEventNum}`; + `#logEventNum=${innerLogEventNum}`; }) .catch((e) => { let msg = "Unknown error."; diff --git a/components/log-viewer-webui/yscope-log-viewer b/components/log-viewer-webui/yscope-log-viewer index c939f7b55..bc8109f9f 160000 --- a/components/log-viewer-webui/yscope-log-viewer +++ b/components/log-viewer-webui/yscope-log-viewer @@ -1 +1 @@ -Subproject commit c939f7b55b55b42f65226470d5277b15ac484665 +Subproject commit bc8109f9f371c3327070000dee3537bdaf535428 diff --git a/deps-tasks.yml b/deps-tasks.yml index bfe80d8b5..eac7b6509 100644 --- a/deps-tasks.yml +++ b/deps-tasks.yml @@ -421,8 +421,8 @@ tasks: vars: DEST: "{{.DEST}}" FLAGS: "--extract" - SRC_NAME: "yscope-log-viewer-c939f7b55b55b42f65226470d5277b15ac484665" - SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/c939f7b.zip" + SRC_NAME: "yscope-log-viewer-bc8109f9f371c3327070000dee3537bdaf535428" + SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/bc8109f.zip" # This command must be last - task: ":utils:compute-checksum" vars: From 7043d040bc74b6dd2e01c5f5342471fd6e311275 Mon Sep 17 00:00:00 2001 From: Henry8192 <50559854+Henry8192@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:15:08 -0400 Subject: [PATCH 084/114] package: Upgrade dependencies to resolve security issues. (#536) --- .../log-viewer-webui/client/package-lock.json | 3889 +++++++++-------- .../log-viewer-webui/client/package.json | 4 +- .../log-viewer-webui/server/package-lock.json | 2887 ++++++++---- .../log-viewer-webui/server/src/DbManager.js | 4 +- components/webui/package-lock.json | 740 ++-- components/webui/package.json | 2 +- requirements.txt | 2 +- 7 files changed, 4332 insertions(+), 3196 deletions(-) diff --git a/components/log-viewer-webui/client/package-lock.json b/components/log-viewer-webui/client/package-lock.json index 4141c89aa..26c9953a2 100644 --- a/components/log-viewer-webui/client/package-lock.json +++ b/components/log-viewer-webui/client/package-lock.json @@ -29,9 +29,9 @@ "mini-css-extract-plugin": "^2.9.0", "react-refresh": "^0.14.2", "style-loader": "^4.0.0", - "webpack": "^5.92.1", + "webpack": "^5.95.0", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4" + "webpack-dev-server": "^5.1.0" } }, "node_modules/@ampproject/remapping": { @@ -39,6 +39,7 @@ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -48,11 +49,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -60,30 +62,32 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.8", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.8", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -99,53 +103,57 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", + "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -154,19 +162,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", - "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", + "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/traverse": "^7.25.7", "semver": "^6.3.1" }, "engines": { @@ -177,13 +184,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", + "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.7", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -198,6 +206,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -209,76 +218,44 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", + "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -288,35 +265,38 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", + "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", - "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", + "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-wrap-function": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -326,14 +306,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", + "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -343,101 +324,97 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", + "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dependencies": { - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", + "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -447,9 +424,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.8" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -458,13 +439,30 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", + "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", + "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -474,12 +472,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", + "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -489,14 +488,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", + "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -506,13 +506,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", + "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -526,6 +527,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -533,76 +535,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", + "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -612,12 +552,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", + "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -626,139 +567,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", + "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -772,6 +588,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -784,12 +601,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", + "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -799,15 +617,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.8.tgz", + "integrity": "sha512-9ypqkozyzpG+HxlH4o4gdctalFGIjjdufzo7I2XPda0iBnZ6a+FO0rIEQcdSPXp02CkvGsII1exJhmROPQd5oA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -817,14 +635,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz", + "integrity": "sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -834,12 +653,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", + "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -849,12 +669,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", + "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -864,13 +685,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", + "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -880,14 +702,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz", + "integrity": "sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -897,18 +719,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", - "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", + "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/traverse": "^7.25.7", "globals": "^11.1.0" }, "engines": { @@ -919,13 +740,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", + "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/template": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -935,12 +757,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", - "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", + "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -950,13 +773,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", + "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -966,12 +790,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", + "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -980,14 +805,31 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz", + "integrity": "sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -997,13 +839,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", + "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1013,13 +856,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz", + "integrity": "sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1029,13 +872,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", + "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1045,14 +889,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", + "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1062,13 +907,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz", + "integrity": "sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1078,12 +923,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", + "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1093,13 +939,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz", + "integrity": "sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1109,12 +955,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", + "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1124,13 +971,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", + "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1140,14 +988,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", - "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", + "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1157,15 +1006,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", + "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1175,13 +1025,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", + "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1191,13 +1042,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1207,12 +1059,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", + "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1222,13 +1075,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz", + "integrity": "sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1238,13 +1091,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz", + "integrity": "sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1254,15 +1107,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz", + "integrity": "sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-transform-parameters": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1272,13 +1125,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", + "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1288,13 +1142,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz", + "integrity": "sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1304,14 +1158,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", - "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz", + "integrity": "sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1321,12 +1175,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", + "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1336,13 +1191,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", + "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1352,15 +1208,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz", + "integrity": "sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1370,12 +1226,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", + "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1385,12 +1242,13 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", - "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.7.tgz", + "integrity": "sha512-r0QY7NVU8OnrwE+w2IWiRom0wwsTbjx4+xH2RTd7AVdof3uurXOF+/mXHQDRk+2jIvWgSaCHKMgggfvM4dyUGA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1400,16 +1258,17 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", - "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", + "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1419,12 +1278,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", - "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.7.tgz", + "integrity": "sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.24.7" + "@babel/plugin-transform-react-jsx": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1434,13 +1294,14 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", - "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.7.tgz", + "integrity": "sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1450,12 +1311,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", + "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1466,12 +1328,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", + "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1481,12 +1344,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", + "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1496,13 +1360,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", + "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1512,12 +1377,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", + "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1527,12 +1393,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", + "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1542,12 +1409,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", - "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", + "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1557,12 +1425,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", + "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1572,13 +1441,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", + "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1588,13 +1458,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", + "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1604,13 +1475,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", + "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1620,91 +1492,79 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.8.tgz", + "integrity": "sha512-58T2yulDHMN8YMUxiLq5YmWUnlDCyY1FsHM+v12VMx+1/FlrUj5tY50iDCpofFQEM8fMYOaY9YRvym2jcjn1Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.8", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.25.7", + "@babel/plugin-syntax-import-attributes": "^7.25.7", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.25.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.8", + "@babel/plugin-transform-async-to-generator": "^7.25.7", + "@babel/plugin-transform-block-scoped-functions": "^7.25.7", + "@babel/plugin-transform-block-scoping": "^7.25.7", + "@babel/plugin-transform-class-properties": "^7.25.7", + "@babel/plugin-transform-class-static-block": "^7.25.8", + "@babel/plugin-transform-classes": "^7.25.7", + "@babel/plugin-transform-computed-properties": "^7.25.7", + "@babel/plugin-transform-destructuring": "^7.25.7", + "@babel/plugin-transform-dotall-regex": "^7.25.7", + "@babel/plugin-transform-duplicate-keys": "^7.25.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-dynamic-import": "^7.25.8", + "@babel/plugin-transform-exponentiation-operator": "^7.25.7", + "@babel/plugin-transform-export-namespace-from": "^7.25.8", + "@babel/plugin-transform-for-of": "^7.25.7", + "@babel/plugin-transform-function-name": "^7.25.7", + "@babel/plugin-transform-json-strings": "^7.25.8", + "@babel/plugin-transform-literals": "^7.25.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.8", + "@babel/plugin-transform-member-expression-literals": "^7.25.7", + "@babel/plugin-transform-modules-amd": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.7", + "@babel/plugin-transform-modules-umd": "^7.25.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-new-target": "^7.25.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.8", + "@babel/plugin-transform-numeric-separator": "^7.25.8", + "@babel/plugin-transform-object-rest-spread": "^7.25.8", + "@babel/plugin-transform-object-super": "^7.25.7", + "@babel/plugin-transform-optional-catch-binding": "^7.25.8", + "@babel/plugin-transform-optional-chaining": "^7.25.8", + "@babel/plugin-transform-parameters": "^7.25.7", + "@babel/plugin-transform-private-methods": "^7.25.7", + "@babel/plugin-transform-private-property-in-object": "^7.25.8", + "@babel/plugin-transform-property-literals": "^7.25.7", + "@babel/plugin-transform-regenerator": "^7.25.7", + "@babel/plugin-transform-reserved-words": "^7.25.7", + "@babel/plugin-transform-shorthand-properties": "^7.25.7", + "@babel/plugin-transform-spread": "^7.25.7", + "@babel/plugin-transform-sticky-regex": "^7.25.7", + "@babel/plugin-transform-template-literals": "^7.25.7", + "@babel/plugin-transform-typeof-symbol": "^7.25.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.7", + "@babel/plugin-transform-unicode-property-regex": "^7.25.7", + "@babel/plugin-transform-unicode-regex": "^7.25.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.7", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -1719,6 +1579,7 @@ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -1729,17 +1590,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", - "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.7.tgz", + "integrity": "sha512-GjV0/mUEEXpi1U5ZgDprMRRgajGMRW3G5FjMr5KLKD8nT2fTG8+h/klV3+6Dm5739QE+K5+2e91qFKAYI3pmRg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.24.7", - "@babel/plugin-transform-react-jsx-development": "^7.24.7", - "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-transform-react-display-name": "^7.25.7", + "@babel/plugin-transform-react-jsx": "^7.25.7", + "@babel/plugin-transform-react-jsx-development": "^7.25.7", + "@babel/plugin-transform-react-pure-annotations": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1748,16 +1610,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1766,31 +1623,30 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1799,12 +1655,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1816,6 +1673,7 @@ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -1824,6 +1682,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -1841,20 +1700,14 @@ "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/@emotion/babel-plugin/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" }, "node_modules/@emotion/cache": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", - "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", @@ -1866,12 +1719,14 @@ "node_modules/@emotion/hash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", - "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0" } @@ -1879,17 +1734,19 @@ "node_modules/@emotion/memoize": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", - "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.12.0", "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.0", + "@emotion/serialize": "^1.3.1", "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", "@emotion/utils": "^1.4.0", "@emotion/weak-memoize": "^0.4.0", @@ -1905,26 +1762,29 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", - "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", + "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.9.0", - "@emotion/utils": "^1.4.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", - "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" }, "node_modules/@emotion/styled": { "version": "11.13.0", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.12.0", @@ -1944,65 +1804,54 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", - "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==", + "license": "MIT" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", - "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", + "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@types/eslint": "^8.56.5", - "@types/estree": "^1.0.5", - "@typescript-eslint/types": "^7.2.0", "comment-parser": "1.4.1", - "esquery": "^1.5.0", + "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { "node": ">=16" } }, - "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", - "dev": true, - "peer": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -2015,10 +1864,11 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2029,6 +1879,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ajv": "^6.12.4", @@ -2053,6 +1904,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -2064,6 +1916,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "type-fest": "^0.20.2" @@ -2080,6 +1933,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -2089,36 +1943,40 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@floating-ui/core": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", - "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.5" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", - "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "license": "MIT", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.5" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", - "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.0.0" }, @@ -2128,19 +1986,21 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", - "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -2153,6 +2013,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -2164,6 +2025,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -2177,6 +2039,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "peer": true, "engines": { "node": ">=12.22" @@ -2192,56 +2055,14 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", "dev": true, + "license": "BSD-3-Clause", "peer": true }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2255,6 +2076,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -2263,6 +2085,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -2272,20 +2095,23 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2296,6 +2122,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -2308,10 +2135,11 @@ } }, "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -2330,10 +2158,11 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", - "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -2349,12 +2178,14 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@mui/base": { "version": "5.0.0-beta.40", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@floating-ui/react-dom": "^2.0.8", @@ -2383,9 +2214,10 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", - "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", + "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" @@ -2395,6 +2227,7 @@ "version": "5.0.0-beta.48", "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.48.tgz", "integrity": "sha512-OhTvjuGl9I5IvpBr0BQyDehIW/xb2yteW6YglHJMdOb/279nItn76X1NBtPV9ImldNlBjReGwvpOXmBTTGER9w==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@mui/base": "5.0.0-beta.40", @@ -2432,12 +2265,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", - "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", + "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.4", + "@mui/utils": "^5.16.6", "prop-types": "^15.8.1" }, "engines": { @@ -2458,9 +2292,10 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", - "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", + "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -2489,15 +2324,16 @@ } }, "node_modules/@mui/system": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", - "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", + "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.4", - "@mui/styled-engine": "^5.16.4", + "@mui/private-theming": "^5.16.6", + "@mui/styled-engine": "^5.16.6", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.4", + "@mui/utils": "^5.16.6", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2528,11 +2364,12 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", - "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "version": "7.2.18", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.18.tgz", + "integrity": "sha512-uvK9dWeyCJl/3ocVnTOS6nlji/Knj8/tVqVX03UVTpdmTJYu/s4jtDd9Kvv0nRGE0CUSNW1UYAci7PYypjealg==", + "license": "MIT", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -2541,11 +2378,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", - "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", + "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", + "@mui/types": "^7.2.15", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -2568,16 +2407,12 @@ } } }, - "node_modules/@mui/utils/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2592,6 +2427,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 8" @@ -2602,6 +2438,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -2611,21 +2448,12 @@ "node": ">= 8" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -2639,6 +2467,7 @@ "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz", "integrity": "sha512-LFWllMA55pzB9D34w/wXUCf8+c+IYKuJDgxiZ3qMhl64KRMBHYM1I3VdGaD2BV5FNPV2/S2596bppxHbv2ZydQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-html": "^0.0.9", "core-js-pure": "^3.23.3", @@ -2687,6 +2516,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -2695,16 +2525,26 @@ "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@stylistic/eslint-plugin-js": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.8.1.tgz", "integrity": "sha512-c5c2C8Mos5tTQd+NWpqwEu7VT6SSRooAguFPMj1cp2RkTYl1ynKoXo8MWy3k4rkbzoeYHrqC2UlUzsroAN7wtQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -2725,6 +2565,7 @@ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.8.1.tgz", "integrity": "sha512-k1Eb6rcjMP+mmjvj+vd9y5KUdWn1OBkkPLHXhsrHt5lCDFZxJEs0aVQzE5lpYrtVZVkpc5esTtss/cPJux0lfA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@stylistic/eslint-plugin-js": "^1.8.1", @@ -2744,6 +2585,7 @@ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.8.1.tgz", "integrity": "sha512-4+40H3lHYTN8OWz+US8CamVkO+2hxNLp9+CAjorI7top/lHqemhpJvKA1LD9Uh+WMY9DYWiWpL2+SZ2wAXY9fQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -2758,6 +2600,7 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -2768,6 +2611,7 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2777,6 +2621,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2786,42 +2631,37 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -2830,10 +2670,24 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -2845,19 +2699,22 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2866,28 +2723,32 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", - "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", + "version": "22.7.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.7.tgz", + "integrity": "sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -2895,6 +2756,7 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2902,29 +2764,34 @@ "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -2934,13 +2801,15 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@types/send": { @@ -2948,6 +2817,7 @@ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -2958,6 +2828,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -2967,6 +2838,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -2978,15 +2850,17 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2996,6 +2870,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@typescript-eslint/types": "6.21.0", @@ -3014,6 +2889,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3028,6 +2904,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "@typescript-eslint/types": "6.21.0", @@ -3053,10 +2930,11 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" @@ -3070,6 +2948,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -3092,10 +2971,11 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" @@ -3109,6 +2989,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@typescript-eslint/types": "6.21.0", @@ -3127,6 +3008,7 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/@webassemblyjs/ast": { @@ -3134,6 +3016,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6" @@ -3143,25 +3026,29 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.6", "@webassemblyjs/helper-api-error": "1.11.6", @@ -3172,13 +3059,15 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -3191,6 +3080,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -3200,6 +3090,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } @@ -3208,13 +3099,15 @@ "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -3231,6 +3124,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", @@ -3244,6 +3138,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-buffer": "1.12.1", @@ -3256,6 +3151,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", @@ -3270,6 +3166,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" @@ -3280,6 +3177,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.15.0" }, @@ -3293,6 +3191,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.15.0" }, @@ -3306,6 +3205,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.15.0" }, @@ -3323,19 +3223,22 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -3345,10 +3248,11 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3361,6 +3265,7 @@ "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -3370,6 +3275,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -3380,6 +3286,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3396,6 +3303,7 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -3409,15 +3317,16 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3428,13 +3337,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -3447,6 +3358,7 @@ "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -3459,6 +3371,7 @@ "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -3468,6 +3381,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3476,6 +3390,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -3488,6 +3403,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3501,6 +3417,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -3513,6 +3430,7 @@ "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=14" @@ -3523,6 +3441,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, + "license": "Python-2.0", "peer": true }, "node_modules/array-buffer-byte-length": { @@ -3530,6 +3449,7 @@ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.5", @@ -3546,13 +3466,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-includes": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -3574,6 +3496,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -3584,6 +3507,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -3605,6 +3529,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -3626,6 +3551,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -3645,6 +3571,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -3659,24 +3586,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, "node_modules/array.prototype.tosorted": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -3694,6 +3609,7 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -3715,13 +3631,15 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -3734,9 +3652,10 @@ } }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3744,10 +3663,11 @@ } }, "node_modules/babel-loader": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", "dev": true, + "license": "MIT", "dependencies": { "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" @@ -3764,6 +3684,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -3779,6 +3700,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.2", @@ -3789,13 +3711,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3806,6 +3729,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2" }, @@ -3817,19 +3741,23 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -3839,6 +3767,7 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3847,10 +3776,11 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -3860,7 +3790,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -3875,6 +3805,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3884,6 +3815,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3892,13 +3824,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bonjour-service": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -3908,13 +3842,16 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -3924,6 +3861,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -3932,9 +3870,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -3950,11 +3888,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -3967,13 +3906,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, + "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -3989,6 +3930,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3998,6 +3940,7 @@ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4016,6 +3959,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4025,15 +3969,16 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, + "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001640", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", - "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", "dev": true, "funding": [ { @@ -4048,12 +3993,14 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4067,6 +4014,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -4076,6 +4024,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4100,6 +4049,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4112,6 +4062,7 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } @@ -4121,6 +4072,7 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", "dev": true, + "license": "MIT", "dependencies": { "source-map": "~0.6.0" }, @@ -4128,11 +4080,22 @@ "node": ">= 10.0" } }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -4146,6 +4109,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4154,6 +4118,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -4161,18 +4126,21 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4185,6 +4153,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12" } @@ -4194,6 +4163,7 @@ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 12.0.0" @@ -4203,13 +4173,15 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -4222,6 +4194,7 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -4240,6 +4213,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4248,19 +4222,22 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/connect-history-api-fallback": { @@ -4268,6 +4245,7 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -4277,6 +4255,7 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -4289,6 +4268,7 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4297,13 +4277,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4312,15 +4294,17 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -4328,11 +4312,12 @@ } }, "node_modules/core-js-pure": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.1.tgz", - "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.1.tgz", + "integrity": "sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==", "dev": true, "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -4342,12 +4327,14 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -4364,6 +4351,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4378,6 +4366,7 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -4409,10 +4398,11 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4425,6 +4415,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -4441,6 +4432,7 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -4453,6 +4445,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -4463,13 +4456,15 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.6", @@ -4488,6 +4483,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -4506,6 +4502,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.6", @@ -4520,11 +4517,12 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4540,6 +4538,7 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/default-browser": { @@ -4547,6 +4546,7 @@ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, + "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -4563,6 +4563,7 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -4570,23 +4571,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4604,6 +4594,7 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4616,6 +4607,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-data-property": "^1.0.1", @@ -4633,6 +4625,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -4642,6 +4635,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -4651,6 +4645,7 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -4660,13 +4655,15 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "path-type": "^4.0.0" @@ -4680,6 +4677,7 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -4692,6 +4690,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -4705,6 +4704,7 @@ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, + "license": "MIT", "dependencies": { "utila": "~0.4" } @@ -4714,6 +4714,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -4733,13 +4734,15 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -4755,6 +4758,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -4769,58 +4773,52 @@ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.816", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.816.tgz", - "integrity": "sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "version": "1.5.41", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", + "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", + "dev": true, + "license": "ISC" }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4834,15 +4832,17 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -4854,6 +4854,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } @@ -4863,6 +4864,7 @@ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", "dev": true, + "license": "MIT", "dependencies": { "stackframe": "^1.3.4" } @@ -4872,6 +4874,7 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -4933,6 +4936,7 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -4945,15 +4949,17 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -4963,12 +4969,12 @@ "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", + "iterator.prototype": "^1.1.3", "safe-array-concat": "^1.1.2" }, "engines": { @@ -4979,13 +4985,15 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-errors": "^1.3.0" @@ -4999,6 +5007,7 @@ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "get-intrinsic": "^1.2.4", @@ -5014,6 +5023,7 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "hasown": "^2.0.0" @@ -5024,6 +5034,7 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-callable": "^1.1.4", @@ -5038,10 +5049,11 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5050,12 +5062,14 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -5064,17 +5078,19 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -5143,6 +5159,7 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7", @@ -5155,16 +5172,18 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7" @@ -5183,41 +5202,45 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "node_modules/eslint-plugin-import-newlines": { @@ -5225,6 +5248,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.4.0.tgz", "integrity": "sha512-+Cz1x2xBLtI9gJbmuYEpvY7F8K75wskBmJ7rk4VRObIJo+jklUJaejFJgtnWeL0dCFWabGEkhausrikXaNbtoQ==", "dev": true, + "license": "MIT", "peer": true, "bin": { "import-linter": "lib/index.js" @@ -5241,6 +5265,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -5252,6 +5277,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -5262,6 +5288,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -5275,6 +5302,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -5284,22 +5312,24 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.0.tgz", - "integrity": "sha512-ukXPNpGby3KjCveCizIS8t1EbuJEHYEu/tBg8GCbn/YbHcXwphyvYCdvRZ/oMRfTscGSSzfsWoZ+ZkAP0/6YMQ==", + "version": "48.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.11.0.tgz", + "integrity": "sha512-d12JHJDPNo7IFwTOAItCeJY1hcqoIxE0lHA8infQByLilQ9xkqrRa6laWCnsuCrf+8rUnvxXY1XuTbibRBNylA==", "dev": true, + "license": "BSD-3-Clause", "peer": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.43.1", + "@es-joy/jsdoccomment": "~0.46.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.4", + "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "parse-imports": "^2.1.0", - "semver": "^7.6.2", + "espree": "^10.1.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", + "semver": "^7.6.3", "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.0" + "synckit": "^0.9.1" }, "engines": { "node": ">=18" @@ -5308,11 +5338,45 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" @@ -5326,6 +5390,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "eslint-rule-composer": "^0.3.0", @@ -5339,36 +5404,37 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", - "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "version": "7.37.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", + "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.hasown": "^1.1.4", "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { @@ -5376,6 +5442,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=10" @@ -5389,6 +5456,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -5400,6 +5468,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -5413,6 +5482,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -5426,6 +5496,7 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-core-module": "^2.13.0", @@ -5444,6 +5515,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", "dev": true, + "license": "MIT", "peer": true, "peerDependencies": { "eslint": ">=5.0.0" @@ -5454,6 +5526,7 @@ "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=4.0.0" @@ -5464,6 +5537,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "esrecurse": "^4.3.0", @@ -5481,6 +5555,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5494,6 +5569,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "color-convert": "^2.0.1" @@ -5510,6 +5586,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -5521,6 +5598,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -5538,6 +5616,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "color-name": "~1.1.4" @@ -5551,6 +5630,7 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/eslint/node_modules/globals": { @@ -5558,6 +5638,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "type-fest": "^0.20.2" @@ -5574,6 +5655,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -5584,6 +5666,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -5597,6 +5680,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-flag": "^4.0.0" @@ -5610,6 +5694,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "acorn": "^8.9.0", @@ -5624,10 +5709,11 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "peer": true, "dependencies": { "estraverse": "^5.1.0" @@ -5641,6 +5727,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5653,6 +5740,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -5662,6 +5750,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -5671,6 +5760,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5679,72 +5769,52 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5760,6 +5830,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -5768,19 +5839,22 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5798,6 +5872,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "is-glob": "^4.0.1" @@ -5810,20 +5885,30 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, + "license": "MIT", "peer": true }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.9.1" } @@ -5833,6 +5918,7 @@ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "reusify": "^1.0.4" @@ -5843,6 +5929,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -5855,6 +5942,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "flat-cache": "^3.0.4" @@ -5868,6 +5956,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5876,13 +5965,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -5898,6 +5988,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -5906,13 +5997,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dev": true, + "license": "MIT", "dependencies": { "common-path-prefix": "^3.0.0", "pkg-dir": "^7.0.0" @@ -5927,13 +6020,15 @@ "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "locate-path": "^6.0.0", @@ -5951,6 +6046,7 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -5960,6 +6056,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "flatted": "^3.2.9", @@ -5975,18 +6072,20 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -6001,43 +6100,17 @@ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-callable": "^1.1.3" } }, - "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6052,6 +6125,7 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6061,6 +6135,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6070,6 +6145,7 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/fsevents": { @@ -6078,6 +6154,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6090,6 +6167,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6099,6 +6177,7 @@ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -6118,6 +6197,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6128,6 +6208,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -6137,6 +6218,7 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -6151,23 +6233,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.5", @@ -6187,6 +6258,7 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -6208,6 +6280,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "is-glob": "^4.0.3" @@ -6220,13 +6293,15 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -6238,6 +6313,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -6250,6 +6326,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } @@ -6259,6 +6336,7 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-properties": "^1.2.1", @@ -6276,6 +6354,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-union": "^2.1.0", @@ -6297,6 +6376,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -6308,26 +6388,30 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6337,6 +6421,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -6346,6 +6431,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -6358,6 +6444,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6370,6 +6457,7 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6382,6 +6470,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-symbols": "^1.0.3" @@ -6397,6 +6486,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -6409,6 +6499,7 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -6417,15 +6508,23 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", "dependencies": { "react-is": "^16.7.0" } }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -6437,13 +6536,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6458,13 +6559,15 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -6483,13 +6586,15 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "dev": true, + "license": "MIT", "dependencies": { "camel-case": "^4.1.2", "clean-css": "^5.2.2", @@ -6507,10 +6612,11 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", - "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.2.tgz", + "integrity": "sha512-q7xp/FO9RGBVoTKNItkdX1jKLscLFkgn/dLVFNYbHVbfHLBk6DYW5nsQ8kCzIWcgKP/kUBocetjvav6lD8YfCQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -6550,6 +6656,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -6561,13 +6668,15 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -6583,13 +6692,15 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -6600,10 +6711,11 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -6623,20 +6735,12 @@ } } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/hyperdyperid": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.18" } @@ -6646,6 +6750,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -6658,6 +6763,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -6666,10 +6772,11 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 4" @@ -6679,6 +6786,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -6691,10 +6799,11 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -6714,6 +6823,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -6727,6 +6837,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -6739,6 +6850,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -6754,6 +6866,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -6766,6 +6879,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -6778,6 +6892,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=0.8.19" @@ -6789,6 +6904,7 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "once": "^1.3.0", @@ -6799,13 +6915,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-errors": "^1.3.0", @@ -6821,6 +6939,7 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -6830,6 +6949,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -6839,6 +6959,7 @@ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -6854,13 +6975,15 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -6877,6 +7000,7 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-bigints": "^1.0.1" @@ -6890,6 +7014,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -6902,6 +7027,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -6919,6 +7045,7 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -6928,9 +7055,10 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -6946,6 +7074,7 @@ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-typed-array": "^1.1.13" @@ -6962,6 +7091,7 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -6978,6 +7108,7 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -6993,6 +7124,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7002,6 +7134,7 @@ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2" @@ -7010,20 +7143,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -7040,6 +7165,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -7052,6 +7178,7 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -7070,6 +7197,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -7083,6 +7211,7 @@ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -7096,6 +7225,7 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -7108,6 +7238,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -7117,6 +7248,7 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -7133,6 +7265,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -7143,6 +7276,7 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7155,6 +7289,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -7167,6 +7302,7 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -7184,6 +7320,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -7197,6 +7334,7 @@ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7" @@ -7208,23 +7346,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -7241,6 +7368,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-symbols": "^1.0.2" @@ -7257,6 +7385,7 @@ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "which-typed-array": "^1.1.14" @@ -7273,6 +7402,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -7286,6 +7416,7 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2" @@ -7299,6 +7430,7 @@ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -7316,6 +7448,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, + "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -7331,28 +7464,32 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-properties": "^1.2.1", @@ -7360,24 +7497,9 @@ "has-symbols": "^1.0.3", "reflect.getprototypeof": "^1.0.4", "set-function-name": "^2.0.1" - } - }, - "node_modules/jackspeak": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", - "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "node": ">= 0.4" } }, "node_modules/jest-worker": { @@ -7385,6 +7507,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -7399,6 +7522,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7408,6 +7532,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7421,13 +7546,15 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "argparse": "^2.0.1" @@ -7441,20 +7568,22 @@ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=12.0.0" } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { @@ -7462,24 +7591,28 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/json5": { @@ -7487,6 +7620,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -7499,6 +7633,7 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.6", @@ -7515,6 +7650,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "json-buffer": "3.0.1" @@ -7525,15 +7661,17 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -7544,6 +7682,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "prelude-ls": "^1.2.1", @@ -7556,13 +7695,15 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } @@ -7572,6 +7713,7 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -7586,6 +7728,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "p-locate": "^5.0.0" @@ -7601,25 +7744,29 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -7632,6 +7779,7 @@ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -7641,6 +7789,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -7650,18 +7799,20 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/memfs": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", - "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", + "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", + "@jsonjoy.com/util": "^1.3.0", "tree-dump": "^1.0.1", "tslib": "^2.0.0" }, @@ -7674,22 +7825,28 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 8" @@ -7700,15 +7857,17 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -7722,6 +7881,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7734,6 +7894,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -7745,6 +7906,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7753,6 +7915,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -7760,20 +7923,12 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/mini-css-extract-plugin": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", - "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.1.tgz", + "integrity": "sha512-+Vyi+GCCOHnrJ2VPS+6aPoXN2k2jgUzDRhTFLjjTBn23qyXJXkjUWQgTL+mXpF5/A8ixLdCc6kWsoeOjKGejKQ==", "dev": true, + "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -7793,13 +7948,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7816,30 +7973,24 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -7859,6 +8010,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -7871,6 +8023,7 @@ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/negotiator": { @@ -7878,6 +8031,7 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7886,13 +8040,15 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -7903,42 +8059,34 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -7950,6 +8098,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7959,6 +8108,7 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7971,6 +8121,7 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -7981,6 +8132,7 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.5", @@ -8000,6 +8152,7 @@ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8015,6 +8168,7 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8034,6 +8188,7 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8044,29 +8199,12 @@ "node": ">= 0.4" } }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "peer": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8084,13 +8222,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -8103,6 +8243,7 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8112,31 +8253,18 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/open": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, + "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -8155,6 +8283,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "deep-is": "^0.1.3", @@ -8173,6 +8302,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "yocto-queue": "^0.1.0" @@ -8189,6 +8319,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "p-limit": "^3.0.2" @@ -8205,6 +8336,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -8222,21 +8354,17 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true - }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dev": true, + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -8246,6 +8374,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -8254,10 +8383,11 @@ } }, "node_modules/parse-imports": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", - "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", + "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", "dev": true, + "license": "Apache-2.0 AND MIT", "peer": true, "dependencies": { "es-module-lexer": "^1.5.3", @@ -8271,6 +8401,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -8289,6 +8420,7 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8298,6 +8430,7 @@ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -8308,6 +8441,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8317,6 +8451,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=0.10.0" @@ -8327,6 +8462,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8334,57 +8470,37 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", - "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=12" @@ -8398,6 +8514,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^6.3.0" }, @@ -8413,6 +8530,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" @@ -8429,6 +8547,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^6.0.0" }, @@ -8444,6 +8563,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^1.0.0" }, @@ -8459,6 +8579,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^4.0.0" }, @@ -8474,6 +8595,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } @@ -8483,6 +8605,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -8495,15 +8618,16 @@ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "dev": true, "funding": [ { @@ -8519,10 +8643,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -8533,6 +8658,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -8545,6 +8671,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -8562,6 +8689,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, + "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -8577,6 +8705,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -8588,10 +8717,11 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", - "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -8604,13 +8734,15 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.8.0" @@ -8621,6 +8753,7 @@ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4.17.20", "renderkid": "^3.0.0" @@ -8630,23 +8763,32 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -8660,6 +8802,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -8667,24 +8810,27 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -8712,6 +8858,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "peer": true }, "node_modules/randombytes": { @@ -8719,6 +8866,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -8728,6 +8876,7 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8737,6 +8886,7 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -8752,6 +8902,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8760,6 +8911,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -8771,6 +8923,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -8780,15 +8933,17 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8798,6 +8953,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -8812,6 +8968,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -8824,6 +8981,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -8836,6 +8994,7 @@ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, + "license": "MIT", "dependencies": { "resolve": "^1.20.0" }, @@ -8848,6 +9007,7 @@ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8869,13 +9029,15 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -8886,28 +9048,31 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -8917,15 +9082,16 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -8933,32 +9099,32 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", + "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -8968,6 +9134,7 @@ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", "dev": true, + "license": "MIT", "dependencies": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", @@ -8981,6 +9148,7 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8989,12 +9157,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -9012,6 +9182,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -9024,6 +9195,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9032,6 +9204,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", "engines": { "node": ">=4" } @@ -9041,6 +9214,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -9050,6 +9224,7 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "iojs": ">=1.0.0", @@ -9062,6 +9237,7 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "glob": "^7.1.3" @@ -9078,6 +9254,7 @@ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -9104,6 +9281,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "peer": true, "dependencies": { "queue-microtask": "^1.2.2" @@ -9114,6 +9292,7 @@ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9146,13 +9325,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.6", @@ -9170,12 +9351,14 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -9185,6 +9368,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -9200,15 +9384,16 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -9220,6 +9405,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -9231,19 +9417,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selfsigned": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -9257,15 +9446,17 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -9290,6 +9481,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9298,19 +9490,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -9320,6 +9518,7 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -9338,6 +9537,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9347,6 +9547,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9356,6 +9557,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -9370,39 +9572,44 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -9413,6 +9620,7 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -9430,6 +9638,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-data-property": "^1.1.4", @@ -9445,13 +9654,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -9464,6 +9675,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9476,6 +9688,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9485,6 +9698,7 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9494,6 +9708,7 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -9507,17 +9722,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -9528,6 +9738,7 @@ "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/sockjs": { @@ -9535,6 +9746,7 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -9542,19 +9754,20 @@ } }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -9564,16 +9777,28 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, + "license": "CC-BY-3.0", "peer": true }, "node_modules/spdx-expression-parse": { @@ -9581,6 +9806,7 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -9588,10 +9814,11 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", "dev": true, + "license": "CC0-1.0", "peer": true }, "node_modules/spdy": { @@ -9599,6 +9826,7 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -9615,6 +9843,7 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -9628,13 +9857,15 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9644,80 +9875,17 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9740,11 +9908,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9764,6 +9945,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9779,6 +9961,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9797,19 +9980,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9822,25 +9993,18 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=4" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -9854,6 +10018,7 @@ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 18.12.0" }, @@ -9868,12 +10033,14 @@ "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -9885,6 +10052,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9893,10 +10061,11 @@ } }, "node_modules/synckit": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", - "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -9914,15 +10083,17 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/terser": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", - "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -9941,6 +10112,7 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", @@ -9975,6 +10147,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -9992,13 +10165,15 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/thingies": { @@ -10006,6 +10181,7 @@ "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, + "license": "Unlicense", "engines": { "node": ">=10.18" }, @@ -10017,12 +10193,14 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", "engines": { "node": ">=4" } @@ -10032,6 +10210,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -10044,6 +10223,7 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } @@ -10053,6 +10233,7 @@ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -10069,6 +10250,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=16" @@ -10082,6 +10264,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/json5": "^0.0.29", @@ -10095,6 +10278,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "minimist": "^1.2.0" @@ -10104,16 +10288,18 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "dev": true, + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "prelude-ls": "^1.2.1" @@ -10127,6 +10313,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "peer": true, "engines": { "node": ">=10" @@ -10140,6 +10327,7 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -10153,6 +10341,7 @@ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -10168,6 +10357,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -10188,6 +10378,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -10209,6 +10400,7 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -10226,10 +10418,11 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, + "license": "Apache-2.0", "peer": true, "bin": { "tsc": "bin/tsc", @@ -10244,6 +10437,7 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -10256,16 +10450,18 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10275,6 +10471,7 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -10284,10 +10481,11 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10297,6 +10495,7 @@ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10306,14 +10505,15 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -10329,9 +10529,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -10345,6 +10546,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -10353,19 +10555,22 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -10375,6 +10580,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -10384,15 +10590,17 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -10406,17 +10614,18 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", @@ -10425,7 +10634,7 @@ "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -10462,6 +10671,7 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^2.1.1", @@ -10507,15 +10717,17 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } }, "node_modules/webpack-dev-middleware": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", - "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", @@ -10541,10 +10753,11 @@ } }, "node_modules/webpack-dev-server": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", - "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz", + "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -10559,8 +10772,7 @@ "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", + "express": "^4.19.2", "graceful-fs": "^4.2.6", "html-entities": "^2.4.0", "http-proxy-middleware": "^2.0.3", @@ -10568,14 +10780,13 @@ "launch-editor": "^2.6.1", "open": "^10.0.3", "p-retry": "^6.2.0", - "rimraf": "^5.0.5", "schema-utils": "^4.2.0", "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.1.0", - "ws": "^8.16.0" + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" @@ -10599,67 +10810,12 @@ } } }, - "node_modules/webpack-dev-server/node_modules/glob": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", - "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/webpack-dev-server/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/webpack-dev-server/node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", @@ -10674,6 +10830,7 @@ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -10683,6 +10840,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -10696,6 +10854,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -10705,6 +10864,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -10723,6 +10883,7 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -10737,6 +10898,7 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -10746,6 +10908,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -10761,6 +10924,7 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-bigint": "^1.0.1", @@ -10774,14 +10938,15 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -10790,8 +10955,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -10805,6 +10970,7 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-map": "^2.0.3", @@ -10824,6 +10990,7 @@ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -10843,150 +11010,26 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/ws": { @@ -10994,6 +11037,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -11014,12 +11058,14 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { "node": ">= 6" } @@ -11029,6 +11075,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=10" diff --git a/components/log-viewer-webui/client/package.json b/components/log-viewer-webui/client/package.json index 8978b8aee..906d6eba7 100644 --- a/components/log-viewer-webui/client/package.json +++ b/components/log-viewer-webui/client/package.json @@ -24,9 +24,9 @@ "mini-css-extract-plugin": "^2.9.0", "react-refresh": "^0.14.2", "style-loader": "^4.0.0", - "webpack": "^5.92.1", + "webpack": "^5.95.0", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4" + "webpack-dev-server": "^5.1.0" }, "eslintConfig": { "extends": [ diff --git a/components/log-viewer-webui/server/package-lock.json b/components/log-viewer-webui/server/package-lock.json index b5ad7d428..d16171d80 100644 --- a/components/log-viewer-webui/server/package-lock.json +++ b/components/log-viewer-webui/server/package-lock.json @@ -32,6 +32,7 @@ "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.1.3.tgz", "integrity": "sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^4.0.0" @@ -45,6 +46,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -57,6 +59,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -69,6 +72,7 @@ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -78,25 +82,15 @@ "node": ">=6.0.0" } }, - "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -104,32 +98,34 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.8", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.8", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -144,34 +140,12 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/eslint-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.8.tgz", - "integrity": "sha512-nYAikI4XTGokU2QX7Jx+v4rxZKhKivaQaREZjuW3mrJrbdWJ5yUfohnoUULge+zEEaKjPYNxhoRgUKktjXtbwA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.8.tgz", + "integrity": "sha512-Po3VLMN7fJtv0nsOjBDSbO1J71UhzShE9MuOSkWEV9IZQXzhZklYtzKZ8ZD/Ij3a0JBv1AG3Ny2L3jvAHQVOGg==", "dev": true, + "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -185,61 +159,34 @@ "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", - "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/types": "^7.24.9", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -247,99 +194,33 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "peer": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "peer": true - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -349,93 +230,87 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -444,90 +319,16 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "peer": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "peer": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/parser": { + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "has-flag": "^3.0.0" + "@babel/types": "^7.25.8" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", - "dev": true, - "peer": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -536,12 +337,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", + "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -551,35 +353,34 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -587,25 +388,16 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -616,19 +408,22 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -636,11 +431,23 @@ "node": ">=12" } }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.46.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "comment-parser": "1.4.1", @@ -656,6 +463,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -667,11 +475,26 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -682,6 +505,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ajv": "^6.12.4", @@ -706,17 +530,36 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -725,11 +568,26 @@ "node": "*" } }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -739,6 +597,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", + "license": "MIT", "engines": { "node": ">=14" } @@ -747,6 +606,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz", "integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==", + "license": "MIT", "dependencies": { "ajv": "^8.11.0", "ajv-formats": "^2.1.1", @@ -757,6 +617,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -769,24 +630,28 @@ } }, "node_modules/@fastify/ajv-compiler/node_modules/ajv/node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "license": "BSD-3-Clause" }, "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/@fastify/error": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", - "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==" + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==", + "license": "MIT" }, "node_modules/@fastify/fast-json-stringify-compiler": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "license": "MIT", "dependencies": { "fast-json-stringify": "^5.7.0" } @@ -795,6 +660,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" } @@ -803,6 +669,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/@fastify/mongodb/-/mongodb-8.0.0.tgz", "integrity": "sha512-IDw/wWpdc53+Y5sPpMg+ek71HOIVuz8NoD2GlfIOcvGE/lYdrZvnFQxqJcaZtlwPZ7YflDDkIu5aNkCPWdZQ0Q==", + "license": "MIT", "dependencies": { "fastify-plugin": "^4.0.0", "mongodb": "^6.0.0" @@ -812,6 +679,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@fastify/mysql/-/mysql-4.3.0.tgz", "integrity": "sha512-eVx5/PyMmoBWp3hTaqdvXiZdo8YnKsAx3k/8AEXgI/MjUbgcn8YrSdy8eHSpCL3YZtBhD/2vLpOXFFciyqlWjQ==", + "license": "MIT", "dependencies": { "fastify-plugin": "^4.0.0", "mysql2": "^3.9.7" @@ -821,6 +689,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", + "license": "MIT", "dependencies": { "@lukeed/ms": "^2.0.1", "escape-html": "~1.0.3", @@ -833,6 +702,7 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz", "integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==", + "license": "MIT", "dependencies": { "@fastify/accept-negotiator": "^1.0.0", "@fastify/send": "^2.0.0", @@ -843,14 +713,15 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -863,6 +734,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -874,6 +746,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -887,6 +760,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "peer": true, "engines": { "node": ">=12.22" @@ -902,12 +776,14 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", "dev": true, + "license": "BSD-3-Clause", "peer": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -921,9 +797,10 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -935,6 +812,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -950,6 +828,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.7.tgz", "integrity": "sha512-9f0bhUr9TnwwpgUhEpr3FjxSaH/OHaARkE2F9fM0lS4nIs2GNerrvGwQz493dk0JKlTaGYVrKbq36vA/whZ34g==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node14": "*", @@ -990,6 +869,7 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -999,6 +879,7 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1008,6 +889,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -1018,22 +900,12 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1043,6 +915,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6.0.0" @@ -1052,30 +925,34 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@lukeed/ms": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", - "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -1084,6 +961,7 @@ "version": "3.0.0-beta2", "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz", "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==", + "license": "ISC", "engines": { "node": ">= 14" } @@ -1093,37 +971,17 @@ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, + "license": "MIT", "dependencies": { "eslint-scope": "5.1.1" } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -1138,6 +996,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 8" @@ -1148,6 +1007,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -1162,6 +1022,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", "dev": true, + "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -1177,13 +1038,15 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@npmcli/fs": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, + "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -1191,11 +1054,25 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@npmcli/git": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "ini": "^4.1.3", @@ -1216,6 +1093,7 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16" } @@ -1224,13 +1102,28 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/@npmcli/git/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, "node_modules/@npmcli/git/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -1246,6 +1139,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", "dev": true, + "license": "ISC", "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -1262,15 +1156,17 @@ "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/package-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.0.tgz", - "integrity": "sha512-qe/kiqqkW0AGtvBjL8TJKZk/eBBSpnJkUWvHdQ9jM2lKHXRYYJuyNpJPlJw3c8QjC2ow6NZYiLExhUaeJelbxQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.1.tgz", + "integrity": "sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "glob": "^10.2.2", @@ -1284,11 +1180,25 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@npmcli/package-json/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@npmcli/promise-spawn": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", "dev": true, + "license": "ISC", "dependencies": { "which": "^4.0.0" }, @@ -1301,6 +1211,7 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16" } @@ -1310,6 +1221,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -1325,6 +1237,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", "dev": true, + "license": "ISC", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -1334,6 +1247,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.0.0", @@ -1350,6 +1264,7 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16" } @@ -1359,6 +1274,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -1373,6 +1289,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1383,6 +1300,7 @@ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -1391,11 +1309,20 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@sigstore/bundle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.3.2" }, @@ -1408,6 +1335,7 @@ "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -1417,6 +1345,7 @@ "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -1426,6 +1355,7 @@ "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", @@ -1443,6 +1373,7 @@ "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.3.2", "tuf-js": "^2.2.1" @@ -1456,6 +1387,7 @@ "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.1.0", @@ -1470,6 +1402,7 @@ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.8.1.tgz", "integrity": "sha512-c5c2C8Mos5tTQd+NWpqwEu7VT6SSRooAguFPMj1cp2RkTYl1ynKoXo8MWy3k4rkbzoeYHrqC2UlUzsroAN7wtQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -1485,11 +1418,26 @@ "eslint": ">=8.40.0" } }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@stylistic/eslint-plugin-jsx": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.8.1.tgz", "integrity": "sha512-k1Eb6rcjMP+mmjvj+vd9y5KUdWn1OBkkPLHXhsrHt5lCDFZxJEs0aVQzE5lpYrtVZVkpc5esTtss/cPJux0lfA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@stylistic/eslint-plugin-js": "^1.8.1", @@ -1509,6 +1457,7 @@ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.8.1.tgz", "integrity": "sha512-4+40H3lHYTN8OWz+US8CamVkO+2hxNLp9+CAjorI7top/lHqemhpJvKA1LD9Uh+WMY9DYWiWpL2+SZ2wAXY9fQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/eslint": "^8.56.10", @@ -1523,6 +1472,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.31.tgz", "integrity": "sha512-531NkYOls9PvqfnLsEDRzIWwjynoFRbUVq7pTYuA3PRIw4Ka7jA9uUjILeUurcWjaHrQNzUua0jj/Yu94f6YYw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "is-actual-promise": "^1.0.1" }, @@ -1538,6 +1488,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-2.0.8.tgz", "integrity": "sha512-btkpQ/BhmRyG50rezduxEZb3pMJblECvTQa41+U2ln2te1prDTlllHlpq4lOjceUksl8KFF1avDqcBqIqPzneQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "function-loop": "^4.0.0" }, @@ -1553,6 +1504,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-2.0.8.tgz", "integrity": "sha512-57VrI0p2kAqfgHHUwowDvd31eTfDHw3HO4FSSVUCvngPGWa96R6eH9gXa9fNig4qIp4Dup+nI7gJlJfU0R80SA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/stack": "2.0.1", "is-actual-promise": "^1.0.1", @@ -1574,6 +1526,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-2.0.8.tgz", "integrity": "sha512-22ZdGSn/zOKf8J8cb3yfw5R4I/ozdHEDKL8lBWon/zsxxMMvaRTgOtFXEjb4RE+5SDrqQ4NM7ZRYPGhE7T97dw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "is-actual-promise": "^1.0.1" }, @@ -1589,6 +1542,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-2.0.8.tgz", "integrity": "sha512-Xjgk8/fuP7iFa5CYjFDl05p5PZGRe//VyHJNuYNzWpF1K9PNMtVdlmwplfpFmbrNrw/bIPq7R6LuiPmTBgzuOw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "function-loop": "^4.0.0" }, @@ -1604,6 +1558,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/chdir/-/chdir-1.1.4.tgz", "integrity": "sha512-axXkT5kWp2/X8l6inKyrqzUhqgvsgrWI8/0xLAdmirpFZ8H6gFxrl763Ozdm27EAmkLnnnWgFITPqUQCuB/tMA==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, @@ -1616,6 +1571,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-3.1.6.tgz", "integrity": "sha512-5gkDMSLXL5798bbCdX4RdLpB4OUQeu9TXftzKmL1+1T2xbcd4q7zfDnCfOB9zTk50x2f04+4h6Q7Z1NcSKIspg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/core": "2.1.6", "@tapjs/test": "2.2.4", @@ -1641,6 +1597,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -1653,6 +1610,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-2.1.6.tgz", "integrity": "sha512-NYMp0bl52DxXfcLmivMKvOIE14aaB9qJjdHeUbs6GZ9yxgD5w0yeiOT+gWEL+1PzZgGWRxSFEpghID1YfXAc4w==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/processinfo": "^3.1.8", "@tapjs/stack": "2.0.1", @@ -1676,6 +1634,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-2.0.1.tgz", "integrity": "sha512-P+M4rtcfkDsUveKKmoRNF+07xpbPnRY5KrstIUOnyn483clQ7BJhsnWr162yYNCsyOj4zEfZmAJI1f8Bi7h/ZA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "minipass": "^7.0.4" }, @@ -1691,6 +1650,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-2.0.8.tgz", "integrity": "sha512-/ps6nOS3CTh1WLfCjJnU7tS4PH4KFgEasFSVPCIFN+BasyoqDapzj4JKIlzQvppZOGTQadKH3wUakafZl7uz8w==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, @@ -1706,6 +1666,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-2.0.8.tgz", "integrity": "sha512-LJnjeAMSozPFXzu+wQw2HJsjA9djHbTcyeMnsgiRL/Q8ffcLqAawV3SN6XKdDLdWYUg3e1fXhHspnbsouZj+xA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "mkdirp": "^3.0.0", "rimraf": "^5.0.5" @@ -1721,19 +1682,17 @@ } }, "node_modules/@tapjs/fixture/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -1743,6 +1702,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-2.0.8.tgz", "integrity": "sha512-OF2Q35jtZ20bwV4hRNoca7vqIrzPFR3JR25G2rGru+fgPmq4heN0RLoh0d1O34AbrtXqra2lXkacMB/DPgb01A==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/after": "1.1.31", "@tapjs/stack": "2.0.1" @@ -1759,6 +1719,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-2.1.6.tgz", "integrity": "sha512-bNXKrjg/r+i/gfKij5Oo/5Md2DvGNHPSRCHQmjz3VQjpyxqK7S1FGcR0kyqJ8Nof6Wc8yIhpNOCuibj19200IQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/after": "1.1.31", "@tapjs/stack": "2.0.1", @@ -1780,6 +1741,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-2.0.8.tgz", "integrity": "sha512-92oqhkmIz5wr0yRs1CPQfim5JSwHPSmoDWnQmJlYUZsY1OYgYouQm3ifnPkqK/9hJpVYzlZEQmefxehxbs2WNQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/error-serdes": "2.0.1", "@tapjs/stack": "2.0.1", @@ -1800,6 +1762,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.8.tgz", "integrity": "sha512-FIriEB+qqArPhmVYc1PZwRHD99myRdl7C9Oe/uts04Q2LOxQ5MEmqP9XOP8vVYzpDOYwmL8OmL6eOYt9eZlQKQ==", "dev": true, + "license": "ISC", "dependencies": { "pirates": "^4.0.5", "process-on-spawn": "^1.0.0", @@ -1815,6 +1778,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-2.0.8.tgz", "integrity": "sha512-tZn5ZHIrFwjbi59djtdXHBwgSIZSBXdJpz2i9CZ9HEC1nFhWtIr2Jczvrz4ScfixUgA0GNFirz+q+9iA4IFMvw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/config": "3.1.6", "@tapjs/stack": "2.0.1", @@ -1845,6 +1809,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -1852,17 +1817,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@tapjs/reporter/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/@tapjs/run": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-2.1.7.tgz", "integrity": "sha512-Hk41E68f1x4eLBm6Rrxx4ARzZzrjwaLbKThb16+f3bGYiajmqAvBdeyNEoQpEWmW+Sv2HSlueOk2SS2P4fyetg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/after": "1.1.31", "@tapjs/before": "2.0.8", @@ -1909,6 +1869,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -1921,33 +1882,46 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16" } }, "node_modules/@tapjs/run/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@tapjs/run/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@tapjs/run/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -1963,6 +1937,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-2.0.8.tgz", "integrity": "sha512-L0vtqWKkgnQt/XNQkvHOme9Np7ffteCNf1P0F9mz2YiJion4er1nv6pZuJoKVxXFQsbNd2k+LGyx0Iw+bIzwFg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "is-actual-promise": "^1.0.1", "tcompare": "7.0.1", @@ -1983,6 +1958,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-2.0.8.tgz", "integrity": "sha512-vCYwynIYJNijY87uHFANe+gCu9rdGoe4GOBmghl6kwDy7eISmcN/FW5TlmrjePMNhTvrDMeYqOIAzqh3WRYmPA==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, @@ -1995,6 +1971,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-2.0.1.tgz", "integrity": "sha512-3rKbZkRkLeJl9ilV/6b80YfI4C4+OYf7iEz5/d0MIVhmVvxv0ttIy5JnZutAc4Gy9eRp5Ne5UTAIFOVY5k36cg==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, @@ -2007,6 +1984,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-2.0.8.tgz", "integrity": "sha512-tW/exLXuDqjtH2wjptiPHXBahkdSyoppxDY56l9MG4tiz66dMN6NTCZFvQxp7+3t+lsQKqJp/74z8T/ayp+vZA==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, @@ -2019,6 +1997,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-2.2.4.tgz", "integrity": "sha512-QIgq2BhMpwO9SN8I0qlwZYXAllO4xWCfJ0MgAGhc+J7p69B5p9dDNPmyOreHeXWMmk6VlNj3oWveoXb5Zn9xZQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.7", "@tapjs/after": "1.1.31", @@ -2060,19 +2039,17 @@ } }, "node_modules/@tapjs/test/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -2082,6 +2059,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2095,6 +2073,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.4.13.tgz", "integrity": "sha512-MNs7zlhM6G3pNUIjkKXDxgNCwCGZt2bUCGtVunSTDVIrKiUlHAl4QSjQ1oTjumHlCi9gFIWiwFAvpHekzFti0w==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.7" }, @@ -2110,6 +2089,7 @@ "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-2.0.8.tgz", "integrity": "sha512-AySf2kV6OHvwgD3DrLdT2az2g4hRdoRtKsFCLdZo3jOoKte+ft/IQJEnOW7CPT0RYUskS3elv6eabYgSyTH4tg==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, @@ -2121,31 +2101,36 @@ "version": "14.1.2", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-14.1.2.tgz", "integrity": "sha512-1vncsbfCZ3TBLPxesRYz02Rn7SNJfbLoDVkcZ7F/ixOV6nwxwgdhD1mdPcc5YQ413qBJ8CvMxXMFfJ7oawjo7Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "16.1.3", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-16.1.3.tgz", "integrity": "sha512-9nTOUBn+EMKO6rtSZJk+DcqsfgtlERGT9XPJ5PRj/HNENPCBY1yu/JEj5wT6GLtbCLBO2k46SeXDaY0pjMqypw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node18": { "version": "18.2.4", "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node20": { "version": "20.1.4", "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", "integrity": "sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", "dev": true, + "license": "MIT", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -2155,6 +2140,7 @@ "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", "dev": true, + "license": "MIT", "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.4" @@ -2168,6 +2154,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2179,10 +2166,11 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "8.56.12", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz", + "integrity": "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/estree": "*", @@ -2190,23 +2178,26 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@types/json5": { @@ -2214,16 +2205,18 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "22.7.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.7.tgz", + "integrity": "sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/semver": { @@ -2231,17 +2224,20 @@ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, "node_modules/@types/whatwg-url": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", "dependencies": { "@types/webidl-conversions": "*" } @@ -2251,6 +2247,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@typescript-eslint/types": "6.21.0", @@ -2269,6 +2266,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2283,6 +2281,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "@typescript-eslint/types": "6.21.0", @@ -2307,11 +2306,26 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/utils": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -2333,11 +2347,26 @@ "eslint": "^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@typescript-eslint/types": "6.21.0", @@ -2351,11 +2380,26 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/abbrev": { @@ -2363,6 +2407,7 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -2371,6 +2416,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" }, @@ -2381,13 +2427,15 @@ "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", - "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2400,16 +2448,18 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -2422,6 +2472,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -2434,6 +2485,7 @@ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -2447,6 +2499,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2456,6 +2509,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -2472,6 +2526,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -2488,6 +2543,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -2500,20 +2556,23 @@ } }, "node_modules/ajv-formats/node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "license": "BSD-3-Clause" }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/ansi-escapes": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.16" }, @@ -2525,22 +2584,23 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/anymatch": { @@ -2548,6 +2608,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2561,6 +2622,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -2573,6 +2635,7 @@ "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=14" @@ -2582,13 +2645,15 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, + "license": "Python-2.0", "peer": true }, "node_modules/array-buffer-byte-length": { @@ -2596,6 +2661,7 @@ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.5", @@ -2613,6 +2679,7 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -2634,6 +2701,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -2644,6 +2712,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -2665,6 +2734,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -2686,6 +2756,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -2705,6 +2776,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -2719,24 +2791,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, "node_modules/array.prototype.tosorted": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -2754,6 +2814,7 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -2777,6 +2838,7 @@ "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-4.0.1.tgz", "integrity": "sha512-bSktexGodAjfHWIrSrrqxqWzf1hWBZBpmPNZv+TYUMyWa2eoefFc6q6H1+KtdHYSz35lrhWdmXt/XK9wNEZvww==", "dev": true, + "license": "ISC", "engines": { "node": ">=16" } @@ -2785,6 +2847,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -2794,6 +2857,7 @@ "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -2806,6 +2870,7 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -2818,18 +2883,20 @@ } }, "node_modules/avvio": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.3.2.tgz", - "integrity": "sha512-st8e519GWHa/azv8S87mcJvZs4WsgTBjOw/Ih1CP6u+8SZvcOeAYNG6JbsIrAUUJJ7JfmrnOkR8ipDS+u9SIRQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.4.0.tgz", + "integrity": "sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==", + "license": "MIT", "dependencies": { "@fastify/error": "^3.3.0", "fastq": "^1.17.1" } }, "node_modules/aws-ssl-profiles": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", - "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", "engines": { "node": ">= 6.0.0" } @@ -2837,7 +2904,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2856,13 +2924,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2874,6 +2944,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -2883,6 +2954,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -2891,9 +2963,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -2909,11 +2981,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, "bin": { @@ -2927,6 +3000,7 @@ "version": "6.8.0", "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "license": "Apache-2.0", "engines": { "node": ">=16.20.1" } @@ -2949,6 +3023,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -2959,6 +3034,7 @@ "resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz", "integrity": "sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg==", "dev": true, + "license": "ISC", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@istanbuljs/schema": "^0.1.3", @@ -2984,6 +3060,7 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -3006,13 +3083,15 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-define-property": "^1.0.0", @@ -3033,15 +3112,16 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", "dev": true, "funding": [ { @@ -3057,23 +3137,34 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "CC-BY-4.0", "peer": true }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.0" } }, "node_modules/chokidar": { @@ -3081,6 +3172,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3105,6 +3197,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -3117,6 +3210,7 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -3132,6 +3226,7 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } @@ -3141,6 +3236,7 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3150,6 +3246,7 @@ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3162,6 +3259,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^4.0.0" }, @@ -3177,6 +3275,7 @@ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^5.0.0" @@ -3193,6 +3292,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3205,6 +3305,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -3217,6 +3318,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" @@ -3233,6 +3335,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -3242,17 +3345,55 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3267,6 +3408,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3284,6 +3426,7 @@ "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", "dev": true, + "license": "MIT", "dependencies": { "convert-to-spaces": "^2.0.1" }, @@ -3292,31 +3435,36 @@ } }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 12.0.0" @@ -3326,12 +3474,14 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -3343,21 +3493,24 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/convert-to-spaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3366,6 +3519,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3380,6 +3534,7 @@ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.6", @@ -3398,6 +3553,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -3416,6 +3572,7 @@ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.6", @@ -3433,17 +3590,19 @@ "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3459,6 +3618,7 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/define-data-property": { @@ -3466,6 +3626,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-define-property": "^1.0.0", @@ -3484,6 +3645,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-data-property": "^1.0.1", @@ -3501,6 +3663,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", "engines": { "node": ">=0.10" } @@ -3509,6 +3672,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3518,6 +3682,7 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -3527,6 +3692,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "path-type": "^4.0.0" @@ -3540,6 +3706,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -3552,6 +3719,7 @@ "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -3562,25 +3730,29 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.828", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.828.tgz", - "integrity": "sha512-QOIJiWpQJDHAVO4P58pwb133Cwee0nbvy/MV1CwzZVGpkH1RX33N3vsaWRCpR6bF63AAq366neZrRTu7Qlsbbw==", + "version": "1.5.41", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", + "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -3590,6 +3762,7 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -3599,6 +3772,7 @@ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3607,13 +3781,15 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es-abstract": { "version": "1.23.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -3675,6 +3851,7 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "get-intrinsic": "^1.2.4" @@ -3688,16 +3865,18 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" } }, "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -3707,12 +3886,12 @@ "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", + "iterator.prototype": "^1.1.3", "safe-array-concat": "^1.1.2" }, "engines": { @@ -3724,6 +3903,7 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/es-object-atoms": { @@ -3731,6 +3911,7 @@ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-errors": "^1.3.0" @@ -3744,6 +3925,7 @@ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "get-intrinsic": "^1.2.4", @@ -3759,6 +3941,7 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "hasown": "^2.0.0" @@ -3769,6 +3952,7 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-callable": "^1.1.4", @@ -3783,10 +3967,11 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3794,13 +3979,15 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=10" @@ -3810,17 +3997,19 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -3889,6 +4078,7 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7", @@ -3901,16 +4091,18 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7" @@ -3929,41 +4121,45 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "node_modules/eslint-plugin-import-newlines": { @@ -3971,6 +4167,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.4.0.tgz", "integrity": "sha512-+Cz1x2xBLtI9gJbmuYEpvY7F8K75wskBmJ7rk4VRObIJo+jklUJaejFJgtnWeL0dCFWabGEkhausrikXaNbtoQ==", "dev": true, + "license": "MIT", "peer": true, "bin": { "import-linter": "lib/index.js" @@ -3987,6 +4184,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -3998,6 +4196,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -4008,6 +4207,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -4021,6 +4221,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -4029,21 +4230,12 @@ "node": "*" } }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.7.0.tgz", - "integrity": "sha512-5oiVf7Y+ZxGYQTlLq81X72n+S+hjvS/u0upAdbpPEeaIZILK3MKN8lm/6QqKioBjm/qZ0B5XpMQUtc2fUkqXAg==", + "version": "48.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.11.0.tgz", + "integrity": "sha512-d12JHJDPNo7IFwTOAItCeJY1hcqoIxE0lHA8infQByLilQ9xkqrRa6laWCnsuCrf+8rUnvxXY1XuTbibRBNylA==", "dev": true, + "license": "BSD-3-Clause", "peer": true, "dependencies": { "@es-joy/jsdoccomment": "~0.46.0", @@ -4051,11 +4243,12 @@ "comment-parser": "1.4.1", "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", + "espree": "^10.1.0", "esquery": "^1.6.0", "parse-imports": "^2.1.1", - "semver": "^7.6.2", + "semver": "^7.6.3", "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.0" + "synckit": "^0.9.1" }, "engines": { "node": ">=18" @@ -4064,11 +4257,59 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", + "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", + "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-plugin-no-autofix": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/eslint-plugin-no-autofix/-/eslint-plugin-no-autofix-1.2.3.tgz", "integrity": "sha512-JFSYe82Da2A8Krh+Gfq7+3X2pchTScKgmrlMKIA4HmV6t5xGBF/kgjiFL3YTWRQXQ0NB9eOqpcxh6SuLtQUFjQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "eslint-rule-composer": "^0.3.0", @@ -4082,16 +4323,16 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", - "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", + "version": "7.37.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", + "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", @@ -4112,7 +4353,7 @@ "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { @@ -4120,104 +4361,205 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "license": "MIT", "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "esutils": "^2.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "node": ">=10" }, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-simple-import-sort": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", - "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", - "dev": true, - "peer": true, - "peerDependencies": { - "eslint": ">=5.0.0" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "peer": true, - "engines": { - "node": ">=4.0.0" - } + "license": "MIT", + "peer": true }, - "node_modules/eslint-scope": { + "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "esrecurse": "^4.3.0", @@ -4230,11 +4572,12 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-visitor-keys": { + "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4243,15 +4586,32 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" } }, "node_modules/eslint/node_modules/minimatch": { @@ -4259,6 +4619,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -4267,11 +4628,40 @@ "node": "*" } }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "acorn": "^8.9.0", @@ -4285,11 +4675,26 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "peer": true, "dependencies": { "estraverse": "^5.1.0" @@ -4303,6 +4708,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4315,6 +4721,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -4324,6 +4731,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "engines": { "node": ">=0.10.0" @@ -4333,6 +4741,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4341,6 +4750,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } @@ -4350,6 +4760,7 @@ "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-2.0.3.tgz", "integrity": "sha512-f/qE2gImHRa4Cp2y1stEOSgw8wTFyUdVJX7G//bMwbaV9JqISFxg99NbmVQeP7YLnDUZ2un851jlaDrlpmGehQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -4358,33 +4769,39 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", - "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", + "license": "MIT" }, "node_modules/fast-copy": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", - "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==" + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "license": "MIT" }, "node_modules/fast-decode-uri-component": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", - "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4402,6 +4819,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "is-glob": "^4.0.1" @@ -4415,12 +4833,14 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/fast-json-stringify": { "version": "5.16.1", "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz", "integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==", + "license": "MIT", "dependencies": { "@fastify/merge-json-schemas": "^0.1.0", "ajv": "^8.10.0", @@ -4435,6 +4855,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -4450,6 +4871,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -4463,26 +4885,30 @@ } }, "node_modules/fast-json-stringify/node_modules/ajv/node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "license": "BSD-3-Clause" }, "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/fast-querystring": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", "dependencies": { "fast-decode-uri-component": "^1.0.1" } @@ -4491,6 +4917,7 @@ "version": "3.5.0", "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4498,12 +4925,14 @@ "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" }, "node_modules/fast-uri": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz", - "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==" + "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==", + "license": "MIT" }, "node_modules/fastify": { "version": "4.28.1", @@ -4519,6 +4948,7 @@ "url": "https://opencollective.com/fastify" } ], + "license": "MIT", "dependencies": { "@fastify/ajv-compiler": "^3.5.0", "@fastify/error": "^3.4.0", @@ -4541,12 +4971,26 @@ "node_modules/fastify-plugin": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", - "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==" + "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==", + "license": "MIT" + }, + "node_modules/fastify/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -4556,6 +5000,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "flat-cache": "^3.0.4" @@ -4569,6 +5014,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4577,9 +5023,10 @@ } }, "node_modules/find-my-way": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.0.tgz", - "integrity": "sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz", + "integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", @@ -4594,6 +5041,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4610,6 +5058,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "flatted": "^3.2.9", @@ -4625,6 +5074,7 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/for-each": { @@ -4632,15 +5082,17 @@ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4656,6 +5108,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4678,13 +5131,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -4696,7 +5151,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -4704,6 +5160,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4717,6 +5174,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4726,13 +5184,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-4.0.0.tgz", "integrity": "sha512-f34iQBedYF3XcI93uewZZOnyscDragxgTK/eTvVB74k3fCD0ZorOi5BV9GS4M8rz/JoNi0Kl3qX5Y9MH3S/CLQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/function.prototype.name": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -4752,6 +5212,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4761,6 +5222,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", "dependencies": { "is-property": "^1.0.2" } @@ -4770,6 +5232,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=6.9.0" @@ -4780,6 +5243,7 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -4789,6 +5253,7 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-errors": "^1.3.0", @@ -4809,6 +5274,7 @@ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.5", @@ -4826,6 +5292,7 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -4846,6 +5313,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "is-glob": "^4.0.3" @@ -4858,6 +5326,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4869,19 +5338,14 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, "node_modules/globalthis": { @@ -4889,6 +5353,7 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-properties": "^1.2.1", @@ -4906,6 +5371,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-union": "^2.1.0", @@ -4927,6 +5393,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "get-intrinsic": "^1.1.3" @@ -4939,13 +5406,15 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/has-bigints": { @@ -4953,18 +5422,20 @@ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { @@ -4972,6 +5443,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-define-property": "^1.0.0" @@ -4985,6 +5457,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -4998,6 +5471,7 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -5011,6 +5485,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-symbols": "^1.0.3" @@ -5027,6 +5502,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "function-bind": "^1.1.2" @@ -5038,13 +5514,15 @@ "node_modules/help-me": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==" + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" }, "node_modules/hosted-git-info": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, + "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -5056,24 +5534,28 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -5090,6 +5572,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -5101,13 +5584,15 @@ "node_modules/http-status-codes": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", - "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==" + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", + "license": "MIT" }, "node_modules/https-proxy-agent": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -5120,6 +5605,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5144,13 +5630,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 4" @@ -5160,13 +5648,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ignore-walk": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", "dev": true, + "license": "ISC", "dependencies": { "minimatch": "^9.0.0" }, @@ -5179,6 +5669,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "parent-module": "^1.0.0", @@ -5196,6 +5687,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -5205,6 +5697,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5218,6 +5711,7 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5226,13 +5720,15 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ini": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -5242,6 +5738,7 @@ "resolved": "https://registry.npmjs.org/ink/-/ink-4.4.1.tgz", "integrity": "sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==", "dev": true, + "license": "MIT", "dependencies": { "@alcalzone/ansi-tokenize": "^0.1.3", "ansi-escapes": "^6.0.0", @@ -5291,6 +5788,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -5302,25 +5800,15 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/ink/node_modules/type-fest": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", - "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "ISC" }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-errors": "^1.3.0", @@ -5336,6 +5824,7 @@ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", "devOptional": true, + "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -5348,6 +5837,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -5356,13 +5846,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-actual-promise/-/is-actual-promise-1.0.2.tgz", "integrity": "sha512-xsFiO1of0CLsQnPZ1iXHNTyR9YszOeWKYv+q6n8oSFW3ipooFJ1j1lbRMgiMCr+pp2gLruESI4zb5Ak6eK5OnQ==", - "dev": true + "dev": true, + "license": "BlueOak-1.0.0" }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -5380,6 +5872,7 @@ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5396,6 +5889,7 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-bigints": "^1.0.1" @@ -5409,6 +5903,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5421,6 +5916,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -5438,6 +5934,7 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -5451,6 +5948,7 @@ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, + "license": "MIT", "dependencies": { "ci-info": "^3.2.0" }, @@ -5459,10 +5957,11 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "hasown": "^2.0.2" @@ -5479,6 +5978,7 @@ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-typed-array": "^1.1.13" @@ -5495,6 +5995,7 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5511,6 +6012,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5520,6 +6022,7 @@ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2" @@ -5532,6 +6035,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -5541,6 +6045,7 @@ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5557,6 +6062,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5568,13 +6074,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -5584,6 +6092,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -5597,6 +6106,7 @@ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -5610,6 +6120,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5619,6 +6130,7 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5635,6 +6147,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -5645,6 +6158,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5652,13 +6166,15 @@ "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -5676,6 +6192,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -5689,6 +6206,7 @@ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7" @@ -5705,6 +6223,7 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5721,6 +6240,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "has-symbols": "^1.0.2" @@ -5737,6 +6257,7 @@ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "which-typed-array": "^1.1.14" @@ -5753,6 +6274,7 @@ "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -5762,6 +6284,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -5775,6 +6298,7 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2" @@ -5788,6 +6312,7 @@ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -5805,18 +6330,21 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -5826,6 +6354,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -5835,11 +6364,35 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-reports": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -5849,10 +6402,11 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-properties": "^1.2.1", @@ -5860,12 +6414,16 @@ "has-symbols": "^1.0.3", "reflect.getprototypeof": "^1.0.4", "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -5880,6 +6438,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", "engines": { "node": ">=10" } @@ -5888,13 +6447,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "argparse": "^2.0.1" @@ -5907,29 +6468,32 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=12.0.0" } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "peer": true, "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { @@ -5937,6 +6501,7 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/json-parse-even-better-errors": { @@ -5944,6 +6509,7 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -5952,6 +6518,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" } @@ -5961,6 +6528,7 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/json-stable-stringify-without-jsonify": { @@ -5968,19 +6536,21 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "peer": true, - "dependencies": { - "minimist": "^1.2.0" - }, "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsonparse": { @@ -5990,13 +6560,15 @@ "dev": true, "engines": [ "node >= 0.2.0" - ] + ], + "license": "MIT" }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.6", @@ -6013,6 +6585,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "json-buffer": "3.0.1" @@ -6023,6 +6596,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "prelude-ls": "^1.2.1", @@ -6033,11 +6607,12 @@ } }, "node_modules/light-my-request": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.13.0.tgz", - "integrity": "sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz", + "integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==", + "license": "BSD-3-Clause", "dependencies": { - "cookie": "^0.6.0", + "cookie": "^0.7.0", "process-warning": "^3.0.0", "set-cookie-parser": "^2.4.1" } @@ -6047,6 +6622,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -6061,25 +6637,29 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "license": "Apache-2.0" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -6088,11 +6668,29 @@ } }, "node_modules/lru-cache": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", - "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lru.min": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz", + "integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==", + "license": "MIT", "engines": { - "node": ">=16.14" + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" } }, "node_modules/make-dir": { @@ -6100,6 +6698,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -6110,17 +6709,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -6142,23 +6756,26 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "braces": "^3.0.3", @@ -6173,6 +6790,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8.6" @@ -6185,6 +6803,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -6197,6 +6816,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6206,6 +6826,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6220,6 +6841,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6228,6 +6850,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -6237,6 +6860,7 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -6249,6 +6873,7 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -6266,6 +6891,7 @@ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6278,6 +6904,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6285,11 +6912,19 @@ "node": ">=8" } }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.2.tgz", + "integrity": "sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==", "dev": true, + "license": "MIT", "dependencies": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -6300,6 +6935,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6307,11 +6943,19 @@ "node": ">=8" } }, + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6324,6 +6968,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6331,11 +6976,19 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6348,6 +7001,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6355,11 +7009,19 @@ "node": ">=8" } }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -6373,6 +7035,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6380,11 +7043,19 @@ "node": ">=8" } }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/mkdirp": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "dist/cjs/src/bin.js" }, @@ -6396,9 +7067,10 @@ } }, "node_modules/mongodb": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", - "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", + "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", + "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.1.5", "bson": "^6.7.0", @@ -6444,28 +7116,31 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^13.0.0" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/mysql2": { - "version": "3.10.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.3.tgz", - "integrity": "sha512-k43gmH9i79rZD4hGPdj7pDuT0UBiFjs4UzXEy1cJrV0QqcSABomoLwvejqdbcXN+Vd7gi999CVM6o9vCPKq29g==", + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.3.tgz", + "integrity": "sha512-Qpu2ADfbKzyLdwC/5d4W7+5Yz7yBzCU05YWt5npWzACST37wJsB23wgOSo00qi043urkiRwXtEvJc9UnuLX/MQ==", + "license": "MIT", "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", "long": "^5.2.1", - "lru-cache": "^8.0.0", + "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" @@ -6478,6 +7153,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "license": "MIT", "dependencies": { "lru-cache": "^7.14.1" }, @@ -6489,6 +7165,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -6498,13 +7175,15 @@ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6514,6 +7193,7 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", "dev": true, + "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", @@ -6538,15 +7218,30 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=16" } }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-gyp/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -6558,17 +7253,19 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/nodemon": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", - "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", + "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", @@ -6597,25 +7294,18 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/nodemon/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6623,16 +7313,17 @@ "node": "*" } }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/nodemon/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=4" + "node": ">=10" } }, "node_modules/nopt": { @@ -6640,6 +7331,7 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "^2.0.0" }, @@ -6655,6 +7347,7 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", @@ -6664,11 +7357,25 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6678,6 +7385,7 @@ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", "dev": true, + "license": "ISC", "dependencies": { "npm-normalize-package-bin": "^3.0.0" }, @@ -6690,6 +7398,7 @@ "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "semver": "^7.1.1" }, @@ -6697,20 +7406,35 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/npm-install-checks/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/npm-normalize-package-bin": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", "dev": true, + "license": "ISC", "dependencies": { "hosted-git-info": "^7.0.0", "proc-log": "^4.0.0", @@ -6721,11 +7445,25 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/npm-packlist": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, + "license": "ISC", "dependencies": { "ignore-walk": "^6.0.4" }, @@ -6738,6 +7476,7 @@ "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, + "license": "ISC", "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", @@ -6748,11 +7487,25 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/npm-pick-manifest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/npm-registry-fetch": { "version": "16.2.1", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/redact": "^1.1.0", "make-fetch-happen": "^13.0.0", @@ -6772,6 +7525,7 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=0.10.0" @@ -6782,6 +7536,7 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -6795,6 +7550,7 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -6805,6 +7561,7 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.5", @@ -6824,6 +7581,7 @@ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -6839,6 +7597,7 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -6858,6 +7617,7 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -6873,6 +7633,7 @@ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -6890,6 +7651,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -6898,6 +7660,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -6907,6 +7670,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6922,6 +7686,7 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, + "license": "(WTFPL OR MIT)", "bin": { "opener": "bin/opener-bin.js" } @@ -6931,6 +7696,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "deep-is": "^0.1.3", @@ -6949,6 +7715,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -6964,6 +7731,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -6979,6 +7747,7 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -6990,15 +7759,17 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" }, "node_modules/pacote": { "version": "17.0.7", "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.7.tgz", "integrity": "sha512-sgvnoUMlkv9xHwDUKjKQFXVyUi8dtJGKp3vg6sYy+TxbDic5RjZCHF3ygv0EJgNRZ2GfRONjlKPUfokJ9lDpwQ==", "dev": true, + "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", @@ -7031,6 +7802,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "callsites": "^3.0.0" @@ -7040,10 +7812,11 @@ } }, "node_modules/parse-imports": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", - "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", + "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", "dev": true, + "license": "Apache-2.0 AND MIT", "peer": true, "dependencies": { "es-module-lexer": "^1.5.3", @@ -7058,6 +7831,7 @@ "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } @@ -7067,6 +7841,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7076,6 +7851,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7084,6 +7860,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7093,12 +7870,14 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -7113,23 +7892,26 @@ "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/picomatch": { @@ -7137,6 +7919,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=12" @@ -7146,16 +7929,17 @@ } }, "node_modules/pino": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.3.1.tgz", - "integrity": "sha512-afSfrq/hUiW/MFmQcLEwV9Zh8Ry6MrMTOyBU53o/fc0gEl+1OZ/Fks/xQCM2nOC0C/OfDtQMnT2d8c3kpcfSzA==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.5.0.tgz", + "integrity": "sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==", + "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^1.2.0", + "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", - "process-warning": "^3.0.0", + "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", @@ -7167,18 +7951,19 @@ } }, "node_modules/pino-abstract-transport": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", - "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", "dependencies": { - "readable-stream": "^4.0.0", "split2": "^4.0.0" } }, "node_modules/pino-pretty": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.2.1.tgz", - "integrity": "sha512-O05NuD9tkRasFRWVaF/uHLOvoRDFD7tb5VMertr78rbsYFjYp48Vg3477EshVAF5eZaEw+OpDl/tu+B0R5o+7g==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.3.0.tgz", + "integrity": "sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==", + "license": "MIT", "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", @@ -7188,7 +7973,7 @@ "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^1.0.0", + "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "readable-stream": "^4.0.0", "secure-json-parse": "^2.4.0", @@ -7202,13 +7987,21 @@ "node_modules/pino-std-serializers": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", - "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==" + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, + "node_modules/pino/node_modules/process-warning": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.0.tgz", + "integrity": "sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==", + "license": "MIT" }, "node_modules/pirates": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -7218,6 +8011,7 @@ "resolved": "https://registry.npmjs.org/polite-json/-/polite-json-4.0.1.tgz", "integrity": "sha512-8LI5ZeCPBEb4uBbcYKNVwk4jgqNx1yHReWoW4H4uUihWlSqZsUDfSITrRhjliuPgxsNPFhNSudGO2Zu4cbWinQ==", "dev": true, + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, @@ -7230,6 +8024,7 @@ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -7240,6 +8035,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.8.0" @@ -7250,6 +8046,7 @@ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -7259,6 +8056,7 @@ "resolved": "https://registry.npmjs.org/prismjs-terminal/-/prismjs-terminal-1.2.3.tgz", "integrity": "sha512-xc0zuJ5FMqvW+DpiRkvxURlz98DdfDsZcFHdO699+oL+ykbFfgI7O4VDEgUyc07BSL2NHl3zdb8m/tZ/aaqUrw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "chalk": "^5.2.0", "prismjs": "^1.29.0", @@ -7276,6 +8074,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -7288,6 +8087,7 @@ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7296,6 +8096,7 @@ "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -7305,6 +8106,7 @@ "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", "dev": true, + "license": "MIT", "dependencies": { "fromentries": "^1.2.0" }, @@ -7315,19 +8117,22 @@ "node_modules/process-warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", - "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, + "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -7341,6 +8146,7 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.4.0", @@ -7352,6 +8158,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -7364,12 +8171,14 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -7379,6 +8188,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -7402,18 +8212,21 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "peer": true }, "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -7426,6 +8239,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0", @@ -7440,6 +8254,7 @@ "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", "dev": true, + "license": "MIT", "dependencies": { "@base2/pretty-print-object": "1.0.1", "is-plain-object": "5.0.0", @@ -7454,13 +8269,15 @@ "version": "18.1.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/react-reconciler": { @@ -7468,6 +8285,7 @@ "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.2.tgz", "integrity": "sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -7485,6 +8303,7 @@ "integrity": "sha512-8PcDiZ8DXUjLf687Ol4BR8Bpm2umR7vhoZOzNRt+uxD9GpBh/K+CAAALVIiYFknmvlmyg7hM7BSNUXPaCCqd0Q==", "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.2.2", "json-parse-even-better-errors": "^3.0.0", @@ -7500,6 +8319,7 @@ "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dev": true, + "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -7512,6 +8332,7 @@ "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -7528,6 +8349,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -7540,6 +8362,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7551,6 +8374,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", "engines": { "node": ">= 12.13.0" } @@ -7560,6 +8384,7 @@ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -7578,16 +8403,17 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -7601,6 +8427,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7609,6 +8436,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7618,6 +8446,7 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-core-module": "^2.13.0", @@ -7636,6 +8465,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=4" @@ -7646,6 +8476,7 @@ "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.6.tgz", "integrity": "sha512-CIw9e64QcKcCFUj9+KxUCJPy8hYofv6eVfo3U9wdhCm2E4IjvFnZ6G4/yIC4yP3f11+h6uU5b3LdS7O64LgqrA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "glob": "^10.3.3", "walk-up-path": "^3.0.1" @@ -7662,6 +8493,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -7677,12 +8509,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ret": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "license": "MIT", "engines": { "node": ">=10" } @@ -7692,6 +8526,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -7700,6 +8535,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -7708,7 +8544,8 @@ "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", @@ -7716,6 +8553,7 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "glob": "^7.1.3" @@ -7732,6 +8570,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "balanced-match": "^1.0.0", @@ -7744,6 +8583,7 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -7765,6 +8605,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -7792,6 +8633,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "peer": true, "dependencies": { "queue-microtask": "^1.2.2" @@ -7802,6 +8644,7 @@ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -7833,13 +8676,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.6", @@ -7857,14 +8702,16 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "license": "MIT", "dependencies": { "ret": "~0.4.0" } }, "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", "engines": { "node": ">=10" } @@ -7872,13 +8719,15 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -7886,17 +8735,17 @@ "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/seq-queue": { @@ -7905,15 +8754,17 @@ "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz", + "integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==", + "license": "MIT" }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-data-property": "^1.1.4", @@ -7932,6 +8783,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-data-property": "^1.1.4", @@ -7946,12 +8798,14 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -7963,6 +8817,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7972,6 +8827,7 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -7990,6 +8846,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { "node": ">=14" }, @@ -8002,6 +8859,7 @@ "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", @@ -8019,6 +8877,7 @@ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -8026,11 +8885,25 @@ "node": ">=10" } }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=8" @@ -8041,6 +8914,7 @@ "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", "dev": true, + "license": "ISC", "peer": true }, "node_modules/slice-ansi": { @@ -8048,6 +8922,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-6.0.0.tgz", "integrity": "sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^4.0.0" @@ -8064,6 +8939,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8076,6 +8952,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8088,6 +8965,7 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "devOptional": true, + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -8098,6 +8976,7 @@ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "devOptional": true, + "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -8112,6 +8991,7 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -8122,9 +9002,10 @@ } }, "node_modules/sonic-boom": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", - "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0" } @@ -8133,6 +9014,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" } @@ -8142,6 +9024,7 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -8152,6 +9035,7 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -8161,13 +9045,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -8175,15 +9061,17 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", - "dev": true + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", "engines": { "node": ">= 10.x" } @@ -8192,12 +9080,14 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "devOptional": true + "devOptional": true, + "license": "BSD-3-Clause" }, "node_modules/sqlstring": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8207,6 +9097,7 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -8219,6 +9110,7 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -8231,6 +9123,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8239,6 +9132,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8247,6 +9141,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -8256,6 +9151,7 @@ "resolved": "https://registry.npmjs.org/string-length/-/string-length-6.0.0.tgz", "integrity": "sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==", "dev": true, + "license": "MIT", "dependencies": { "strip-ansi": "^7.1.0" }, @@ -8267,10 +9163,11 @@ } }, "node_modules/string-length/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8283,6 +9180,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -8297,6 +9195,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -8314,6 +9213,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8326,12 +9226,14 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -8343,6 +9245,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -8358,6 +9261,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8385,6 +9289,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "define-properties": "^1.1.3", @@ -8396,6 +9301,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8415,6 +9321,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8430,6 +9337,7 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -8447,6 +9355,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8459,6 +9368,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8471,6 +9381,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=4" @@ -8480,6 +9391,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -8488,15 +9400,16 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -8504,6 +9417,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">= 0.4" @@ -8517,6 +9431,7 @@ "resolved": "https://registry.npmjs.org/sync-content/-/sync-content-1.0.2.tgz", "integrity": "sha512-znd3rYiiSxU3WteWyS9a6FXkTA/Wjk8WQsOyzHbineeL837dLn3DA4MRhsIX3qGcxDMH6+uuFV4axztssk7wEQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "glob": "^10.2.6", "mkdirp": "^3.0.1", @@ -8534,28 +9449,27 @@ } }, "node_modules/sync-content/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -8573,6 +9487,7 @@ "resolved": "https://registry.npmjs.org/tap/-/tap-19.2.5.tgz", "integrity": "sha512-Mz7MznUuKCqrN9dr0s8REt6zLg6WLNrvGXwDSaUyPO73dpXXjakYA7YVKRWu6TBnj7NsSYKuHXpQFROlqZ2KTg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@tapjs/after": "1.1.31", "@tapjs/after-each": "2.0.8", @@ -8610,6 +9525,7 @@ "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-16.0.1.tgz", "integrity": "sha512-vKianJzSSzLkJ3bHBwzvZDDRi9yGMwkRANJxwPAjAue50owB8rlluYySmTN4tZVH0nsh6stvrQbg9kuCL5svdg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "events-to-array": "^2.0.3", "tap-yaml": "2.2.2" @@ -8626,6 +9542,7 @@ "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.2.tgz", "integrity": "sha512-MWG4OpAKtNoNVjCz/BqlDJiwTM99tiHRhHPS4iGOe1ZS0CgM4jSFH92lthSFvvy4EdDjQZDV7uYqUFlU9JuNhw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "yaml": "^2.4.1", "yaml-types": "^0.3.0" @@ -8639,6 +9556,7 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -8656,6 +9574,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -8668,6 +9587,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -8680,6 +9600,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=8" } @@ -8689,6 +9610,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8696,11 +9618,19 @@ "node": ">=10" } }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/tcompare": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-7.0.1.tgz", "integrity": "sha512-JN5s7hgmg/Ya5HxZqCnywT+XiOGRFcJRgYhtMyt/1m+h0yWpWwApO7HIM8Bpwyno9hI151ljjp5eAPCHhIGbpQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "diff": "^5.2.0", "react-element-to-jsx-string": "^15.0.0" @@ -8714,6 +9644,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -8728,6 +9659,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8739,6 +9671,7 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -8759,6 +9692,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -8771,12 +9705,14 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/thread-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", "dependencies": { "real-require": "^0.2.0" } @@ -8786,6 +9722,7 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=4" @@ -8796,6 +9733,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8807,6 +9745,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "license": "MIT", "engines": { "node": ">=12" } @@ -8815,6 +9754,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -8824,6 +9764,7 @@ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, + "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" } @@ -8832,6 +9773,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "license": "MIT", "dependencies": { "punycode": "^2.3.0" }, @@ -8844,6 +9786,7 @@ "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-2.0.0.tgz", "integrity": "sha512-iGbM7X2slv9ORDVj2y2FFUq3cP/ypbtu2nQ8S38ufjL0glBABvmR9pTdsib1XtS2LUhhLMbelaBUaf/s5J3dSw==", "dev": true, + "license": "ISC", "engines": { "node": ">= 8" } @@ -8853,6 +9796,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=16" @@ -8866,6 +9810,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@types/json5": "^0.0.29", @@ -8874,11 +9819,26 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/tshy": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.18.0.tgz", "integrity": "sha512-FQudIujBazHRu7CVPHKQE9/Xq1Wc7lezxD/FCnTXx2PTcnoSN32DVpb/ZXvzV2NJBTDB3XKjqX8Cdm+2UK1DlQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "chalk": "^5.3.0", "chokidar": "^3.6.0", @@ -8904,6 +9864,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -8916,6 +9877,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8931,6 +9893,7 @@ "resolved": "https://registry.npmjs.org/polite-json/-/polite-json-5.0.0.tgz", "integrity": "sha512-OLS/0XeUAcE8a2fdwemNja+udKgXNnY6yKVIXqAD2zVRx1KvY6Ato/rZ2vdzbxqYwPW0u6SCNC/bAMPNzpzxbw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, @@ -8939,34 +9902,34 @@ } }, "node_modules/tshy/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "dev": true, + "license": "0BSD" }, "node_modules/tuf-js": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", "dev": true, + "license": "MIT", "dependencies": { "@tufjs/models": "2.0.1", "debug": "^4.3.4", @@ -8981,6 +9944,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "prelude-ls": "^1.2.1" @@ -8990,11 +9954,11 @@ } }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", "dev": true, - "peer": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -9007,6 +9971,7 @@ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9022,6 +9987,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9042,6 +10008,7 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -9063,6 +10030,7 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.7", @@ -9080,10 +10048,11 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9097,6 +10066,7 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -9112,13 +10082,15 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/unique-filename": { @@ -9126,6 +10098,7 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, + "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -9138,6 +10111,7 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -9146,9 +10120,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -9164,10 +10138,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -9181,6 +10156,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "punycode": "^2.1.0" @@ -9191,6 +10167,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -9199,13 +10176,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -9215,21 +10194,12 @@ "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -9240,6 +10210,7 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -9250,6 +10221,7 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", "dev": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -9258,12 +10230,14 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" } @@ -9272,6 +10246,7 @@ "version": "13.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", "dependencies": { "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" @@ -9284,6 +10259,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -9299,6 +10275,7 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-bigint": "^1.0.1", @@ -9312,14 +10289,15 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -9328,8 +10306,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -9343,6 +10321,7 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "is-map": "^2.0.3", @@ -9362,6 +10341,7 @@ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -9382,6 +10362,7 @@ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", "dev": true, + "license": "MIT", "dependencies": { "string-width": "^5.0.1" }, @@ -9397,6 +10378,7 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=0.10.0" @@ -9406,6 +10388,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -9423,6 +10406,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9435,15 +10419,50 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9454,9 +10473,10 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -9468,6 +10488,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -9479,6 +10500,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -9492,13 +10514,15 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -9520,21 +10544,25 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC", + "peer": true }, "node_modules/yaml": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", - "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -9547,6 +10575,7 @@ "resolved": "https://registry.npmjs.org/yaml-types/-/yaml-types-0.3.0.tgz", "integrity": "sha512-i9RxAO/LZBiE0NJUy9pbN5jFz5EasYDImzRkj8Y81kkInTi1laia3P3K/wlMKzOxFQutZip8TejvQP/DwgbU7A==", "dev": true, + "license": "ISC", "engines": { "node": ">= 16", "npm": ">= 7" @@ -9560,6 +10589,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9578,6 +10608,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -9586,13 +10617,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9607,6 +10640,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9618,7 +10652,8 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", - "dev": true + "dev": true, + "license": "MIT" } } } diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js index 2cb7ef3e0..5cb442795 100644 --- a/components/log-viewer-webui/server/src/DbManager.js +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -2,7 +2,7 @@ import fastifyPlugin from "fastify-plugin"; import fastifyMongo from "@fastify/mongodb"; import fastifyMysql from "@fastify/mysql"; -import msgpack from "@msgpack/msgpack"; +import {encode as msgpackEncode} from "@msgpack/msgpack"; import {sleep} from "./utils.js"; @@ -113,7 +113,7 @@ class DbManager { `INSERT INTO ${this.#queryJobsTableName} (job_config, type) VALUES (?, ?)`, [ - Buffer.from(msgpack.encode(jobConfig)), + Buffer.from(msgpackEncode(jobConfig)), QUERY_JOB_TYPE.EXTRACT_IR, ] ); diff --git a/components/webui/package-lock.json b/components/webui/package-lock.json index 700574212..c7644cc78 100644 --- a/components/webui/package-lock.json +++ b/components/webui/package-lock.json @@ -13,34 +13,34 @@ } }, "@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "requires": { - "@babel/highlight": "^7.24.2", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" } }, "@babel/compat-data": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", - "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==" + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==" }, "@babel/core": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", - "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.8", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.8", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -49,202 +49,172 @@ } }, "@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "requires": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" } }, "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.7" } }, "@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "requires": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "requires": { - "@babel/types": "^7.22.5" - } - }, "@babel/helper-module-imports": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", - "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "requires": { - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" } }, "@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "requires": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" } }, "@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==" + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==" }, "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "requires": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" } }, "@babel/helper-string-parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", - "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==" + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==" }, "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==" }, "@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==" + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==" }, "@babel/helpers": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "requires": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" } }, "@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "requires": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==" + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "requires": { + "@babel/types": "^7.25.8" + } }, "@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", + "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", "requires": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.7" } }, "@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", + "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/types": "^7.25.7" } }, "@babel/runtime": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", - "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "requires": { "regenerator-runtime": "^0.14.0" } }, "@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "requires": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" } }, "@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", - "requires": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "requires": { + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "requires": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" } }, @@ -264,30 +234,30 @@ } }, "@fortawesome/fontawesome-common-types": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", - "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==" + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==" }, "@fortawesome/fontawesome-svg-core": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", - "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", "requires": { - "@fortawesome/fontawesome-common-types": "6.5.2" + "@fortawesome/fontawesome-common-types": "6.6.0" } }, "@fortawesome/free-solid-svg-icons": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", - "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", "requires": { - "@fortawesome/fontawesome-common-types": "6.5.2" + "@fortawesome/fontawesome-common-types": "6.6.0" } }, "@fortawesome/react-fontawesome": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", - "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", "requires": { "prop-types": "^15.8.1" } @@ -313,9 +283,9 @@ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "@jridgewell/trace-mapping": { "version": "0.3.25", @@ -351,9 +321,9 @@ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, "@react-aria/ssr": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.2.tgz", - "integrity": "sha512-0gKkgDYdnq1w+ey8KzG9l+H5Z821qh9vVjztk55rUg71vTk/Eaebeir+WtzcLLwTjw3m/asIjx8Y59y1lJZhBw==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.6.tgz", + "integrity": "sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA==", "requires": { "@swc/helpers": "^0.5.0" } @@ -367,9 +337,9 @@ } }, "@restart/ui": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.8.tgz", - "integrity": "sha512-6ndCv3oZ7r9vuP1Ok9KH55TM1/UkdBnP/fSraW0DFDMbPMzWKhVKeFAIEUCRCSdzayjZDcFYK6xbMlipN9dmMA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.8.0.tgz", + "integrity": "sha512-xJEOXUOTmT4FngTmhdjKFRrVVF0hwCLNPdatLCHkyS4dkiSK12cEu1Y0fjxktjJrdst9jJIc5J6ihMJCoWEN/g==", "requires": { "@babel/runtime": "^7.21.0", "@popperjs/core": "^2.11.6", @@ -390,53 +360,53 @@ } }, "@swc/helpers": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.10.tgz", - "integrity": "sha512-CU+RF9FySljn7HVSkkjiB84hWkvTaI3rtLvF433+jRSBL2hMu3zX5bGhHS8C80SM++h4xy8hBSnUHFQHmRXSBw==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", + "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", "requires": { "tslib": "^2.4.0" } }, "@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true }, "@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, "requires": { - "@types/linkify-it": "*", - "@types/mdurl": "*" + "@types/linkify-it": "^5", + "@types/mdurl": "^2" } }, "@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true }, "@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "@types/react": { - "version": "18.2.79", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", - "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", "requires": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "requires": { "@types/react": "*" } @@ -451,6 +421,14 @@ "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -466,9 +444,19 @@ "dev": true }, "async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, + "aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bluebird": { "version": "3.7.2", @@ -482,20 +470,29 @@ "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==" }, "browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "requires": { + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "caniuse-lite": { - "version": "1.0.30001612", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", - "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==" + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==" }, "catharsis": { "version": "0.9.0", @@ -517,9 +514,9 @@ } }, "chart.js": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", - "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.5.tgz", + "integrity": "sha512-CVVjg1RYTJV9OCC8WeJPMx8gsV8K6WIyIEQUE3ui4AR9Hfgls9URri6Ja3hyMVBbTF8Q2KFa19PE815gWcWhng==", "requires": { "@kurkle/color": "^0.3.0" } @@ -601,16 +598,16 @@ } }, "dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "denque": { @@ -633,9 +630,9 @@ } }, "electron-to-chromium": { - "version": "1.4.747", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz", - "integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==" + "version": "1.5.41", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", + "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==" }, "enabled": { "version": "2.0.0", @@ -643,21 +640,31 @@ "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true }, "escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, "fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", @@ -739,6 +746,11 @@ "safer-buffer": ">= 2.1.2 < 3.0.0" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -787,21 +799,21 @@ } }, "jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", + "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", "dev": true, "requires": { "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", + "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", @@ -818,9 +830,9 @@ } }, "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==" }, "json5": { "version": "2.2.3", @@ -842,12 +854,12 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, "requires": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "lodash": { @@ -857,9 +869,9 @@ "dev": true }, "logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", "requires": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -890,17 +902,23 @@ "yallist": "^3.0.2" } }, + "lru.min": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz", + "integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==" + }, "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "requires": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" } }, "markdown-it-anchor": { @@ -916,15 +934,15 @@ "dev": true }, "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true }, "meteor-node-stubs": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.9.tgz", - "integrity": "sha512-EKRezc1/PblYtYiK4BOT3h5geWDo9AFBBSYNamPNh8AC5msUbVCcg8kekzAa7r7JPzBX8nZWaXEQVar4t8q/Hg==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.10.tgz", + "integrity": "sha512-zP1AVg8sOATz15yfy11R2VTx+IZFfAOXi8GuZa8tOfeVT1tKaqDooAbFylnIXwpStSu6HRBUhQqHtR06Qr9aEA==", "requires": { "@meteorjs/crypto-browserify": "^3.12.1", "assert": "^2.1.0", @@ -933,7 +951,7 @@ "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "domain-browser": "^4.23.0", - "elliptic": "^6.5.4", + "elliptic": "^6.5.7", "events": "^3.3.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", @@ -947,7 +965,7 @@ "string_decoder": "^1.3.0", "timers-browserify": "^2.0.12", "tty-browserify": "0.0.1", - "url": "^0.11.3", + "url": "^0.11.4", "util": "^0.12.5", "vm-browserify": "^1.1.2" }, @@ -1147,12 +1165,14 @@ "bundled": true }, "call-bind": { - "version": "1.0.5", + "version": "1.0.7", "bundled": true, "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, "cipher-base": { @@ -1213,12 +1233,12 @@ } }, "define-data-property": { - "version": "1.1.1", + "version": "1.1.4", "bundled": true, "requires": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" } }, "define-properties": { @@ -1258,7 +1278,7 @@ "bundled": true }, "elliptic": { - "version": "6.5.5", + "version": "6.5.7", "bundled": true, "requires": { "bn.js": "^4.11.9", @@ -1276,6 +1296,17 @@ } } }, + "es-define-property": { + "version": "1.0.0", + "bundled": true, + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "bundled": true + }, "events": { "version": "3.3.0", "bundled": true @@ -1300,9 +1331,10 @@ "bundled": true }, "get-intrinsic": { - "version": "1.2.2", + "version": "1.2.4", "bundled": true, "requires": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", @@ -1317,10 +1349,10 @@ } }, "has-property-descriptors": { - "version": "1.0.1", + "version": "1.0.2", "bundled": true, "requires": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" } }, "has-proto": { @@ -1453,7 +1485,7 @@ "bundled": true }, "object-inspect": { - "version": "1.13.1", + "version": "1.13.2", "bundled": true }, "object-is": { @@ -1554,10 +1586,10 @@ "bundled": true }, "qs": { - "version": "6.11.2", + "version": "6.13.0", "bundled": true, "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "querystring-es3": { @@ -1601,13 +1633,15 @@ "bundled": true }, "set-function-length": { - "version": "1.1.1", + "version": "1.2.2", "bundled": true, "requires": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" } }, "setimmediate": { @@ -1623,12 +1657,13 @@ } }, "side-channel": { - "version": "1.0.4", + "version": "1.0.6", "bundled": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, "stream-browserify": { @@ -1668,11 +1703,11 @@ "bundled": true }, "url": { - "version": "0.11.3", + "version": "0.11.4", "bundled": true, "requires": { "punycode": "^1.4.1", - "qs": "^6.11.2" + "qs": "^6.12.3" } }, "util": { @@ -1723,30 +1758,24 @@ "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "mysql2": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.0.tgz", - "integrity": "sha512-qx0mfWYt1DpTPkw8mAcHW/OwqqyNqBLBHvY5IjN8+icIYTjt6znrgYJ+gxqNNRpVknb5Wc/gcCM4XjbCR0j5tw==", + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.3.tgz", + "integrity": "sha512-Qpu2ADfbKzyLdwC/5d4W7+5Yz7yBzCU05YWt5npWzACST37wJsB23wgOSo00qi043urkiRwXtEvJc9UnuLX/MQ==", "requires": { + "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", "long": "^5.2.1", - "lru-cache": "^8.0.0", + "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" - }, - "dependencies": { - "lru-cache": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", - "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==" - } } }, "named-placeholders": { @@ -1765,9 +1794,9 @@ } }, "node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "object-assign": { "version": "4.1.1", @@ -1788,17 +1817,22 @@ } }, "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", "requires": { "isarray": "0.0.1" } }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" }, "prop-types": { "version": "15.8.1", @@ -1819,22 +1853,28 @@ "warning": "^4.0.0" } }, + "punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true + }, "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "requires": { "loose-envify": "^1.1.0" } }, "react-bootstrap": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.2.tgz", - "integrity": "sha512-UvB7mRqQjivdZNxJNEA2yOQRB7L9N43nBnKc33K47+cH90/ujmnMwatTCwQLu83gLhrzAl8fsa6Lqig/KLghaA==", + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz", + "integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==", "requires": { - "@babel/runtime": "^7.22.5", + "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.8", + "@restart/ui": "^1.6.9", "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", @@ -1865,12 +1905,12 @@ } }, "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "requires": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" } }, "react-fast-compare": { @@ -1889,9 +1929,9 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "react-onclickoutside": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", - "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==" + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz", + "integrity": "sha512-LdrrxK/Yh9zbBQdFbMTXPp3dTSN9B+9YJQucdDu3JNKRrbdU+H+/TVONJoWtOwy4II8Sqf1y/DTI6w/vGPYW0w==" }, "react-popper": { "version": "2.3.0", @@ -1978,9 +2018,9 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" }, "safer-buffer": { "version": "2.1.2", @@ -1988,9 +2028,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "requires": { "loose-envify": "^1.1.0" } @@ -2071,14 +2111,14 @@ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" }, "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" }, "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "dev": true }, "uncontrollable": { @@ -2093,18 +2133,18 @@ } }, "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", "dev": true }, "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" } }, "util-deprecate": { @@ -2131,15 +2171,15 @@ } }, "winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", + "integrity": "sha512-RhruH2Cj0bV0WgNL+lOfoUBI4DVfdUNjVnJGVovWZmrcKtrFTTRzgXYK2O9cymSGjrERCtaAeHwMNnUWXlwZow==", "requires": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.4.0", + "logform": "^2.6.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", @@ -2160,13 +2200,27 @@ } }, "winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.8.0.tgz", + "integrity": "sha512-qxSTKswC6llEMZKgCQdaWgDuMJQnhuvF5f2Nk3SNXc4byfQ+voo2mX1Px9dkNOuR8p0KAjfPG29PuYUSIb+vSA==", "requires": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "logform": "^2.6.1", + "readable-stream": "^4.5.2", "triple-beam": "^1.3.0" + }, + "dependencies": { + "readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + } } }, "xmlcreate": { diff --git a/components/webui/package.json b/components/webui/package.json index 5b34be3f9..8ba99fc11 100644 --- a/components/webui/package.json +++ b/components/webui/package.json @@ -25,7 +25,7 @@ "chartjs-plugin-zoom": "^2.0.1", "dayjs": "^1.11.10", "json5": "^2.2.3", - "meteor-node-stubs": "^1.2.9", + "meteor-node-stubs": "^1.2.10", "mysql2": "^3.10.0", "react": "^18.2.0", "react-bootstrap": "^2.10.2", diff --git a/requirements.txt b/requirements.txt index d48e14ebb..fdd8fafea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ pip~=23.3 poetry~=1.7 -setuptools~=69.0 +setuptools~=75.2.0 From 4daf8d8818ba9604d56df823e2a5310a34201255 Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Thu, 24 Oct 2024 22:52:02 -0400 Subject: [PATCH 085/114] clp-s: Implement table packing (#466) Co-authored-by: wraymo <37269683+wraymo@users.noreply.github.com> Co-authored-by: Kirk Rodrigues <2454684+kirkrodrigues@users.noreply.github.com> Co-authored-by: wraymo --- components/core/src/clp_s/ArchiveReader.cpp | 124 ++++++++++++------ components/core/src/clp_s/ArchiveReader.hpp | 28 +++- components/core/src/clp_s/ArchiveWriter.cpp | 112 ++++++++++++++-- components/core/src/clp_s/ArchiveWriter.hpp | 29 ++++ components/core/src/clp_s/CMakeLists.txt | 2 + components/core/src/clp_s/ColumnWriter.cpp | 44 +++---- components/core/src/clp_s/ColumnWriter.hpp | 42 +++--- .../core/src/clp_s/CommandLineArguments.cpp | 5 + .../core/src/clp_s/CommandLineArguments.hpp | 3 + components/core/src/clp_s/JsonParser.cpp | 1 + components/core/src/clp_s/JsonParser.hpp | 1 + .../core/src/clp_s/PackedStreamReader.cpp | 117 +++++++++++++++++ .../core/src/clp_s/PackedStreamReader.hpp | 97 ++++++++++++++ components/core/src/clp_s/SchemaReader.cpp | 18 +-- components/core/src/clp_s/SchemaReader.hpp | 18 +-- components/core/src/clp_s/SchemaWriter.cpp | 21 ++- components/core/src/clp_s/SchemaWriter.hpp | 13 +- components/core/src/clp_s/clp-s.cpp | 1 + components/core/src/clp_s/search/Output.cpp | 2 +- 19 files changed, 544 insertions(+), 134 deletions(-) create mode 100644 components/core/src/clp_s/PackedStreamReader.cpp create mode 100644 components/core/src/clp_s/PackedStreamReader.hpp diff --git a/components/core/src/clp_s/ArchiveReader.cpp b/components/core/src/clp_s/ArchiveReader.cpp index 1bdc0baae..5362d32cc 100644 --- a/components/core/src/clp_s/ArchiveReader.cpp +++ b/components/core/src/clp_s/ArchiveReader.cpp @@ -27,8 +27,8 @@ void ArchiveReader::open(string_view archives_dir, string_view archive_id) { m_schema_tree = ReaderUtils::read_schema_tree(archive_path_str); m_schema_map = ReaderUtils::read_schemas(archive_path_str); - m_tables_file_reader.open(archive_path_str + constants::cArchiveTablesFile); m_table_metadata_file_reader.open(archive_path_str + constants::cArchiveTableMetadataFile); + m_stream_reader.open_packed_streams(archive_path_str + constants::cArchiveTablesFile); } void ArchiveReader::read_metadata() { @@ -38,6 +38,20 @@ void ArchiveReader::read_metadata() { cDecompressorFileReadBufferCapacity ); + m_stream_reader.read_metadata(m_table_metadata_decompressor); + + size_t num_separate_column_schemas; + if (auto error + = m_table_metadata_decompressor.try_read_numeric_value(num_separate_column_schemas); + ErrorCodeSuccess != error) + { + throw OperationFailed(error, __FILENAME__, __LINE__); + } + + if (0 != num_separate_column_schemas) { + throw OperationFailed(ErrorCode::ErrorCodeUnsupported, __FILENAME__, __LINE__); + } + size_t num_schemas; if (auto error = m_table_metadata_decompressor.try_read_numeric_value(num_schemas); ErrorCodeSuccess != error) @@ -45,39 +59,65 @@ void ArchiveReader::read_metadata() { throw OperationFailed(error, __FILENAME__, __LINE__); } - for (size_t i = 0; i < num_schemas; i++) { + bool prev_metadata_initialized{false}; + SchemaReader::SchemaMetadata prev_metadata{}; + int32_t prev_schema_id{}; + for (size_t i = 0; i < num_schemas; ++i) { + uint64_t stream_id; + uint64_t stream_offset; int32_t schema_id; uint64_t num_messages; - size_t table_offset; - size_t uncompressed_size; - if (auto error = m_table_metadata_decompressor.try_read_numeric_value(schema_id); + if (auto error = m_table_metadata_decompressor.try_read_numeric_value(stream_id); ErrorCodeSuccess != error) { throw OperationFailed(error, __FILENAME__, __LINE__); } - if (auto error = m_table_metadata_decompressor.try_read_numeric_value(num_messages); + if (auto error = m_table_metadata_decompressor.try_read_numeric_value(stream_offset); ErrorCodeSuccess != error) { throw OperationFailed(error, __FILENAME__, __LINE__); } - if (auto error = m_table_metadata_decompressor.try_read_numeric_value(table_offset); + if (stream_offset > m_stream_reader.get_uncompressed_stream_size(stream_id)) { + throw OperationFailed(ErrorCodeCorrupt, __FILENAME__, __LINE__); + } + + if (auto error = m_table_metadata_decompressor.try_read_numeric_value(schema_id); ErrorCodeSuccess != error) { throw OperationFailed(error, __FILENAME__, __LINE__); } - if (auto error = m_table_metadata_decompressor.try_read_numeric_value(uncompressed_size); + if (auto error = m_table_metadata_decompressor.try_read_numeric_value(num_messages); ErrorCodeSuccess != error) { throw OperationFailed(error, __FILENAME__, __LINE__); } - m_id_to_table_metadata[schema_id] = {num_messages, table_offset, uncompressed_size}; + if (prev_metadata_initialized) { + uint64_t uncompressed_size{0}; + if (stream_id != prev_metadata.stream_id) { + uncompressed_size + = m_stream_reader.get_uncompressed_stream_size(prev_metadata.stream_id) + - prev_metadata.stream_offset; + } else { + uncompressed_size = stream_offset - prev_metadata.stream_offset; + } + prev_metadata.uncompressed_size = uncompressed_size; + m_id_to_schema_metadata[prev_schema_id] = prev_metadata; + } else { + prev_metadata_initialized = true; + } + prev_metadata = {stream_id, stream_offset, num_messages, 0}; + prev_schema_id = schema_id; m_schema_ids.push_back(schema_id); } + prev_metadata.uncompressed_size + = m_stream_reader.get_uncompressed_stream_size(prev_metadata.stream_id) + - prev_metadata.stream_offset; + m_id_to_schema_metadata[prev_schema_id] = prev_metadata; m_table_metadata_decompressor.close(); } @@ -89,14 +129,12 @@ void ArchiveReader::read_dictionaries_and_metadata() { read_metadata(); } -SchemaReader& ArchiveReader::read_table( +SchemaReader& ArchiveReader::read_schema_table( int32_t schema_id, bool should_extract_timestamp, bool should_marshal_records ) { - constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB - - if (m_id_to_table_metadata.count(schema_id) == 0) { + if (m_id_to_schema_metadata.count(schema_id) == 0) { throw OperationFailed(ErrorCodeFileNotFound, __FILENAME__, __LINE__); } @@ -107,30 +145,26 @@ SchemaReader& ArchiveReader::read_table( should_marshal_records ); - m_tables_file_reader.try_seek_from_begin(m_id_to_table_metadata[schema_id].offset); - m_tables_decompressor.open(m_tables_file_reader, cDecompressorFileReadBufferCapacity); - m_schema_reader.load( - m_tables_decompressor, - m_id_to_table_metadata[schema_id].uncompressed_size - ); - m_tables_decompressor.close_for_reuse(); + auto& schema_metadata = m_id_to_schema_metadata[schema_id]; + auto stream_buffer = read_stream(schema_metadata.stream_id, true); + m_schema_reader + .load(stream_buffer, schema_metadata.stream_offset, schema_metadata.uncompressed_size); return m_schema_reader; } std::vector> ArchiveReader::read_all_tables() { - constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB - std::vector> readers; - readers.reserve(m_id_to_table_metadata.size()); - for (auto const& [id, table_metadata] : m_id_to_table_metadata) { + readers.reserve(m_id_to_schema_metadata.size()); + for (auto schema_id : m_schema_ids) { auto schema_reader = std::make_shared(); - initialize_schema_reader(*schema_reader, id, true, true); - - m_tables_file_reader.try_seek_from_begin(table_metadata.offset); - m_tables_decompressor.open(m_tables_file_reader, cDecompressorFileReadBufferCapacity); - schema_reader->load(m_tables_decompressor, table_metadata.uncompressed_size); - m_tables_decompressor.close_for_reuse(); - + initialize_schema_reader(*schema_reader, schema_id, true, true); + auto& schema_metadata = m_id_to_schema_metadata[schema_id]; + auto stream_buffer = read_stream(schema_metadata.stream_id, false); + schema_reader->load( + stream_buffer, + schema_metadata.stream_offset, + schema_metadata.uncompressed_size + ); readers.push_back(std::move(schema_reader)); } return readers; @@ -238,7 +272,7 @@ void ArchiveReader::initialize_schema_reader( m_projection, schema_id, schema.get_ordered_schema_view(), - m_id_to_table_metadata[schema_id].num_messages, + m_id_to_schema_metadata[schema_id].num_messages, should_marshal_records ); auto timestamp_column_ids = m_timestamp_dict->get_authoritative_timestamp_column_ids(); @@ -285,9 +319,8 @@ void ArchiveReader::initialize_schema_reader( void ArchiveReader::store(FileWriter& writer) { std::string message; - - for (auto& [id, table_metadata] : m_id_to_table_metadata) { - auto& schema_reader = read_table(id, false, true); + for (auto schema_id : m_schema_ids) { + auto& schema_reader = read_schema_table(schema_id, false, true); while (schema_reader.get_next_message(message)) { writer.write(message.c_str(), message.length()); } @@ -305,11 +338,28 @@ void ArchiveReader::close() { m_array_dict->close(); m_timestamp_dict->close(); - m_tables_file_reader.close(); + m_stream_reader.close(); m_table_metadata_file_reader.close(); - m_id_to_table_metadata.clear(); + m_id_to_schema_metadata.clear(); m_schema_ids.clear(); + m_cur_stream_id = 0; + m_stream_buffer.reset(); + m_stream_buffer_size = 0ULL; } +std::shared_ptr ArchiveReader::read_stream(size_t stream_id, bool reuse_buffer) { + if (nullptr != m_stream_buffer && m_cur_stream_id == stream_id) { + return m_stream_buffer; + } + + if (false == reuse_buffer) { + m_stream_buffer.reset(); + m_stream_buffer_size = 0; + } + + m_stream_reader.read_stream(stream_id, m_stream_buffer, m_stream_buffer_size); + m_cur_stream_id = stream_id; + return m_stream_buffer; +} } // namespace clp_s diff --git a/components/core/src/clp_s/ArchiveReader.hpp b/components/core/src/clp_s/ArchiveReader.hpp index 97966131f..41073ec84 100644 --- a/components/core/src/clp_s/ArchiveReader.hpp +++ b/components/core/src/clp_s/ArchiveReader.hpp @@ -10,6 +10,7 @@ #include #include "DictionaryReader.hpp" +#include "PackedStreamReader.hpp" #include "ReaderUtils.hpp" #include "SchemaReader.hpp" #include "search/Projection.hpp" @@ -92,8 +93,11 @@ class ArchiveReader { * @param should_marshal_records * @return the schema reader */ - SchemaReader& - read_table(int32_t schema_id, bool should_extract_timestamp, bool should_marshal_records); + SchemaReader& read_schema_table( + int32_t schema_id, + bool should_extract_timestamp, + bool should_marshal_records + ); /** * Loads all of the tables in the archive and returns SchemaReaders for them. @@ -176,6 +180,18 @@ class ArchiveReader { bool should_marshal_records ); + /** + * Reads a table with given ID from the packed stream reader. If read_stream is called multiple + * times in a row for the same stream_id a cached buffer is returned. This function allows the + * caller to ask for the same buffer to be reused to read multiple different tables: this can + * save memory allocations, but can only be used when tables are read one at a time. + * @param stream_id + * @param reuse_buffer when true the same buffer is reused across invocations, overwriting data + * returned previous calls to read_stream + * @return a buffer containing the decompressed stream identified by stream_id + */ + std::shared_ptr read_stream(size_t stream_id, bool reuse_buffer); + bool m_is_open; std::string m_archive_id; std::shared_ptr m_var_dict; @@ -186,16 +202,18 @@ class ArchiveReader { std::shared_ptr m_schema_tree; std::shared_ptr m_schema_map; std::vector m_schema_ids; - std::map m_id_to_table_metadata; + std::map m_id_to_schema_metadata; std::shared_ptr m_projection{ std::make_shared(search::ProjectionMode::ReturnAllColumns) }; - FileReader m_tables_file_reader; + PackedStreamReader m_stream_reader; FileReader m_table_metadata_file_reader; - ZstdDecompressor m_tables_decompressor; ZstdDecompressor m_table_metadata_decompressor; SchemaReader m_schema_reader; + std::shared_ptr m_stream_buffer{}; + size_t m_stream_buffer_size{0ULL}; + size_t m_cur_stream_id{0ULL}; }; } // namespace clp_s diff --git a/components/core/src/clp_s/ArchiveWriter.cpp b/components/core/src/clp_s/ArchiveWriter.cpp index ba540a79d..369fd79d2 100644 --- a/components/core/src/clp_s/ArchiveWriter.cpp +++ b/components/core/src/clp_s/ArchiveWriter.cpp @@ -1,5 +1,7 @@ #include "ArchiveWriter.hpp" +#include + #include #include "archive_constants.hpp" @@ -11,6 +13,7 @@ void ArchiveWriter::open(ArchiveWriterOption const& option) { m_id = boost::uuids::to_string(option.id); m_compression_level = option.compression_level; m_print_archive_stats = option.print_archive_stats; + m_min_table_size = option.min_table_size; auto archive_path = boost::filesystem::path(option.archives_dir) / m_id; boost::system::error_code boost_error_code; @@ -138,18 +141,103 @@ size_t ArchiveWriter::store_tables() { FileWriter::OpenMode::CreateForWriting ); m_table_metadata_compressor.open(m_table_metadata_file_writer, m_compression_level); - m_table_metadata_compressor.write_numeric_value(m_id_to_schema_writer.size()); - for (auto& i : m_id_to_schema_writer) { - m_table_metadata_compressor.write_numeric_value(i.first); - m_table_metadata_compressor.write_numeric_value(i.second->get_num_messages()); - m_table_metadata_compressor.write_numeric_value(m_tables_file_writer.get_pos()); - - m_tables_compressor.open(m_tables_file_writer, m_compression_level); - size_t uncompressed_size = i.second->store(m_tables_compressor); - m_tables_compressor.close(); - delete i.second; - - m_table_metadata_compressor.write_numeric_value(uncompressed_size); + + /** + * Packed stream metadata schema + * ------------------------------ + * Schema tables are packed into a series of compression streams. Each of those compression + * streams is identified by a 64 bit stream id. In the first half of the metadata we identify + * how many streams there are, and the offset into the file where each compression stream can + * be found. In the second half of the metadata we record how many schema tables there are, + * which compression stream they belong to, the offset into that compression stream where + * they can be found, and how many messages that schema table contains. + * + * Section 1: Compression Streams Metadata + * - Contains metadata about each compression stream. + * - Structure: + * - Number of packed streams: <64-bit integer> + * - For each stream: + * - Offset into the file: <64-bit integer> + * - Uncompressed size: <64-bit integer> + * - Number of separate column schemas: <64-bit integer> + * It is always 0 in the current implementation. + * - Undefined section for separate column schemas, reserved for future support. + * + * Section 2: Schema Tables Metadata + * - Contains metadata about schema tables associated with each compression stream. + * - Structure: + * - Number of schema tables: <64-bit integer> + * - For each schema table: + * - Stream ID: <64-bit integer> + * - Offset into the stream: <64-bit integer> + * - Schema ID: <32-bit integer> + * - Number of messages: <64-bit integer> + * + * We buffer the first half of the metadata in the "stream_metadata" vector, and the second half + * of the metadata in the "schema_metadata" vector as we compress the tables. The metadata is + * flushed once all of the schema tables have been compressed. + */ + using schema_map_it = decltype(m_id_to_schema_writer)::iterator; + std::vector schemas; + std::vector stream_metadata; + std::vector schema_metadata; + + schema_metadata.reserve(m_id_to_schema_writer.size()); + schemas.reserve(m_id_to_schema_writer.size()); + for (auto it = m_id_to_schema_writer.begin(); it != m_id_to_schema_writer.end(); ++it) { + schemas.push_back(it); + } + auto comp = [](schema_map_it const& lhs, schema_map_it const& rhs) -> bool { + return lhs->second->get_total_uncompressed_size() + > rhs->second->get_total_uncompressed_size(); + }; + std::sort(schemas.begin(), schemas.end(), comp); + + uint64_t current_stream_offset = 0; + uint64_t current_stream_id = 0; + uint64_t current_table_file_offset = 0; + m_tables_compressor.open(m_tables_file_writer, m_compression_level); + for (auto it : schemas) { + it->second->store(m_tables_compressor); + schema_metadata.emplace_back( + current_stream_id, + current_stream_offset, + it->first, + it->second->get_num_messages() + ); + current_stream_offset += it->second->get_total_uncompressed_size(); + delete it->second; + + if (current_stream_offset > m_min_table_size || schemas.size() == schema_metadata.size()) { + stream_metadata.emplace_back(current_table_file_offset, current_stream_offset); + m_tables_compressor.close(); + current_stream_offset = 0; + ++current_stream_id; + current_table_file_offset = m_tables_file_writer.get_pos(); + + if (schemas.size() != schema_metadata.size()) { + m_tables_compressor.open(m_tables_file_writer, m_compression_level); + } + } + } + + m_table_metadata_compressor.write_numeric_value(stream_metadata.size()); + for (auto& stream : stream_metadata) { + m_table_metadata_compressor.write_numeric_value(stream.file_offset); + m_table_metadata_compressor.write_numeric_value(stream.uncompressed_size); + } + + // The current implementation doesn't store large tables as separate columns, so this is always + // zero. + size_t const num_separate_column_schemas{0}; + m_table_metadata_compressor.write_numeric_value(num_separate_column_schemas); + + m_table_metadata_compressor.write_numeric_value(schema_metadata.size()); + for (auto& schema : schema_metadata) { + m_table_metadata_compressor.write_numeric_value(schema.stream_id); + m_table_metadata_compressor.write_numeric_value(schema.stream_offset); + m_table_metadata_compressor.write_numeric_value(schema.schema_id); + m_table_metadata_compressor.write_numeric_value(schema.num_messages); } m_table_metadata_compressor.close(); diff --git a/components/core/src/clp_s/ArchiveWriter.hpp b/components/core/src/clp_s/ArchiveWriter.hpp index 70eb5dc9b..7edfe4491 100644 --- a/components/core/src/clp_s/ArchiveWriter.hpp +++ b/components/core/src/clp_s/ArchiveWriter.hpp @@ -21,6 +21,7 @@ struct ArchiveWriterOption { std::string archives_dir; int compression_level; bool print_archive_stats; + size_t min_table_size; }; class ArchiveWriter { @@ -32,6 +33,33 @@ class ArchiveWriter { : TraceableException(error_code, filename, line_number) {} }; + struct StreamMetadata { + StreamMetadata(uint64_t file_offset, uint64_t uncompressed_size) + : file_offset(file_offset), + uncompressed_size(uncompressed_size) {} + + uint64_t file_offset{}; + uint64_t uncompressed_size{}; + }; + + struct SchemaMetadata { + SchemaMetadata( + uint64_t stream_id, + uint64_t stream_offset, + int32_t schema_id, + uint64_t num_messages + ) + : stream_id(stream_id), + stream_offset(stream_offset), + schema_id(schema_id), + num_messages(num_messages) {} + + uint64_t stream_id{}; + uint64_t stream_offset{}; + int32_t schema_id{}; + uint64_t num_messages{}; + }; + // Constructor explicit ArchiveWriter(std::shared_ptr metadata_db) : m_metadata_db(std::move(metadata_db)) {} @@ -159,6 +187,7 @@ class ArchiveWriter { std::shared_ptr m_metadata_db; int m_compression_level{}; bool m_print_archive_stats{}; + size_t m_min_table_size{}; SchemaMap m_schema_map; SchemaTree m_schema_tree; diff --git a/components/core/src/clp_s/CMakeLists.txt b/components/core/src/clp_s/CMakeLists.txt index 625972de7..1656a5d59 100644 --- a/components/core/src/clp_s/CMakeLists.txt +++ b/components/core/src/clp_s/CMakeLists.txt @@ -65,6 +65,8 @@ set( JsonParser.cpp JsonParser.hpp JsonSerializer.hpp + PackedStreamReader.cpp + PackedStreamReader.hpp ParsedMessage.hpp ReaderUtils.cpp ReaderUtils.hpp diff --git a/components/core/src/clp_s/ColumnWriter.cpp b/components/core/src/clp_s/ColumnWriter.cpp index 183f17e57..77fa51f15 100644 --- a/components/core/src/clp_s/ColumnWriter.cpp +++ b/components/core/src/clp_s/ColumnWriter.cpp @@ -1,41 +1,37 @@ #include "ColumnWriter.hpp" namespace clp_s { -void Int64ColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& size) { - size = sizeof(int64_t); +size_t Int64ColumnWriter::add_value(ParsedMessage::variable_t& value) { m_values.push_back(std::get(value)); + return sizeof(int64_t); } -size_t Int64ColumnWriter::store(ZstdCompressor& compressor) { +void Int64ColumnWriter::store(ZstdCompressor& compressor) { size_t size = m_values.size() * sizeof(int64_t); compressor.write(reinterpret_cast(m_values.data()), size); - return size; } -void FloatColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& size) { - size = sizeof(double); +size_t FloatColumnWriter::add_value(ParsedMessage::variable_t& value) { m_values.push_back(std::get(value)); + return sizeof(double); } -size_t FloatColumnWriter::store(ZstdCompressor& compressor) { +void FloatColumnWriter::store(ZstdCompressor& compressor) { size_t size = m_values.size() * sizeof(double); compressor.write(reinterpret_cast(m_values.data()), size); - return size; } -void BooleanColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& size) { - size = sizeof(uint8_t); +size_t BooleanColumnWriter::add_value(ParsedMessage::variable_t& value) { m_values.push_back(std::get(value) ? 1 : 0); + return sizeof(uint8_t); } -size_t BooleanColumnWriter::store(ZstdCompressor& compressor) { +void BooleanColumnWriter::store(ZstdCompressor& compressor) { size_t size = m_values.size() * sizeof(uint8_t); compressor.write(reinterpret_cast(m_values.data()), size); - return size; } -void ClpStringColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& size) { - size = sizeof(int64_t); +size_t ClpStringColumnWriter::add_value(ParsedMessage::variable_t& value) { std::string string_var = std::get(value); uint64_t id; uint64_t offset = m_encoded_vars.size(); @@ -48,45 +44,43 @@ void ClpStringColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& m_log_dict->add_entry(m_logtype_entry, id); auto encoded_id = encode_log_dict_id(id, offset); m_logtypes.push_back(encoded_id); - size += sizeof(int64_t) * (m_encoded_vars.size() - offset); + return sizeof(int64_t) + sizeof(int64_t) * (m_encoded_vars.size() - offset); } -size_t ClpStringColumnWriter::store(ZstdCompressor& compressor) { +void ClpStringColumnWriter::store(ZstdCompressor& compressor) { size_t logtypes_size = m_logtypes.size() * sizeof(int64_t); compressor.write(reinterpret_cast(m_logtypes.data()), logtypes_size); size_t encoded_vars_size = m_encoded_vars.size() * sizeof(int64_t); size_t num_encoded_vars = m_encoded_vars.size(); compressor.write_numeric_value(num_encoded_vars); compressor.write(reinterpret_cast(m_encoded_vars.data()), encoded_vars_size); - return logtypes_size + sizeof(num_encoded_vars) + encoded_vars_size; } -void VariableStringColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& size) { - size = sizeof(int64_t); +size_t VariableStringColumnWriter::add_value(ParsedMessage::variable_t& value) { std::string string_var = std::get(value); uint64_t id; m_var_dict->add_entry(string_var, id); m_variables.push_back(id); + return sizeof(int64_t); } -size_t VariableStringColumnWriter::store(ZstdCompressor& compressor) { +void VariableStringColumnWriter::store(ZstdCompressor& compressor) { size_t size = m_variables.size() * sizeof(int64_t); compressor.write(reinterpret_cast(m_variables.data()), size); - return size; } -void DateStringColumnWriter::add_value(ParsedMessage::variable_t& value, size_t& size) { - size = 2 * sizeof(int64_t); +size_t DateStringColumnWriter::add_value(ParsedMessage::variable_t& value) { auto encoded_timestamp = std::get>(value); m_timestamps.push_back(encoded_timestamp.second); m_timestamp_encodings.push_back(encoded_timestamp.first); + return 2 * sizeof(int64_t); + ; } -size_t DateStringColumnWriter::store(ZstdCompressor& compressor) { +void DateStringColumnWriter::store(ZstdCompressor& compressor) { size_t timestamps_size = m_timestamps.size() * sizeof(int64_t); compressor.write(reinterpret_cast(m_timestamps.data()), timestamps_size); size_t encodings_size = m_timestamp_encodings.size() * sizeof(int64_t); compressor.write(reinterpret_cast(m_timestamp_encodings.data()), encodings_size); - return timestamps_size + encodings_size; } } // namespace clp_s diff --git a/components/core/src/clp_s/ColumnWriter.hpp b/components/core/src/clp_s/ColumnWriter.hpp index ce458381e..7282cf7ea 100644 --- a/components/core/src/clp_s/ColumnWriter.hpp +++ b/components/core/src/clp_s/ColumnWriter.hpp @@ -27,16 +27,24 @@ class BaseColumnWriter { /** * Adds a value to the column * @param value - * @param size + * @return the size of the encoded data appended to this column in bytes */ - virtual void add_value(ParsedMessage::variable_t& value, size_t& size) = 0; + virtual size_t add_value(ParsedMessage::variable_t& value) = 0; /** * Stores the column to a compressed file. * @param compressor - * @return the in-memory uncompressed size of the data written to the compressor */ - virtual size_t store(ZstdCompressor& compressor) = 0; + virtual void store(ZstdCompressor& compressor) = 0; + + /** + * Returns the total size of the header data that will be written to the compressor. This header + * size plus the sum of sizes returned by add_value is equal to the total size of data that will + * be written to the compressor in bytes. + * + * @return the total size of header data that will be written to the compressor in bytes + */ + virtual size_t get_total_header_size() const { return 0; } protected: int32_t m_id; @@ -51,9 +59,9 @@ class Int64ColumnWriter : public BaseColumnWriter { ~Int64ColumnWriter() override = default; // Methods inherited from BaseColumnWriter - void add_value(ParsedMessage::variable_t& value, size_t& size) override; + size_t add_value(ParsedMessage::variable_t& value) override; - size_t store(ZstdCompressor& compressor) override; + void store(ZstdCompressor& compressor) override; private: std::vector m_values; @@ -68,9 +76,9 @@ class FloatColumnWriter : public BaseColumnWriter { ~FloatColumnWriter() override = default; // Methods inherited from BaseColumnWriter - void add_value(ParsedMessage::variable_t& value, size_t& size) override; + size_t add_value(ParsedMessage::variable_t& value) override; - size_t store(ZstdCompressor& compressor) override; + void store(ZstdCompressor& compressor) override; private: std::vector m_values; @@ -85,9 +93,9 @@ class BooleanColumnWriter : public BaseColumnWriter { ~BooleanColumnWriter() override = default; // Methods inherited from BaseColumnWriter - void add_value(ParsedMessage::variable_t& value, size_t& size) override; + size_t add_value(ParsedMessage::variable_t& value) override; - size_t store(ZstdCompressor& compressor) override; + void store(ZstdCompressor& compressor) override; private: std::vector m_values; @@ -109,9 +117,11 @@ class ClpStringColumnWriter : public BaseColumnWriter { ~ClpStringColumnWriter() override = default; // Methods inherited from BaseColumnWriter - void add_value(ParsedMessage::variable_t& value, size_t& size) override; + size_t add_value(ParsedMessage::variable_t& value) override; + + void store(ZstdCompressor& compressor) override; - size_t store(ZstdCompressor& compressor) override; + size_t get_total_header_size() const override { return sizeof(size_t); } /** * @param encoded_id @@ -163,9 +173,9 @@ class VariableStringColumnWriter : public BaseColumnWriter { ~VariableStringColumnWriter() override = default; // Methods inherited from BaseColumnWriter - void add_value(ParsedMessage::variable_t& value, size_t& size) override; + size_t add_value(ParsedMessage::variable_t& value) override; - size_t store(ZstdCompressor& compressor) override; + void store(ZstdCompressor& compressor) override; private: std::shared_ptr m_var_dict; @@ -181,9 +191,9 @@ class DateStringColumnWriter : public BaseColumnWriter { ~DateStringColumnWriter() override = default; // Methods inherited from BaseColumnWriter - void add_value(ParsedMessage::variable_t& value, size_t& size) override; + size_t add_value(ParsedMessage::variable_t& value) override; - size_t store(ZstdCompressor& compressor) override; + void store(ZstdCompressor& compressor) override; private: std::vector m_timestamps; diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index 553f17c39..cf69a066c 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -160,6 +160,11 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { default_value(m_target_encoded_size), "Target size (B) for the dictionaries and encoded messages before a new " "archive is created." + )( + "min-table-size", + po::value(&m_minimum_table_size)->value_name("MIN_TABLE_SIZE")-> + default_value(m_minimum_table_size), + "Minimum size (B) for a packed table before it gets compressed." )( "max-document-size", po::value(&m_max_document_size)->value_name("DOC_SIZE")-> diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 030ff8b99..798e42728 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -108,6 +108,8 @@ class CommandLineArguments { size_t get_ordered_chunk_size() const { return m_ordered_chunk_size; } + size_t get_minimum_table_size() const { return m_minimum_table_size; } + std::vector const& get_projection_columns() const { return m_projection_columns; } private: @@ -175,6 +177,7 @@ class CommandLineArguments { bool m_structurize_arrays{false}; bool m_ordered_decompression{false}; size_t m_ordered_chunk_size{0}; + size_t m_minimum_table_size{1ULL * 1024 * 1024}; // 1 MB // Metadata db variables std::optional m_metadata_db_config; diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index a68062958..7d4af1469 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -31,6 +31,7 @@ JsonParser::JsonParser(JsonParserOption const& option) m_archive_options.archives_dir = option.archives_dir; m_archive_options.compression_level = option.compression_level; m_archive_options.print_archive_stats = option.print_archive_stats; + m_archive_options.min_table_size = option.min_table_size; m_archive_options.id = m_generator(); m_archive_writer = std::make_unique(option.metadata_db); diff --git a/components/core/src/clp_s/JsonParser.hpp b/components/core/src/clp_s/JsonParser.hpp index 84aa27fef..af6b024ef 100644 --- a/components/core/src/clp_s/JsonParser.hpp +++ b/components/core/src/clp_s/JsonParser.hpp @@ -32,6 +32,7 @@ struct JsonParserOption { std::string archives_dir; size_t target_encoded_size; size_t max_document_size; + size_t min_table_size; int compression_level; bool print_archive_stats; bool structurize_arrays; diff --git a/components/core/src/clp_s/PackedStreamReader.cpp b/components/core/src/clp_s/PackedStreamReader.cpp new file mode 100644 index 000000000..44eb94e96 --- /dev/null +++ b/components/core/src/clp_s/PackedStreamReader.cpp @@ -0,0 +1,117 @@ +#include "PackedStreamReader.hpp" + +namespace clp_s { + +void PackedStreamReader::read_metadata(ZstdDecompressor& decompressor) { + switch (m_state) { + case PackedStreamReaderState::Uninitialized: + m_state = PackedStreamReaderState::MetadataRead; + break; + case PackedStreamReaderState::PackedStreamsOpened: + m_state = PackedStreamReaderState::PackedStreamsOpenedAndMetadataRead; + break; + default: + throw OperationFailed(ErrorCodeNotReady, __FILE__, __LINE__); + } + + size_t num_streams; + if (auto error = decompressor.try_read_numeric_value(num_streams); ErrorCodeSuccess != error) { + throw OperationFailed(error, __FILE__, __LINE__); + } + m_stream_metadata.reserve(num_streams); + + for (size_t i = 0; i < num_streams; ++i) { + size_t file_offset; + size_t uncompressed_size; + + if (auto error = decompressor.try_read_numeric_value(file_offset); + ErrorCodeSuccess != error) + { + throw OperationFailed(error, __FILE__, __LINE__); + } + + if (auto error = decompressor.try_read_numeric_value(uncompressed_size); + ErrorCodeSuccess != error) + { + throw OperationFailed(error, __FILE__, __LINE__); + } + + m_stream_metadata.emplace_back(file_offset, uncompressed_size); + } +} + +void PackedStreamReader::open_packed_streams(std::string const& tables_file_path) { + switch (m_state) { + case PackedStreamReaderState::Uninitialized: + m_state = PackedStreamReaderState::PackedStreamsOpened; + break; + case PackedStreamReaderState::MetadataRead: + m_state = PackedStreamReaderState::PackedStreamsOpenedAndMetadataRead; + break; + default: + throw OperationFailed(ErrorCodeNotReady, __FILE__, __LINE__); + } + m_packed_stream_reader.open(tables_file_path); +} + +void PackedStreamReader::close() { + switch (m_state) { + case PackedStreamReaderState::PackedStreamsOpened: + case PackedStreamReaderState::PackedStreamsOpenedAndMetadataRead: + case PackedStreamReaderState::ReadingPackedStreams: + break; + default: + throw OperationFailed(ErrorCodeNotReady, __FILE__, __LINE__); + } + m_packed_stream_reader.close(); + m_prev_stream_id = 0; + m_stream_metadata.clear(); + m_state = PackedStreamReaderState::Uninitialized; +} + +void PackedStreamReader::read_stream( + size_t stream_id, + std::shared_ptr& buf, + size_t& buf_size +) { + constexpr size_t cDecompressorFileReadBufferCapacity = 64 * 1024; // 64 KB + if (stream_id >= m_stream_metadata.size()) { + throw OperationFailed(ErrorCodeCorrupt, __FILE__, __LINE__); + } + + switch (m_state) { + case PackedStreamReaderState::PackedStreamsOpenedAndMetadataRead: + m_state = PackedStreamReaderState::ReadingPackedStreams; + break; + case PackedStreamReaderState::ReadingPackedStreams: + if (m_prev_stream_id >= stream_id) { + throw OperationFailed(ErrorCodeBadParam, __FILE__, __LINE__); + } + break; + default: + throw OperationFailed(ErrorCodeNotReady, __FILE__, __LINE__); + } + m_prev_stream_id = stream_id; + + auto& [file_offset, uncompressed_size] = m_stream_metadata[stream_id]; + if (auto error = m_packed_stream_reader.try_seek_from_begin(file_offset); + ErrorCodeSuccess != error) + { + throw OperationFailed(error, __FILE__, __LINE__); + } + m_packed_stream_decompressor.open(m_packed_stream_reader, cDecompressorFileReadBufferCapacity); + if (buf_size < uncompressed_size) { + // make_shared is supposed to work here for c++20, but it seems like the compiler version + // we use doesn't support it, so we convert a unique_ptr to a shared_ptr instead. + buf = std::make_unique(uncompressed_size); + buf_size = uncompressed_size; + } + if (auto error + = m_packed_stream_decompressor.try_read_exact_length(buf.get(), uncompressed_size); + ErrorCodeSuccess != error) + { + throw OperationFailed(error, __FILE__, __LINE__); + } + m_packed_stream_decompressor.close_for_reuse(); +} +} // namespace clp_s diff --git a/components/core/src/clp_s/PackedStreamReader.hpp b/components/core/src/clp_s/PackedStreamReader.hpp new file mode 100644 index 000000000..d9f9af58f --- /dev/null +++ b/components/core/src/clp_s/PackedStreamReader.hpp @@ -0,0 +1,97 @@ +#ifndef CLP_S_PACKEDSTREAMREADER_HPP +#define CLP_S_PACKEDSTREAMREADER_HPP + +#include +#include +#include +#include + +#include "FileReader.hpp" +#include "ZstdDecompressor.hpp" + +namespace clp_s { +/** + * PackedStreamReader ensures that the tables section of an archive is read safely. Any attempt to + * read the tables section without loading the tables metadata, and any attempt to read tables + * section out of order will throw. As well, any incorrect usage of this class (e.g. closing without + * opening) will throw. + */ +class PackedStreamReader { +public: + class OperationFailed : public TraceableException { + public: + // Constructors + OperationFailed(ErrorCode error_code, char const* const filename, int line_number) + : TraceableException(error_code, filename, line_number) {} + }; + + struct PackedStreamMetadata { + PackedStreamMetadata(size_t offset, size_t size) + : file_offset(offset), + uncompressed_size(size) {} + + size_t file_offset; + size_t uncompressed_size; + }; + + /** + * Reads packed stream metadata from the provided compression stream. Must be invoked before + * reading packed streams. + * @param decompressor an open ZstdDecompressor pointing to the packed stream metadata + */ + void read_metadata(ZstdDecompressor& decompressor); + + /** + * Opens a file reader for the tables section. Must be invoked before reading packed streams. + * @param tables_file_path the path to the tables file for the archive being read + */ + void open_packed_streams(std::string const& tables_file_path); + + /** + * Closes the file reader for the tables section. + */ + void close(); + + /** + * Decompresses a stream with a given stream_id and returns it. This function must be called + * strictly in ascending stream_id order. If this function is called twice for the same stream + * or if a stream with lower id is requested after a stream with higher id then an error is + * thrown. + * + * Note: the buffer and buffer size are returned by reference. This is to support the use case + * where the caller wants to re-use the same buffer for multiple streams to avoid allocations + * when they already have a sufficiently large buffer. If no buffer is provided or the provided + * buffer is too small calling read_stream will create a buffer exactly as large as the stream + * being decompressed. + * + * @param stream_id + * @param buf a shared ptr to the buffer where the stream will be read. The buffer gets resized + * if it is too small to contain the requested stream. + * @param buf_size the size of the underlying buffer owned by buf -- passed and updated by + * reference + */ + void read_stream(size_t stream_id, std::shared_ptr& buf, size_t& buf_size); + + [[nodiscard]] size_t get_uncompressed_stream_size(size_t stream_id) const { + return m_stream_metadata.at(stream_id).uncompressed_size; + } + +private: + enum PackedStreamReaderState { + Uninitialized, + MetadataRead, + PackedStreamsOpened, + PackedStreamsOpenedAndMetadataRead, + ReadingPackedStreams + }; + + std::vector m_stream_metadata; + FileReader m_packed_stream_reader; + ZstdDecompressor m_packed_stream_decompressor; + PackedStreamReaderState m_state{PackedStreamReaderState::Uninitialized}; + size_t m_prev_stream_id{0ULL}; +}; + +} // namespace clp_s + +#endif // CLP_S_PACKEDSTREAMREADER_HPP diff --git a/components/core/src/clp_s/SchemaReader.cpp b/components/core/src/clp_s/SchemaReader.cpp index d2c7739da..35c1d0a6e 100644 --- a/components/core/src/clp_s/SchemaReader.cpp +++ b/components/core/src/clp_s/SchemaReader.cpp @@ -37,17 +37,13 @@ void SchemaReader::mark_column_as_timestamp(BaseColumnReader* column_reader) { } } -void SchemaReader::load(ZstdDecompressor& decompressor, size_t uncompressed_size) { - if (uncompressed_size > m_table_buffer_size) { - m_table_buffer = std::make_unique(uncompressed_size); - m_table_buffer_size = uncompressed_size; - } - auto error = decompressor.try_read_exact_length(m_table_buffer.get(), uncompressed_size); - if (ErrorCodeSuccess != error) { - throw OperationFailed(error, __FILENAME__, __LINE__); - } - - BufferViewReader buffer_reader{m_table_buffer.get(), uncompressed_size}; +void SchemaReader::load( + std::shared_ptr stream_buffer, + size_t offset, + size_t uncompressed_size +) { + m_stream_buffer = stream_buffer; + BufferViewReader buffer_reader{m_stream_buffer.get() + offset, uncompressed_size}; for (auto& reader : m_columns) { reader->load(buffer_reader, m_num_messages); } diff --git a/components/core/src/clp_s/SchemaReader.hpp b/components/core/src/clp_s/SchemaReader.hpp index d72b2c3b6..08651cc39 100644 --- a/components/core/src/clp_s/SchemaReader.hpp +++ b/components/core/src/clp_s/SchemaReader.hpp @@ -1,6 +1,7 @@ #ifndef CLP_S_SCHEMAREADER_HPP #define CLP_S_SCHEMAREADER_HPP +#include #include #include #include @@ -48,10 +49,11 @@ class SchemaReader { : TraceableException(error_code, filename, line_number) {} }; - struct TableMetadata { + struct SchemaMetadata { + uint64_t stream_id; + uint64_t stream_offset; uint64_t num_messages; - size_t offset; - size_t uncompressed_size; + uint64_t uncompressed_size; }; // Constructor @@ -134,11 +136,12 @@ class SchemaReader { ); /** - * Loads the encoded messages - * @param decompressor + * Loads the encoded messages from a shared buffer starting at a given offset + * @param stream_buffer + * @param offset * @param uncompressed_size */ - void load(ZstdDecompressor& decompressor, size_t uncompressed_size); + void load(std::shared_ptr stream_buffer, size_t offset, size_t uncompressed_size); /** * Gets next message @@ -281,8 +284,7 @@ class SchemaReader { std::unordered_map m_column_map; std::vector m_columns; std::vector m_reordered_columns; - std::unique_ptr m_table_buffer; - size_t m_table_buffer_size{0}; + std::shared_ptr m_stream_buffer; BaseColumnReader* m_timestamp_column; std::function m_get_timestamp; diff --git a/components/core/src/clp_s/SchemaWriter.cpp b/components/core/src/clp_s/SchemaWriter.cpp index b6de15f2f..ae3f16f15 100644 --- a/components/core/src/clp_s/SchemaWriter.cpp +++ b/components/core/src/clp_s/SchemaWriter.cpp @@ -4,35 +4,32 @@ namespace clp_s { void SchemaWriter::append_column(BaseColumnWriter* column_writer) { + m_total_uncompressed_size += column_writer->get_total_header_size(); m_columns.push_back(column_writer); } size_t SchemaWriter::append_message(ParsedMessage& message) { - int count = 0; - size_t size, total_size; - size = total_size = 0; + int count{}; + size_t total_size{}; for (auto& i : message.get_content()) { - m_columns[count]->add_value(i.second, size); - total_size += size; - count++; + total_size += m_columns[count]->add_value(i.second); + ++count; } for (auto& i : message.get_unordered_content()) { - m_columns[count]->add_value(i, size); - total_size += size; + total_size += m_columns[count]->add_value(i); ++count; } m_num_messages++; + m_total_uncompressed_size += total_size; return total_size; } -size_t SchemaWriter::store(ZstdCompressor& compressor) { - size_t total_size = 0; +void SchemaWriter::store(ZstdCompressor& compressor) { for (auto& writer : m_columns) { - total_size += writer->store(compressor); + writer->store(compressor); } - return total_size; } SchemaWriter::~SchemaWriter() { diff --git a/components/core/src/clp_s/SchemaWriter.hpp b/components/core/src/clp_s/SchemaWriter.hpp index 41b28600b..4f204d949 100644 --- a/components/core/src/clp_s/SchemaWriter.hpp +++ b/components/core/src/clp_s/SchemaWriter.hpp @@ -40,20 +40,19 @@ class SchemaWriter { /** * Stores the columns to disk. * @param compressor - * @return the uncompressed in-memory size of the table */ - [[nodiscard]] size_t store(ZstdCompressor& compressor); + void store(ZstdCompressor& compressor); + + uint64_t get_num_messages() const { return m_num_messages; } /** - * Closes the schema writer. - * @return the compressed size of the schema table in bytes + * @return the uncompressed in-memory size of the data that will be written to the compressor */ - [[nodiscard]] size_t close(); - - uint64_t get_num_messages() const { return m_num_messages; } + size_t get_total_uncompressed_size() const { return m_total_uncompressed_size; } private: uint64_t m_num_messages; + size_t m_total_uncompressed_size{}; std::vector m_columns; std::vector m_unordered_columns; diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 8e37ca769..5f4384a1c 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -91,6 +91,7 @@ bool compress(CommandLineArguments const& command_line_arguments) { option.archives_dir = archives_dir.string(); option.target_encoded_size = command_line_arguments.get_target_encoded_size(); option.max_document_size = command_line_arguments.get_max_document_size(); + option.min_table_size = command_line_arguments.get_minimum_table_size(); option.compression_level = command_line_arguments.get_compression_level(); option.timestamp_key = command_line_arguments.get_timestamp_key(); option.print_archive_stats = command_line_arguments.print_archive_stats(); diff --git a/components/core/src/clp_s/search/Output.cpp b/components/core/src/clp_s/search/Output.cpp index b6a3b8fe0..4d36b4e29 100644 --- a/components/core/src/clp_s/search/Output.cpp +++ b/components/core/src/clp_s/search/Output.cpp @@ -84,7 +84,7 @@ bool Output::filter() { add_wildcard_columns_to_searched_columns(); - auto& reader = m_archive_reader->read_table( + auto& reader = m_archive_reader->read_schema_table( schema_id, m_output_handler->should_output_metadata(), m_should_marshal_records From 829013bc94d87baf2a30ff28a5495de469a1d389 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:25:25 -0400 Subject: [PATCH 086/114] log-viewer-webui: Update `yscope-log-viewer` to the latest version. (#565) --- components/log-viewer-webui/yscope-log-viewer | 2 +- deps-tasks.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/log-viewer-webui/yscope-log-viewer b/components/log-viewer-webui/yscope-log-viewer index bc8109f9f..4c69bc11d 160000 --- a/components/log-viewer-webui/yscope-log-viewer +++ b/components/log-viewer-webui/yscope-log-viewer @@ -1 +1 @@ -Subproject commit bc8109f9f371c3327070000dee3537bdaf535428 +Subproject commit 4c69bc11dbe8a5d87b5fbfb0e43a2f2a06f04866 diff --git a/deps-tasks.yml b/deps-tasks.yml index eac7b6509..64a218a47 100644 --- a/deps-tasks.yml +++ b/deps-tasks.yml @@ -421,8 +421,8 @@ tasks: vars: DEST: "{{.DEST}}" FLAGS: "--extract" - SRC_NAME: "yscope-log-viewer-bc8109f9f371c3327070000dee3537bdaf535428" - SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/bc8109f.zip" + SRC_NAME: "yscope-log-viewer-4c69bc11dbe8a5d87b5fbfb0e43a2f2a06f04866" + SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/4c69bc1.zip" # This command must be last - task: ":utils:compute-checksum" vars: From b92a6c6fa55d1ca3127da8232a7c69c42768756e Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:49:04 -0400 Subject: [PATCH 087/114] ci: Switch GitHub macOS build workflow to use macos-13 (x86) and macos-14 (ARM) runners. (#566) --- .github/workflows/clp-core-build-macos.yaml | 9 +++++---- .github/workflows/clp-core-build.yaml | 4 ++-- .../lib_install/{macos-12 => macos}/install-all.sh | 0 docs/src/dev-guide/components-core/index.md | 4 ++-- .../{macos12-deps-install.md => macos-deps-install.md} | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) rename components/core/tools/scripts/lib_install/{macos-12 => macos}/install-all.sh (100%) rename docs/src/dev-guide/components-core/{macos12-deps-install.md => macos-deps-install.md} (85%) diff --git a/.github/workflows/clp-core-build-macos.yaml b/.github/workflows/clp-core-build-macos.yaml index dfcc46d31..85d04d9c7 100644 --- a/.github/workflows/clp-core-build-macos.yaml +++ b/.github/workflows/clp-core-build-macos.yaml @@ -8,7 +8,7 @@ on: - "components/core/CMakeLists.txt" - "components/core/src/**" - "components/core/tests/**" - - "components/core/tools/scripts/lib_install/macos-12/**" + - "components/core/tools/scripts/lib_install/macos/**" - "components/core/tools/scripts/deps-download/**" - "components/core/tools/scripts/utils/build-and-run-unit-tests.py" - "deps-tasks.yml" @@ -21,7 +21,7 @@ on: - "components/core/CMakeLists.txt" - "components/core/src/**" - "components/core/tests/**" - - "components/core/tools/scripts/lib_install/macos-12/**" + - "components/core/tools/scripts/lib_install/macos/**" - "components/core/tools/scripts/deps-download/**" - "components/core/tools/scripts/utils/build-and-run-unit-tests.py" - "deps-tasks.yml" @@ -38,8 +38,9 @@ jobs: build-macos: strategy: matrix: + runner: ["macos-13", "macos-14"] use_shared_libs: [true, false] - runs-on: "macos-12" + runs-on: "${{matrix.runner}}" steps: - uses: "actions/checkout@v4" with: @@ -55,7 +56,7 @@ jobs: rm -f /usr/local/bin/python3* - name: "Install dependencies" - run: "./components/core/tools/scripts/lib_install/macos-12/install-all.sh" + run: "./components/core/tools/scripts/lib_install/macos/install-all.sh" - run: "./tools/scripts/deps-download/init.sh" shell: "bash" diff --git a/.github/workflows/clp-core-build.yaml b/.github/workflows/clp-core-build.yaml index 9cec1fc2b..9046f15da 100644 --- a/.github/workflows/clp-core-build.yaml +++ b/.github/workflows/clp-core-build.yaml @@ -11,7 +11,7 @@ on: - "deps-tasks.yml" - "Taskfile.yml" - "tools/scripts/deps-download/**" - - "!components/core/tools/scripts/lib_install/macos-12/**" + - "!components/core/tools/scripts/lib_install/macos/**" push: paths: - ".github/actions/clp-core-build/action.yaml" @@ -22,7 +22,7 @@ on: - "deps-tasks.yml" - "Taskfile.yml" - "tools/scripts/deps-download/**" - - "!components/core/tools/scripts/lib_install/macos-12/**" + - "!components/core/tools/scripts/lib_install/macos/**" workflow_dispatch: env: diff --git a/components/core/tools/scripts/lib_install/macos-12/install-all.sh b/components/core/tools/scripts/lib_install/macos/install-all.sh similarity index 100% rename from components/core/tools/scripts/lib_install/macos-12/install-all.sh rename to components/core/tools/scripts/lib_install/macos/install-all.sh diff --git a/docs/src/dev-guide/components-core/index.md b/docs/src/dev-guide/components-core/index.md index 36fdad548..1406f1bd2 100644 --- a/docs/src/dev-guide/components-core/index.md +++ b/docs/src/dev-guide/components-core/index.md @@ -54,7 +54,7 @@ A handful of packages and libraries are required to build CLP. There are two opt See the relevant README for your OS: * [CentOS Stream 9](centos-stream-9-deps-install) -* [macOS 12](macos12-deps-install) +* [macOS](macos-deps-install) * [Ubuntu 20.04](ubuntu-focal-deps-install) * [Ubuntu 22.04](ubuntu-jammy-deps-install) @@ -98,7 +98,7 @@ the relevant paths on your machine. :hidden: centos-stream-9-deps-install -macos12-deps-install +macos-deps-install ubuntu-focal-deps-install ubuntu-jammy-deps-install regex-utils diff --git a/docs/src/dev-guide/components-core/macos12-deps-install.md b/docs/src/dev-guide/components-core/macos-deps-install.md similarity index 85% rename from docs/src/dev-guide/components-core/macos12-deps-install.md rename to docs/src/dev-guide/components-core/macos-deps-install.md index f1b8a704b..58483a437 100644 --- a/docs/src/dev-guide/components-core/macos12-deps-install.md +++ b/docs/src/dev-guide/components-core/macos-deps-install.md @@ -1,4 +1,4 @@ -# macOS 12 setup +# macOS setup To install the dependencies required to build clp-core, follow the steps below. These same steps are used by our [GitHub workflow][gh-workflow]. @@ -13,7 +13,7 @@ will not install any dependencies you don't expect. To install all dependencies, run: ```shell -components/core/tools/scripts/lib_install/macos-12/install-all.sh +components/core/tools/scripts/lib_install/macos/install-all.sh ``` [gh-workflow]: https://github.com/y-scope/clp/blob/main/.github/workflows/clp-core-build-macos.yaml From 9f6a6ced4da504f6ba3c131efa26fd5b30c6f533 Mon Sep 17 00:00:00 2001 From: "Xiaochong(Eddy) Wei" <40865608+anlowee@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:42:20 -0400 Subject: [PATCH 088/114] core: Add support for user-defined HTTP headers in `NetworkReader`. (#568) Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Co-authored-by: Xiaochong Wei --- .../core/src/clp/CurlDownloadHandler.cpp | 62 +++++++++++++++++-- .../core/src/clp/CurlDownloadHandler.hpp | 10 ++- components/core/src/clp/NetworkReader.cpp | 16 ++++- components/core/src/clp/NetworkReader.hpp | 21 ++++++- components/core/tests/test-NetworkReader.cpp | 58 +++++++++++++++++ 5 files changed, 155 insertions(+), 12 deletions(-) diff --git a/components/core/src/clp/CurlDownloadHandler.cpp b/components/core/src/clp/CurlDownloadHandler.cpp index 9a2720083..d1b88758a 100644 --- a/components/core/src/clp/CurlDownloadHandler.cpp +++ b/components/core/src/clp/CurlDownloadHandler.cpp @@ -1,13 +1,22 @@ #include "CurlDownloadHandler.hpp" +#include +#include +#include #include #include #include +#include #include #include +#include +#include #include #include +#include + +#include "ErrorCode.hpp" namespace clp { CurlDownloadHandler::CurlDownloadHandler( @@ -19,7 +28,8 @@ CurlDownloadHandler::CurlDownloadHandler( size_t offset, bool disable_caching, std::chrono::seconds connection_timeout, - std::chrono::seconds overall_timeout + std::chrono::seconds overall_timeout, + std::optional> const& http_header_kv_pairs ) : m_error_msg_buf{std::move(error_msg_buf)} { if (nullptr != m_error_msg_buf) { @@ -48,13 +58,55 @@ CurlDownloadHandler::CurlDownloadHandler( m_easy_handle.set_option(CURLOPT_TIMEOUT, static_cast(overall_timeout.count())); // Set up http headers + constexpr std::string_view cRangeHeaderName{"range"}; + constexpr std::string_view cCacheControlHeaderName{"cache-control"}; + constexpr std::string_view cPragmaHeaderName{"pragma"}; + std::unordered_set const reserved_headers{ + cRangeHeaderName, + cCacheControlHeaderName, + cPragmaHeaderName + }; if (0 != offset) { - std::string const range{"Range: bytes=" + std::to_string(offset) + "-"}; - m_http_headers.append(range); + m_http_headers.append(fmt::format("{}: bytes={}-", cRangeHeaderName, offset)); } if (disable_caching) { - m_http_headers.append("Cache-Control: no-cache"); - m_http_headers.append("Pragma: no-cache"); + m_http_headers.append(fmt::format("{}: no-cache", cCacheControlHeaderName)); + m_http_headers.append(fmt::format("{}: no-cache", cPragmaHeaderName)); + } + if (http_header_kv_pairs.has_value()) { + for (auto const& [key, value] : http_header_kv_pairs.value()) { + // HTTP header field-name (key) is case-insensitive: + // https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + // Therefore, we convert keys to lowercase for comparison with the reserved keys. + // NOTE: We do not check for duplicate keys due to case insensitivity, leaving duplicate + // handling to the server. + auto lower_key{key}; + std::transform( + lower_key.begin(), + lower_key.end(), + lower_key.begin(), + [](unsigned char c) -> char { + // Implicitly cast the input character into `unsigned char` to avoid UB: + // https://en.cppreference.com/w/cpp/string/byte/tolower + return static_cast(std::tolower(c)); + } + ); + if (reserved_headers.contains(lower_key) || value.ends_with("\r\n")) { + throw CurlOperationFailed( + ErrorCode_Failure, + __FILE__, + __LINE__, + CURLE_BAD_FUNCTION_ARGUMENT, + fmt::format( + "`CurlDownloadHandler` failed to construct with the following " + "invalid header: {}:{}", + key, + value + ) + ); + } + m_http_headers.append(fmt::format("{}: {}", key, value)); + } } if (false == m_http_headers.is_empty()) { m_easy_handle.set_option(CURLOPT_HTTPHEADER, m_http_headers.get_raw_list()); diff --git a/components/core/src/clp/CurlDownloadHandler.hpp b/components/core/src/clp/CurlDownloadHandler.hpp index 6421257ba..e7c4b73a8 100644 --- a/components/core/src/clp/CurlDownloadHandler.hpp +++ b/components/core/src/clp/CurlDownloadHandler.hpp @@ -5,7 +5,10 @@ #include #include #include +#include +#include #include +#include #include @@ -53,6 +56,9 @@ class CurlDownloadHandler { * Doc: https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html * @param overall_timeout Maximum time that the transfer may take. Note that this includes * `connection_timeout`. Doc: https://curl.se/libcurl/c/CURLOPT_TIMEOUT.html + * @param http_header_kv_pairs Key-value pairs representing HTTP headers to pass to the server + * in the download request. Doc: https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html + * @throw CurlOperationFailed if an error occurs. */ explicit CurlDownloadHandler( std::shared_ptr error_msg_buf, @@ -63,7 +69,9 @@ class CurlDownloadHandler { size_t offset = 0, bool disable_caching = false, std::chrono::seconds connection_timeout = cDefaultConnectionTimeout, - std::chrono::seconds overall_timeout = cDefaultOverallTimeout + std::chrono::seconds overall_timeout = cDefaultOverallTimeout, + std::optional> const& http_header_kv_pairs + = std::nullopt ); // Disable copy/move constructors/assignment operators diff --git a/components/core/src/clp/NetworkReader.cpp b/components/core/src/clp/NetworkReader.cpp index cdde759c2..086b60681 100644 --- a/components/core/src/clp/NetworkReader.cpp +++ b/components/core/src/clp/NetworkReader.cpp @@ -6,7 +6,10 @@ #include #include #include +#include #include +#include +#include #include @@ -118,7 +121,8 @@ NetworkReader::NetworkReader( std::chrono::seconds overall_timeout, std::chrono::seconds connection_timeout, size_t buffer_pool_size, - size_t buffer_size + size_t buffer_size, + std::optional> http_header_kv_pairs ) : m_src_url{src_url}, m_offset{offset}, @@ -130,7 +134,12 @@ NetworkReader::NetworkReader( for (size_t i = 0; i < m_buffer_pool_size; ++i) { m_buffer_pool.emplace_back(m_buffer_size); } - m_downloader_thread = std::make_unique(*this, offset, disable_caching); + m_downloader_thread = std::make_unique( + *this, + offset, + disable_caching, + std::move(http_header_kv_pairs) + ); m_downloader_thread->start(); } @@ -215,7 +224,8 @@ auto NetworkReader::DownloaderThread::thread_method() -> void { m_offset, m_disable_caching, m_reader.m_connection_timeout, - m_reader.m_overall_timeout + m_reader.m_overall_timeout, + m_http_header_kv_pairs }; auto const ret_code{curl_handler.perform()}; // Enqueue the last filled buffer, if any diff --git a/components/core/src/clp/NetworkReader.hpp b/components/core/src/clp/NetworkReader.hpp index 7c808fd4f..08be975ea 100644 --- a/components/core/src/clp/NetworkReader.hpp +++ b/components/core/src/clp/NetworkReader.hpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -94,6 +96,8 @@ class NetworkReader : public ReaderInterface { * Doc: https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html * @param buffer_pool_size The required number of buffers in the buffer pool. * @param buffer_size The size of each buffer in the buffer pool. + * @param http_header_kv_pairs Key-value pairs representing HTTP headers to pass to the server + * in the download request. Doc: https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html */ explicit NetworkReader( std::string_view src_url, @@ -103,7 +107,9 @@ class NetworkReader : public ReaderInterface { std::chrono::seconds connection_timeout = CurlDownloadHandler::cDefaultConnectionTimeout, size_t buffer_pool_size = cDefaultBufferPoolSize, - size_t buffer_size = cDefaultBufferSize + size_t buffer_size = cDefaultBufferSize, + std::optional> http_header_kv_pairs + = std::nullopt ); // Destructor @@ -242,11 +248,19 @@ class NetworkReader : public ReaderInterface { * @param reader * @param offset Index of the byte at which to start the download. * @param disable_caching Whether to disable caching. + * @param http_header_kv_pairs Key-value pairs representing HTTP headers to pass to the + * server in the download request. Doc: https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html */ - DownloaderThread(NetworkReader& reader, size_t offset, bool disable_caching) + DownloaderThread( + NetworkReader& reader, + size_t offset, + bool disable_caching, + std::optional> http_header_kv_pairs + ) : m_reader{reader}, m_offset{offset}, - m_disable_caching{disable_caching} {} + m_disable_caching{disable_caching}, + m_http_header_kv_pairs{std::move(http_header_kv_pairs)} {} private: // Methods implementing `clp::Thread` @@ -255,6 +269,7 @@ class NetworkReader : public ReaderInterface { NetworkReader& m_reader; size_t m_offset{0}; bool m_disable_caching{false}; + std::optional> m_http_header_kv_pairs; }; /** diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index cd4b90cc0..f32daef14 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -6,10 +6,13 @@ #include #include #include +#include #include #include #include +#include +#include #include "../src/clp/Array.hpp" #include "../src/clp/CurlDownloadHandler.hpp" @@ -188,3 +191,58 @@ TEST_CASE("network_reader_illegal_offset", "[NetworkReader]") { size_t pos{}; REQUIRE((clp::ErrorCode_Failure == reader.try_get_pos(pos))); } + +TEST_CASE("network_reader_with_valid_http_header_kv_pairs", "[NetworkReader]") { + std::unordered_map valid_http_header_kv_pairs; + // We use httpbin (https://httpbin.org/) to test the user-specified headers. On success, it is + // supposed to respond all the user-specified headers as key-value pairs in JSON form. + constexpr int cNumHttpHeaderKeyValuePairs{10}; + for (size_t i{0}; i < cNumHttpHeaderKeyValuePairs; ++i) { + valid_http_header_kv_pairs.emplace( + fmt::format("Unit-Test-Key{}", i), + fmt::format("Unit-Test-Value{}", i) + ); + } + clp::NetworkReader reader{ + "https://httpbin.org/headers", + 0, + false, + clp::CurlDownloadHandler::cDefaultOverallTimeout, + clp::CurlDownloadHandler::cDefaultConnectionTimeout, + clp::NetworkReader::cDefaultBufferPoolSize, + clp::NetworkReader::cDefaultBufferSize, + valid_http_header_kv_pairs + }; + auto const content = nlohmann::json::parse(get_content(reader)); + auto const& headers{content.at("headers")}; + REQUIRE(assert_curl_error_code(CURLE_OK, reader)); + for (auto const& [key, value] : valid_http_header_kv_pairs) { + REQUIRE((value == headers.at(key).get())); + } +} + +TEST_CASE("network_reader_with_illegal_http_header_kv_pairs", "[NetworkReader]") { + auto illegal_header_kv_pairs = GENERATE( + // The following headers are determined by offset and disable_cache, which should not be + // overridden by user-defined headers. + std::unordered_map{{"Range", "bytes=100-"}}, + std::unordered_map{{"RAnGe", "bytes=100-"}}, + std::unordered_map{{"Cache-Control", "no-cache"}}, + std::unordered_map{{"Pragma", "no-cache"}}, + // The CRLF-terminated headers should be rejected. + std::unordered_map{{"Legal-Name", "CRLF\r\n"}} + ); + clp::NetworkReader reader{ + "https://httpbin.org/headers", + 0, + false, + clp::CurlDownloadHandler::cDefaultOverallTimeout, + clp::CurlDownloadHandler::cDefaultConnectionTimeout, + clp::NetworkReader::cDefaultBufferPoolSize, + clp::NetworkReader::cDefaultBufferSize, + illegal_header_kv_pairs + }; + auto const content = get_content(reader); + REQUIRE(content.empty()); + REQUIRE(assert_curl_error_code(CURLE_BAD_FUNCTION_ARGUMENT, reader)); +} From 6e3645c2ae815e5196a6050cdee3b1c349ba3345 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Wed, 6 Nov 2024 19:28:33 -0500 Subject: [PATCH 089/114] chore: Update to the latest version of yscope-dev-utils. (#574) --- tools/yscope-dev-utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/yscope-dev-utils b/tools/yscope-dev-utils index 2caa3dcfb..ad576e43c 160000 --- a/tools/yscope-dev-utils +++ b/tools/yscope-dev-utils @@ -1 +1 @@ -Subproject commit 2caa3dcfbbccff052d179e643a509d8ad05bc217 +Subproject commit ad576e43c1a43d7a6afde79fc9c3c952b7bf28bd From 5687ff0ec0fcbe9bef3694c0098ddf8ac98c7706 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Wed, 6 Nov 2024 23:42:21 -0500 Subject: [PATCH 090/114] build(core): Upgrade msgpack to v7.0.0. (#575) --- components/core/CMakeLists.txt | 2 +- .../lib_install/centos-stream-9/install-packages-from-source.sh | 2 +- .../lib_install/ubuntu-focal/install-packages-from-source.sh | 2 +- .../lib_install/ubuntu-jammy/install-packages-from-source.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 83e5c7630..e5c9b06c8 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -194,7 +194,7 @@ else() endif() # Find and setup msgpack -find_package(msgpack-cxx 6.0.0 REQUIRED) +find_package(msgpack-cxx 7.0.0 REQUIRED) if(msgpack-cxx_FOUND) message(STATUS "Found msgpack-cxx ${msgpack-cxx_VERSION}") else() diff --git a/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh index e0b6a6c28..f2965f9fd 100755 --- a/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh +++ b/components/core/tools/scripts/lib_install/centos-stream-9/install-packages-from-source.sh @@ -15,4 +15,4 @@ lib_install_scripts_dir="${script_dir}/.." "${lib_install_scripts_dir}/fmtlib.sh" 8.0.1 "${lib_install_scripts_dir}/spdlog.sh" 1.9.2 "${lib_install_scripts_dir}/mongocxx.sh" 3.10.2 -"${lib_install_scripts_dir}/msgpack.sh" 6.0.0 +"${lib_install_scripts_dir}/msgpack.sh" 7.0.0 diff --git a/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh index d785b536f..1e21314cc 100755 --- a/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh +++ b/components/core/tools/scripts/lib_install/ubuntu-focal/install-packages-from-source.sh @@ -16,6 +16,6 @@ lib_install_scripts_dir=$script_dir/.. "$lib_install_scripts_dir"/libarchive.sh 3.5.1 "$lib_install_scripts_dir"/lz4.sh 1.8.2 "$lib_install_scripts_dir"/mongocxx.sh 3.10.2 -"$lib_install_scripts_dir"/msgpack.sh 6.0.0 +"$lib_install_scripts_dir"/msgpack.sh 7.0.0 "$lib_install_scripts_dir"/spdlog.sh 1.9.2 "$lib_install_scripts_dir"/zstandard.sh 1.4.9 diff --git a/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh b/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh index 8049dbebf..7799c9ba5 100755 --- a/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh +++ b/components/core/tools/scripts/lib_install/ubuntu-jammy/install-packages-from-source.sh @@ -13,6 +13,6 @@ lib_install_scripts_dir=$script_dir/.. "$lib_install_scripts_dir"/libarchive.sh 3.5.1 "$lib_install_scripts_dir"/lz4.sh 1.8.2 "$lib_install_scripts_dir"/mongocxx.sh 3.10.2 -"$lib_install_scripts_dir"/msgpack.sh 6.0.0 +"$lib_install_scripts_dir"/msgpack.sh 7.0.0 "$lib_install_scripts_dir"/spdlog.sh 1.9.2 "$lib_install_scripts_dir"/zstandard.sh 1.4.9 From 426cc3d657c67e9fdffe6681e670cba617f4154f Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 7 Nov 2024 00:16:20 -0500 Subject: [PATCH 091/114] feat(ffi): Update IR stream protocol version handling in preparation for releasing the kv-pair IR stream format: (#573) - Bump the IR stream protocol version to 0.1.0 for the kv-pair IR stream format. - Treat the previous IR stream format's versions as backwards compatible. - Differentiate between backwards-compatible and supported versions during validation. Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../src/clp/ffi/ir_stream/Deserializer.hpp | 6 +- .../core/src/clp/ffi/ir_stream/Serializer.cpp | 2 +- .../clp/ffi/ir_stream/decoding_methods.cpp | 45 ++++++----- .../clp/ffi/ir_stream/decoding_methods.hpp | 31 ++++---- .../clp/ffi/ir_stream/encoding_methods.cpp | 3 +- .../clp/ffi/ir_stream/protocol_constants.hpp | 7 +- .../core/src/clp/ir/LogEventDeserializer.cpp | 2 +- .../core/tests/test-ir_encoding_methods.cpp | 76 +++++++++++++++---- 8 files changed, 118 insertions(+), 54 deletions(-) diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp index c1fc13c85..45cca8f26 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp @@ -154,10 +154,8 @@ auto Deserializer::create(ReaderInterface& reader, IrUnitHandler return std::errc::protocol_error; } auto const version = version_iter->get_ref(); - // TODO: Just before the KV-pair IR format is formally released, we should replace this - // hard-coded version check with `ffi::ir_stream::validate_protocol_version`. - if (std::string_view{static_cast(cProtocol::Metadata::BetaVersionValue)} - != version) + if (ffi::ir_stream::IRProtocolErrorCode::Supported + != ffi::ir_stream::validate_protocol_version(version)) { return std::errc::protocol_not_supported; } diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.cpp b/components/core/src/clp/ffi/ir_stream/Serializer.cpp index 01215eb9d..b29cf0492 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.cpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.cpp @@ -253,7 +253,7 @@ auto Serializer::create( ir_buf.insert(ir_buf.cend(), cMagicNumber.begin(), cMagicNumber.end()); nlohmann::json metadata; - metadata.emplace(cProtocol::Metadata::VersionKey, cProtocol::Metadata::BetaVersionValue); + metadata.emplace(cProtocol::Metadata::VersionKey, cProtocol::Metadata::VersionValue); metadata.emplace(cProtocol::Metadata::VariablesSchemaIdKey, cVariablesSchemaVersion); metadata.emplace( cProtocol::Metadata::VariableEncodingMethodsIdKey, diff --git a/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp b/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp index 9388470e4..f61efc1df 100644 --- a/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp @@ -1,6 +1,10 @@ #include "decoding_methods.hpp" +#include +#include #include +#include +#include #include "../../ir/types.hpp" #include "byteswap.hpp" @@ -468,13 +472,23 @@ IRErrorCode deserialize_preamble( return IRErrorCode_Success; } -IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version) { - if ("v0.0.0" == protocol_version) { - // This version is hardcoded to support the oldest IR protocol version. When this version is - // no longer supported, this branch should be removed. - return IRProtocolErrorCode_Supported; +auto validate_protocol_version(std::string_view protocol_version) -> IRProtocolErrorCode { + // These versions are hardcoded to support the IR protocol version that predates the key-value + // pair IR format. + constexpr std::array cBackwardCompatibleVersions{ + "v0.0.0", + "0.0.1", + cProtocol::Metadata::LatestBackwardCompatibleVersion + }; + if (cBackwardCompatibleVersions.cend() + != std::ranges::find(cBackwardCompatibleVersions, protocol_version)) + { + return IRProtocolErrorCode::BackwardCompatible; } - std::regex const protocol_version_regex{cProtocol::Metadata::VersionRegex}; + + std::regex const protocol_version_regex{ + static_cast(cProtocol::Metadata::VersionRegex) + }; if (false == std::regex_match( protocol_version.begin(), @@ -482,19 +496,16 @@ IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version) protocol_version_regex )) { - return IRProtocolErrorCode_Invalid; + return IRProtocolErrorCode::Invalid; } - std::string_view current_build_protocol_version{cProtocol::Metadata::VersionValue}; - auto get_major_version{[](std::string_view version) { - return version.substr(0, version.find('.')); - }}; - if (current_build_protocol_version < protocol_version) { - return IRProtocolErrorCode_Too_New; - } - if (get_major_version(current_build_protocol_version) > get_major_version(protocol_version)) { - return IRProtocolErrorCode_Too_Old; + + // TODO: Currently, we hardcode the supported versions. This should be removed once we + // implement a proper version parser. + if (cProtocol::Metadata::VersionValue == protocol_version) { + return IRProtocolErrorCode::Supported; } - return IRProtocolErrorCode_Supported; + + return IRProtocolErrorCode::Unsupported; } IRErrorCode deserialize_utc_offset_change(ReaderInterface& reader, UtcOffset& utc_offset) { diff --git a/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp b/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp index fb6f6a3c0..a9bc5c4fd 100644 --- a/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp +++ b/components/core/src/clp/ffi/ir_stream/decoding_methods.hpp @@ -1,6 +1,7 @@ #ifndef CLP_FFI_IR_STREAM_DECODING_METHODS_HPP #define CLP_FFI_IR_STREAM_DECODING_METHODS_HPP +#include #include #include @@ -20,12 +21,12 @@ typedef enum { IRErrorCode_Incomplete_IR, } IRErrorCode; -typedef enum { - IRProtocolErrorCode_Supported, - IRProtocolErrorCode_Too_Old, - IRProtocolErrorCode_Too_New, - IRProtocolErrorCode_Invalid, -} IRProtocolErrorCode; +enum class IRProtocolErrorCode : uint8_t { + Supported, + BackwardCompatible, + Unsupported, + Invalid, +}; class DecodingException : public TraceableException { public: @@ -193,15 +194,19 @@ IRErrorCode deserialize_utc_offset_change(ReaderInterface& reader, UtcOffset& ut /** * Validates whether the given protocol version can be supported by the current build. * @param protocol_version - * @return IRProtocolErrorCode_Supported if the protocol version is supported. - * @return IRProtocolErrorCode_Too_Old if the protocol version is no longer supported by this - * build's protocol version. - * @return IRProtocolErrorCode_Too_New if the protocol version is newer than this build's protocol - * version. - * @return IRProtocolErrorCode_Invalid if the protocol version does not follow the SemVer + * @return IRProtocolErrorCode::Supported if the protocol version is supported by the key-value + * pair IR stream serializer and deserializer. TODO: Update this once we integrate backwards + * compatibility into the deserializer. + * @return IRProtocolErrorCode::BackwardCompatible if the protocol version is supported by the + * serializer and deserializer for the IR stream format that predates the key-value pair IR stream + * format. TODO: Update this once we integrate backwards compatibility into the key-value pair IR + * stream format. + * @return IRProtocolErrorCode::Unsupported if the protocol version is not supported by this build. + * @return IRProtocolErrorCode::Invalid if the protocol version does not follow the SemVer * specification. */ -IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version); +[[nodiscard]] auto validate_protocol_version(std::string_view protocol_version +) -> IRProtocolErrorCode; namespace eight_byte_encoding { /** diff --git a/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp b/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp index 128d659c1..7c036de0d 100644 --- a/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp +++ b/components/core/src/clp/ffi/ir_stream/encoding_methods.cpp @@ -98,7 +98,8 @@ static void add_base_metadata_fields( string_view time_zone_id, nlohmann::json& metadata ) { - metadata[cProtocol::Metadata::VersionKey] = cProtocol::Metadata::VersionValue; + metadata[cProtocol::Metadata::VersionKey] + = cProtocol::Metadata::LatestBackwardCompatibleVersion; metadata[cProtocol::Metadata::VariablesSchemaIdKey] = cVariablesSchemaVersion; metadata[cProtocol::Metadata::VariableEncodingMethodsIdKey] = cVariableEncodingMethodsVersion; metadata[cProtocol::Metadata::TimestampPatternKey] = timestamp_pattern; diff --git a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp index c6fd92397..d89b99cf5 100644 --- a/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp +++ b/components/core/src/clp/ffi/ir_stream/protocol_constants.hpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace clp::ffi::ir_stream::cProtocol { @@ -12,8 +13,10 @@ constexpr int8_t LengthUByte = 0x11; constexpr int8_t LengthUShort = 0x12; constexpr char VersionKey[] = "VERSION"; -constexpr char VersionValue[] = "0.0.2"; -constexpr char BetaVersionValue[] = "0.1.0-beta.1"; +constexpr std::string_view VersionValue{"0.1.0"}; + +// This is used for the IR stream format that predates the key-value pair IR format. +constexpr std::string_view LatestBackwardCompatibleVersion{"0.0.2"}; // The following regex can be used to validate a Semantic Versioning string. The source of the // regex can be found here: https://semver.org/ diff --git a/components/core/src/clp/ir/LogEventDeserializer.cpp b/components/core/src/clp/ir/LogEventDeserializer.cpp index 6106568dd..8a1064a78 100644 --- a/components/core/src/clp/ir/LogEventDeserializer.cpp +++ b/components/core/src/clp/ir/LogEventDeserializer.cpp @@ -42,7 +42,7 @@ auto LogEventDeserializer::create(ReaderInterface& reader return std::errc::protocol_error; } auto metadata_version = version_iter->get_ref(); - if (ffi::ir_stream::IRProtocolErrorCode_Supported + if (ffi::ir_stream::IRProtocolErrorCode::BackwardCompatible != ffi::ir_stream::validate_protocol_version(metadata_version)) { return std::errc::protocol_not_supported; diff --git a/components/core/tests/test-ir_encoding_methods.cpp b/components/core/tests/test-ir_encoding_methods.cpp index b4f0257c1..1ee1e3542 100644 --- a/components/core/tests/test-ir_encoding_methods.cpp +++ b/components/core/tests/test-ir_encoding_methods.cpp @@ -630,8 +630,8 @@ TEMPLATE_TEST_CASE( auto metadata_json = nlohmann::json::parse(json_metadata); std::string const version = metadata_json.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey); - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Supported == validate_protocol_version(version) - ); + REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode::BackwardCompatible + == validate_protocol_version(version)); REQUIRE(clp::ffi::ir_stream::cProtocol::Metadata::EncodingJson == metadata_type); set_timestamp_info(metadata_json, ts_info); REQUIRE(timestamp_pattern_syntax == ts_info.timestamp_pattern_syntax); @@ -844,17 +844,63 @@ TEST_CASE("decode_next_message_four_byte_timestamp_delta", "[ffi][deserialize_lo } TEST_CASE("validate_protocol_version", "[ffi][validate_version_protocol]") { - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Invalid == validate_protocol_version("v0.0.1") + REQUIRE( + (clp::ffi::ir_stream::IRProtocolErrorCode::Supported + == validate_protocol_version(clp::ffi::ir_stream::cProtocol::Metadata::VersionValue)) + ); + REQUIRE( + (clp::ffi::ir_stream::IRProtocolErrorCode::BackwardCompatible + == validate_protocol_version( + clp::ffi::ir_stream::cProtocol::Metadata::LatestBackwardCompatibleVersion + )) ); - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Invalid == validate_protocol_version("0.1")); - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Invalid == validate_protocol_version("0.a.1")); - - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Too_New - == validate_protocol_version("1000.0.0")); - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Supported - == validate_protocol_version(clp::ffi::ir_stream::cProtocol::Metadata::VersionValue)); - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Supported - == validate_protocol_version("v0.0.0")); + + SECTION("Test invalid versions") { + auto const invalid_versions{GENERATE( + std::string_view{"v0.0.1"}, + std::string_view{"0.1"}, + std::string_view{"0.1.a"}, + std::string_view{"0.a.1"} + )}; + REQUIRE( + (clp::ffi::ir_stream::IRProtocolErrorCode::Invalid + == validate_protocol_version(invalid_versions)) + ); + } + + SECTION("Test backward compatible versions") { + auto const backward_compatible_versions{GENERATE( + std::string_view{"v0.0.0"}, + std::string_view{"0.0.1"}, + std::string_view{"0.0.2"} + )}; + REQUIRE( + (clp::ffi::ir_stream::IRProtocolErrorCode::BackwardCompatible + == validate_protocol_version(backward_compatible_versions)) + ); + } + + SECTION("Test versions that're too old") { + auto const old_versions{GENERATE( + std::string_view{"0.0.3"}, + std::string_view{"0.0.3-beta.1"}, + std::string_view{"0.1.0-beta"} + )}; + REQUIRE( + (clp::ffi::ir_stream::IRProtocolErrorCode::Unsupported + == validate_protocol_version(old_versions)) + ); + } + + SECTION("Test versions that're too new") { + auto const new_versions{ + GENERATE(std::string_view{"10000.0.0"}, std::string_view{"0.10000.0"}) + }; + REQUIRE( + (clp::ffi::ir_stream::IRProtocolErrorCode::Unsupported + == validate_protocol_version(new_versions)) + ); + } } TEMPLATE_TEST_CASE( @@ -905,8 +951,8 @@ TEMPLATE_TEST_CASE( string_view json_metadata{json_metadata_ptr, metadata_size}; auto metadata_json = nlohmann::json::parse(json_metadata); string const version = metadata_json.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey); - REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode_Supported == validate_protocol_version(version) - ); + REQUIRE(clp::ffi::ir_stream::IRProtocolErrorCode::BackwardCompatible + == validate_protocol_version(version)); REQUIRE(clp::ffi::ir_stream::cProtocol::Metadata::EncodingJson == metadata_type); set_timestamp_info(metadata_json, ts_info); REQUIRE(timestamp_pattern_syntax == ts_info.timestamp_pattern_syntax); @@ -1055,7 +1101,7 @@ TEMPLATE_TEST_CASE( nlohmann::json expected_metadata; expected_metadata.emplace( clp::ffi::ir_stream::cProtocol::Metadata::VersionKey, - clp::ffi::ir_stream::cProtocol::Metadata::BetaVersionValue + clp::ffi::ir_stream::cProtocol::Metadata::VersionValue ); expected_metadata.emplace( clp::ffi::ir_stream::cProtocol::Metadata::VariablesSchemaIdKey, From 9154949fb24a9416e1392e0681c6961dae7fffb7 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Thu, 7 Nov 2024 22:04:31 -0500 Subject: [PATCH 092/114] fix(taskfiles): Trim trailing slash from URL prefix in `download-and-extract-tar` (fixes #577). (#578) --- Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index 5912bd579..02786f9af 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -348,7 +348,7 @@ tasks: - "mkdir -p '{{.OUTPUT_TMP_DIR}}'" - >- curl --fail --location --show-error - "{{.URL_PREFIX}}/{{.TAR_NAME}}" + "{{trimSuffix "/" .URL_PREFIX}}/{{.TAR_NAME}}" --output "{{.TAR_PATH}}" - "tar xf '{{.TAR_PATH}}' --directory '{{.OUTPUT_TMP_DIR}}'" - "mv '{{.EXTRACTED_DIR}}' '{{.OUTPUT_DIR}}'" From 31de766ecc3175b1fa472d12881587e3673294de Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 8 Nov 2024 03:58:28 -0500 Subject: [PATCH 093/114] fix(ffi): Correct `clp::ffi::ir_stream::Deserializer::deserialize_next_ir_unit`'s return value when failing to read the next IR unit's type tag. (#579) --- components/core/src/clp/ffi/ir_stream/Deserializer.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp index 45cca8f26..3418a39ae 100644 --- a/components/core/src/clp/ffi/ir_stream/Deserializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Deserializer.hpp @@ -14,7 +14,6 @@ #include "../../ReaderInterface.hpp" #include "../../time_types.hpp" -#include "../KeyValuePairLogEvent.hpp" #include "../SchemaTree.hpp" #include "decoding_methods.hpp" #include "ir_unit_deserialization_methods.hpp" @@ -66,8 +65,8 @@ class Deserializer { /** * Deserializes the stream from the given reader up to and including the next log event IR unit. * @param reader - * @return std::errc::no_message_available if no tag bytes can be read to determine the next IR - * unit type. + * @return Forwards `deserialize_tag`s return values if no tag bytes can be read to determine + * the next IR unit type. * @return std::errc::protocol_not_supported if the IR unit type is not supported. * @return std::errc::operation_not_permitted if the deserializer already reached the end of * stream by deserializing an end-of-stream IR unit in the previous calls. @@ -172,8 +171,8 @@ auto Deserializer::deserialize_next_ir_unit(ReaderInterface& read } encoded_tag_t tag{}; - if (IRErrorCode::IRErrorCode_Success != deserialize_tag(reader, tag)) { - return std::errc::no_message_available; + if (auto const err{deserialize_tag(reader, tag)}; IRErrorCode::IRErrorCode_Success != err) { + return ir_error_code_to_errc(err); } auto const optional_ir_unit_type{get_ir_unit_type_from_tag(tag)}; From 7ea39416b713c0214d2f045f9af9d1822c61cdfa Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 8 Nov 2024 12:21:09 -0500 Subject: [PATCH 094/114] fix(taskfiles): Update `yscope-log-viewer` sources in `log-viewer-webui-clients` sources list (fixes #576). (#580) --- Taskfile.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 02786f9af..5c20ef460 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -228,10 +228,10 @@ tasks: - "client/src/**/*.css" - "client/src/**/*.jsx" - "client/src/webpack.config.js" - - "yscope-log-viewer/.babelrc" - - "yscope-log-viewer/customized-packages/**/*" - "yscope-log-viewer/package.json" + - "yscope-log-viewer/public/**/*" - "yscope-log-viewer/src/**/*" + - "yscope-log-viewer/tsconfig.json" - "yscope-log-viewer/webpack.common.js" - "yscope-log-viewer/webpack.prod.js" dir: "components/log-viewer-webui" From 4446eb56e315c30f8ccc7a779f0b5a8cc3544575 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sat, 9 Nov 2024 23:00:11 -0500 Subject: [PATCH 095/114] fix(cmake): Add Homebrew path detection for `mariadb-connector-c` to fix macOS build failure. (#582) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../cmake/Modules/FindMariaDBClient.cmake | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/components/core/cmake/Modules/FindMariaDBClient.cmake b/components/core/cmake/Modules/FindMariaDBClient.cmake index 543f31a6b..5801be2e6 100644 --- a/components/core/cmake/Modules/FindMariaDBClient.cmake +++ b/components/core/cmake/Modules/FindMariaDBClient.cmake @@ -20,6 +20,28 @@ include(cmake/Modules/FindLibraryDependencies.cmake) find_package(PkgConfig) pkg_check_modules(mariadbclient_PKGCONF QUIET "lib${mariadbclient_LIBNAME}") +if(NOT mariadbclient_PKGCONF_FOUND AND APPLE) + execute_process( + COMMAND brew --prefix mariadb-connector-c + RESULT_VARIABLE mariadbclient_BREW_RESULT + OUTPUT_VARIABLE mariadbclient_MACOS_PREFIX + ) + if(NOT mariadbclient_BREW_RESULT EQUAL 0) + message( + FATAL_ERROR + "pkg-config cannot find ${mariadbclient_LIBNAME} and mariadb-connector-c isn't" + " installed via Homebrew" + ) + endif() + string(STRIP "${mariadbclient_MACOS_PREFIX}" mariadbclient_MACOS_PREFIX) + list(PREPEND CMAKE_PREFIX_PATH ${mariadbclient_MACOS_PREFIX}) + pkg_check_modules(mariadbclient_PKGCONF QUIET "lib${mariadbclient_LIBNAME}") +endif() + +if(NOT mariadbclient_PKGCONF_FOUND) + message(FATAL_ERROR "pkg-config cannot find ${mariadbclient_LIBNAME}") +endif() + # Set include directory find_path(MariaDBClient_INCLUDE_DIR mysql.h HINTS ${mariadbclient_PKGCONF_INCLUDEDIR} From 5559c1ec56e4a16ca623110d67f4a9d26cdb5586 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sat, 9 Nov 2024 23:41:26 -0500 Subject: [PATCH 096/114] refactor(ffi): Make `get_schema_subtree_bitmap` a public method of `KeyValuePairLogEvent`. (#581) --- .../core/src/clp/ffi/KeyValuePairLogEvent.cpp | 80 +++++++------------ .../core/src/clp/ffi/KeyValuePairLogEvent.hpp | 12 +++ 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp index 2a84795f7..a8a8cf617 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.cpp @@ -153,20 +153,6 @@ node_type_matches_value_type(SchemaTree::Node::Type type, Value const& value) -> KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs ) -> bool; -/** - * @param node_id_value_pairs - * @param schema_tree - * @return A result containing a bitmap where every bit corresponds to the ID of a node in the - * schema tree, and the set bits correspond to the nodes in the subtree defined by all paths from - * the root node to the nodes in `node_id_value_pairs`; or an error code indicating a failure: - * - std::errc::result_out_of_range if a node ID in `node_id_value_pairs` doesn't exist in the - * schema tree. - */ -[[nodiscard]] auto get_schema_subtree_bitmap( - KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs, - SchemaTree const& schema_tree -) -> OUTCOME_V2_NAMESPACE::std_result>; - /** * Inserts the given key-value pair into the JSON object (map). * @param node The schema tree node of the key to insert. @@ -283,38 +269,6 @@ auto is_leaf_node( return true; } -auto get_schema_subtree_bitmap( - KeyValuePairLogEvent::NodeIdValuePairs const& node_id_value_pairs, - SchemaTree const& schema_tree -) -> OUTCOME_V2_NAMESPACE::std_result> { - auto schema_subtree_bitmap{vector(schema_tree.get_size(), false)}; - for (auto const& [node_id, val] : node_id_value_pairs) { - if (node_id >= schema_subtree_bitmap.size()) { - return std::errc::result_out_of_range; - } - schema_subtree_bitmap[node_id] = true; - - // Iteratively mark the parents as true - auto optional_parent_id{schema_tree.get_node(node_id).get_parent_id()}; - while (true) { - // Ideally, we'd use this if statement as the loop condition, but clang-tidy will - // complain about an unchecked `optional` access. - if (false == optional_parent_id.has_value()) { - // Reached the root - break; - } - auto const parent_id{optional_parent_id.value()}; - if (schema_subtree_bitmap[parent_id]) { - // Parent already set by other child - break; - } - schema_subtree_bitmap[parent_id] = true; - optional_parent_id = schema_tree.get_node(parent_id).get_parent_id(); - } - } - return schema_subtree_bitmap; -} - auto insert_kv_pair_into_json_obj( SchemaTree::Node const& node, std::optional const& optional_val, @@ -393,6 +347,36 @@ auto KeyValuePairLogEvent::create( return KeyValuePairLogEvent{std::move(schema_tree), std::move(node_id_value_pairs), utc_offset}; } +auto KeyValuePairLogEvent::get_schema_subtree_bitmap( +) const -> OUTCOME_V2_NAMESPACE::std_result> { + auto schema_subtree_bitmap{vector(m_schema_tree->get_size(), false)}; + for (auto const& [node_id, val] : m_node_id_value_pairs) { + if (node_id >= schema_subtree_bitmap.size()) { + return std::errc::result_out_of_range; + } + schema_subtree_bitmap[node_id] = true; + + // Iteratively mark the parents as true + auto optional_parent_id{m_schema_tree->get_node(node_id).get_parent_id()}; + while (true) { + // Ideally, we'd use this if statement as the loop condition, but clang-tidy will + // complain about an unchecked `optional` access. + if (false == optional_parent_id.has_value()) { + // Reached the root + break; + } + auto const parent_id{optional_parent_id.value()}; + if (schema_subtree_bitmap[parent_id]) { + // Parent already set by other child + break; + } + schema_subtree_bitmap[parent_id] = true; + optional_parent_id = m_schema_tree->get_node(parent_id).get_parent_id(); + } + } + return schema_subtree_bitmap; +} + auto KeyValuePairLogEvent::serialize_to_json( ) const -> OUTCOME_V2_NAMESPACE::std_result { if (m_node_id_value_pairs.empty()) { @@ -409,9 +393,7 @@ auto KeyValuePairLogEvent::serialize_to_json( // vector grows). std::stack dfs_stack; - auto const schema_subtree_bitmap_ret{ - get_schema_subtree_bitmap(m_node_id_value_pairs, *m_schema_tree) - }; + auto const schema_subtree_bitmap_ret{get_schema_subtree_bitmap()}; if (schema_subtree_bitmap_ret.has_error()) { return schema_subtree_bitmap_ret.error(); } diff --git a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp index 04fd31c9e..f6334d378 100644 --- a/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp +++ b/components/core/src/clp/ffi/KeyValuePairLogEvent.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,17 @@ class KeyValuePairLogEvent { [[nodiscard]] auto get_utc_offset() const -> UtcOffset { return m_utc_offset; } + /** + * @return A result containing a bitmap where every bit corresponds to the ID of a node in the + * schema tree, and the set bits correspond to the nodes in the subtree defined by all paths + * from the root node to the nodes in `node_id_value_pairs`; or an error code indicating a + * failure: + * - std::errc::result_out_of_range if a node ID in `node_id_value_pairs` doesn't exist in the + * schema tree. + */ + [[nodiscard]] auto get_schema_subtree_bitmap( + ) const -> OUTCOME_V2_NAMESPACE::std_result>; + /** * Serializes the log event into a `nlohmann::json` object. * @return A result containing the serialized JSON object or an error code indicating the From 8b3fd63fdcbc5eb3628673f8ff79f9399d244d29 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:38:33 -0500 Subject: [PATCH 097/114] ci: Schedule GitHub workflows to daily run to detect failures due to upgraded dependencies or environments. (#583) --- .github/workflows/clp-core-build-macos.yaml | 3 +++ .github/workflows/clp-core-build.yaml | 3 +++ .github/workflows/clp-docs.yaml | 3 +++ .github/workflows/clp-execution-image-build.yaml | 3 +++ .github/workflows/clp-lint.yaml | 2 +- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clp-core-build-macos.yaml b/.github/workflows/clp-core-build-macos.yaml index 85d04d9c7..8196e75d8 100644 --- a/.github/workflows/clp-core-build-macos.yaml +++ b/.github/workflows/clp-core-build-macos.yaml @@ -27,6 +27,9 @@ on: - "deps-tasks.yml" - "Taskfile.yml" - "tools/scripts/deps-download/**" + schedule: + # Run daily at 00:15 UTC (the 15 is to avoid periods of high load) + - cron: "15 0 * * *" workflow_dispatch: concurrency: diff --git a/.github/workflows/clp-core-build.yaml b/.github/workflows/clp-core-build.yaml index 9046f15da..20b305f8d 100644 --- a/.github/workflows/clp-core-build.yaml +++ b/.github/workflows/clp-core-build.yaml @@ -23,6 +23,9 @@ on: - "Taskfile.yml" - "tools/scripts/deps-download/**" - "!components/core/tools/scripts/lib_install/macos/**" + schedule: + # Run daily at 00:15 UTC (the 15 is to avoid periods of high load) + - cron: "15 0 * * *" workflow_dispatch: env: diff --git a/.github/workflows/clp-docs.yaml b/.github/workflows/clp-docs.yaml index 2f0a68e77..38e4cb172 100644 --- a/.github/workflows/clp-docs.yaml +++ b/.github/workflows/clp-docs.yaml @@ -3,6 +3,9 @@ name: "clp-docs" on: pull_request: push: + schedule: + # Run daily at 00:15 UTC (the 15 is to avoid periods of high load) + - cron: "15 0 * * *" workflow_dispatch: concurrency: diff --git a/.github/workflows/clp-execution-image-build.yaml b/.github/workflows/clp-execution-image-build.yaml index d0bc5b017..058e23d5f 100644 --- a/.github/workflows/clp-execution-image-build.yaml +++ b/.github/workflows/clp-execution-image-build.yaml @@ -11,6 +11,9 @@ on: - ".github/actions/clp-execution-image-build/action.yaml" - ".github/workflows/clp-execution-image-build.yaml" - "tools/docker-images/**/*" + schedule: + # Run daily at 00:15 UTC (the 15 is to avoid periods of high load) + - cron: "15 0 * * *" workflow_dispatch: concurrency: diff --git a/.github/workflows/clp-lint.yaml b/.github/workflows/clp-lint.yaml index 75f74fe4a..bbe485c5d 100644 --- a/.github/workflows/clp-lint.yaml +++ b/.github/workflows/clp-lint.yaml @@ -4,7 +4,7 @@ on: pull_request: push: schedule: - # Run at midnight UTC every day with 15 minutes delay added to avoid high load periods + # Run daily at 00:15 UTC (the 15 is to avoid periods of high load) - cron: "15 0 * * *" workflow_dispatch: From f3b1cf61a28fec4e21e8dd2e8b5f6095ea689fc8 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:34:23 -0500 Subject: [PATCH 098/114] docs: Update the required version of task. (#567) --- docs/README.md | 3 ++- docs/src/dev-guide/building-package.md | 2 +- docs/src/dev-guide/components-core/index.md | 2 +- docs/src/dev-guide/contributing-linting.md | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index 722bd625c..8f3d7207c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,7 +13,7 @@ this project: the size of repo as we add and update images. * [Node.js] >= 16 to be able to [view the output](#viewing-the-output) * Python 3.10 or later -* [Task] >= 3.35 +* [Task] >= 3.38.0 * We constrain the version because, in lower versions, the Taskfile syntax we use has bugs. ## Build Commands @@ -44,3 +44,4 @@ the address it binds to (usually http://localhost:8080). [git-lfs]: https://git-lfs.com [http-server]: https://www.npmjs.com/package/http-server [Node.js]: https://nodejs.org/en/download/current +[Task]: https://taskfile.dev/ diff --git a/docs/src/dev-guide/building-package.md b/docs/src/dev-guide/building-package.md index c0778b1c4..6d47185f4 100644 --- a/docs/src/dev-guide/building-package.md +++ b/docs/src/dev-guide/building-package.md @@ -13,7 +13,7 @@ prebuilt version instead, check out the [releases](https://github.com/y-scope/cl * Python 3.8 or newer * python3-dev * python3-venv -* [Task](https://taskfile.dev/) +* [Task](https://taskfile.dev/) >= 3.38.0 ## Setup diff --git a/docs/src/dev-guide/components-core/index.md b/docs/src/dev-guide/components-core/index.md index 1406f1bd2..1af0fb13e 100644 --- a/docs/src/dev-guide/components-core/index.md +++ b/docs/src/dev-guide/components-core/index.md @@ -7,7 +7,7 @@ CLP core is the low-level component that performs compression, decompression, an * We have built and tested CLP on the OSes listed [below](#native-environment). * If you have trouble building for another OS, file an issue, and we may be able to help. * A compiler that supports C++20 and std::span (e.g., gcc-10) -* [Task](https://taskfile.dev/) +* [Task](https://taskfile.dev/) >= 3.38.0 To build, we require some source dependencies, packages from package managers, and libraries built from source. diff --git a/docs/src/dev-guide/contributing-linting.md b/docs/src/dev-guide/contributing-linting.md index 599935157..fb246d045 100644 --- a/docs/src/dev-guide/contributing-linting.md +++ b/docs/src/dev-guide/contributing-linting.md @@ -15,7 +15,7 @@ To run the linting tools, besides commonly installed tools like `tar`, you'll ne * `md5sum` * Python 3.8 or newer * python3-venv -* [Task] +* [Task] >= 3.38.0 ## Running the linters From 9a8bb5937970e163448a8e08239d5735a5facad2 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:09:10 -0500 Subject: [PATCH 099/114] docs(ffi): Update `ffi::ir_stream::Serializer`'s doc string to remove "work-in-progress". (#586) --- components/core/src/clp/ffi/ir_stream/Serializer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/core/src/clp/ffi/ir_stream/Serializer.hpp b/components/core/src/clp/ffi/ir_stream/Serializer.hpp index 292b360a3..14077ffba 100644 --- a/components/core/src/clp/ffi/ir_stream/Serializer.hpp +++ b/components/core/src/clp/ffi/ir_stream/Serializer.hpp @@ -14,7 +14,7 @@ namespace clp::ffi::ir_stream { /** - * A work-in-progress class for serializing log events into the kv-pair IR format. + * Class for serializing log events into the kv-pair IR format. * * This class: * - maintains all necessary internal data structures to track serialization state; From 2dfcd8a8eac498858814e08c7d64483daabbd18a Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:56:10 -0500 Subject: [PATCH 100/114] ci: Add GH workflow to validate PR titles follow Conventional Commits. (#587) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE.md | 8 +++++--- .github/workflows/clp-pr-title-checks.yaml | 23 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/clp-pr-title-checks.yaml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 91462f325..74460716f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,9 @@ # Description diff --git a/.github/workflows/clp-pr-title-checks.yaml b/.github/workflows/clp-pr-title-checks.yaml new file mode 100644 index 000000000..428e9f21d --- /dev/null +++ b/.github/workflows/clp-pr-title-checks.yaml @@ -0,0 +1,23 @@ +name: "clp-pr-title-checks" + +on: + pull_request_target: + types: ["edited", "opened", "reopened"] + branches: ["main"] + +concurrency: + group: "${{github.workflow}}-${{github.ref}}" + + # Cancel in-progress jobs for efficiency + cancel-in-progress: true + +jobs: + conventional-commits: + permissions: + # For amannn/action-semantic-pull-request + pull-requests: "read" + runs-on: "ubuntu-latest" + steps: + - uses: "amannn/action-semantic-pull-request@v5" + env: + GITHUB_TOKEN: "${{secrets.GITHUB_TOKEN}}" From 53c4f52b3ae2ef0e990a8d66a7be87fd1e85cfbe Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Wed, 13 Nov 2024 11:09:23 -0500 Subject: [PATCH 101/114] feat: Add support for escaping characters in KQL key names. (#560) --- components/core/src/clp_s/JsonParser.cpp | 7 ++- .../src/clp_s/TimestampDictionaryReader.cpp | 4 +- components/core/src/clp_s/Utils.cpp | 34 ++++++++++---- components/core/src/clp_s/Utils.hpp | 4 +- components/core/src/clp_s/clp-s.cpp | 5 ++- components/core/src/clp_s/search/kql/Kql.g4 | 2 +- components/core/src/clp_s/search/kql/kql.cpp | 11 ++++- components/core/tests/test-kql.cpp | 45 +++++++++++++++++++ 8 files changed, 95 insertions(+), 17 deletions(-) diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index 7d4af1469..5336c367a 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -21,7 +21,12 @@ JsonParser::JsonParser(JsonParserOption const& option) } if (false == m_timestamp_key.empty()) { - clp_s::StringUtils::tokenize_column_descriptor(m_timestamp_key, m_timestamp_column); + if (false + == clp_s::StringUtils::tokenize_column_descriptor(m_timestamp_key, m_timestamp_column)) + { + SPDLOG_ERROR("Can not parse invalid timestamp key: \"{}\"", m_timestamp_key); + throw OperationFailed(ErrorCodeBadParam, __FILENAME__, __LINE__); + } } for (auto& file_path : option.file_paths) { diff --git a/components/core/src/clp_s/TimestampDictionaryReader.cpp b/components/core/src/clp_s/TimestampDictionaryReader.cpp index c366e4f59..15685a97e 100644 --- a/components/core/src/clp_s/TimestampDictionaryReader.cpp +++ b/components/core/src/clp_s/TimestampDictionaryReader.cpp @@ -44,7 +44,9 @@ void TimestampDictionaryReader::read_new_entries() { TimestampEntry entry; std::vector tokens; entry.try_read_from_file(m_dictionary_decompressor); - StringUtils::tokenize_column_descriptor(entry.get_key_name(), tokens); + if (false == StringUtils::tokenize_column_descriptor(entry.get_key_name(), tokens)) { + throw OperationFailed(ErrorCodeCorrupt, __FILENAME__, __LINE__); + } m_entries.emplace_back(std::move(entry)); // TODO: Currently, we only allow a single authoritative timestamp column at ingestion time, diff --git a/components/core/src/clp_s/Utils.cpp b/components/core/src/clp_s/Utils.cpp index f429fb4a3..acee48851 100644 --- a/components/core/src/clp_s/Utils.cpp +++ b/components/core/src/clp_s/Utils.cpp @@ -427,18 +427,34 @@ bool StringUtils::convert_string_to_double(std::string const& raw, double& conve return true; } -void StringUtils::tokenize_column_descriptor( +bool StringUtils::tokenize_column_descriptor( std::string const& descriptor, std::vector& tokens ) { - // TODO: handle escaped . correctly - auto start = 0U; - auto end = descriptor.find('.'); - while (end != std::string::npos) { - tokens.push_back(descriptor.substr(start, end - start)); - start = end + 1; - end = descriptor.find('.', start); + // TODO: add support for unicode sequences e.g. \u263A + std::string cur_tok; + for (size_t cur = 0; cur < descriptor.size(); ++cur) { + if ('\\' == descriptor[cur]) { + ++cur; + if (cur >= descriptor.size()) { + return false; + } + } else if ('.' == descriptor[cur]) { + if (cur_tok.empty()) { + return false; + } + tokens.push_back(cur_tok); + cur_tok.clear(); + continue; + } + cur_tok.push_back(descriptor[cur]); } - tokens.push_back(descriptor.substr(start)); + + if (cur_tok.empty()) { + return false; + } + + tokens.push_back(cur_tok); + return true; } } // namespace clp_s diff --git a/components/core/src/clp_s/Utils.hpp b/components/core/src/clp_s/Utils.hpp index de33b7728..d6deb3280 100644 --- a/components/core/src/clp_s/Utils.hpp +++ b/components/core/src/clp_s/Utils.hpp @@ -211,9 +211,9 @@ class StringUtils { * Converts a string column descriptor delimited by '.' into a list of tokens * @param descriptor * @param tokens - * @return the list of tokens pushed into the 'tokens' parameter + * @return true if the descriptor was tokenized successfully, false otherwise */ - static void + [[nodiscard]] static bool tokenize_column_descriptor(std::string const& descriptor, std::vector& tokens); private: diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 5f4384a1c..8752384ae 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -191,7 +191,10 @@ bool search_archive( try { for (auto const& column : command_line_arguments.get_projection_columns()) { std::vector descriptor_tokens; - StringUtils::tokenize_column_descriptor(column, descriptor_tokens); + if (false == StringUtils::tokenize_column_descriptor(column, descriptor_tokens)) { + SPDLOG_ERROR("Can not tokenize invalid column: \"{}\"", column); + return false; + } projection->add_column(ColumnDescriptor::create(descriptor_tokens)); } } catch (clp_s::TraceableException& e) { diff --git a/components/core/src/clp_s/search/kql/Kql.g4 b/components/core/src/clp_s/search/kql/Kql.g4 index 2ddef732c..33abf66bd 100644 --- a/components/core/src/clp_s/search/kql/Kql.g4 +++ b/components/core/src/clp_s/search/kql/Kql.g4 @@ -96,7 +96,7 @@ fragment ESCAPED_SPACE ; fragment SPECIAL_CHARACTER - : [\\():<>"*?{}] + : [\\():<>"*?{}.] ; diff --git a/components/core/src/clp_s/search/kql/kql.cpp b/components/core/src/clp_s/search/kql/kql.cpp index fa560cef5..972e44ad7 100644 --- a/components/core/src/clp_s/search/kql/kql.cpp +++ b/components/core/src/clp_s/search/kql/kql.cpp @@ -112,7 +112,10 @@ class ParseTreeVisitor : public KqlBaseVisitor { std::string column = unquote_string(ctx->LITERAL()->getText()); std::vector descriptor_tokens; - StringUtils::tokenize_column_descriptor(column, descriptor_tokens); + if (false == StringUtils::tokenize_column_descriptor(column, descriptor_tokens)) { + SPDLOG_ERROR("Can not tokenize invalid column: \"{}\"", column); + return nullptr; + } return ColumnDescriptor::create(descriptor_tokens); } @@ -248,6 +251,10 @@ std::shared_ptr parse_kql_expression(std::istream& in) { } ParseTreeVisitor visitor; - return std::any_cast>(visitor.visitStart(tree)); + try { + return std::any_cast>(visitor.visitStart(tree)); + } catch (std::exception& e) { + return {}; + } } } // namespace clp_s::search::kql diff --git a/components/core/tests/test-kql.cpp b/components/core/tests/test-kql.cpp index 6b9eb594f..2646ff5e0 100644 --- a/components/core/tests/test-kql.cpp +++ b/components/core/tests/test-kql.cpp @@ -187,4 +187,49 @@ TEST_CASE("Test parsing KQL", "[KQL]") { auto failure = parse_kql_expression(incorrect_query); REQUIRE(nullptr == failure); } + + SECTION("Escape sequences in column name") { + auto query = GENERATE( + "a\\.b.c: *", + "\"a\\.b.c\": *", + "a\\.b: {c: *}", + "\"a\\.b\": {\"c\": *}" + ); + stringstream escaped_column_query{query}; + auto filter + = std::dynamic_pointer_cast(parse_kql_expression(escaped_column_query)); + REQUIRE(nullptr != filter); + REQUIRE(nullptr != filter->get_operand()); + REQUIRE(nullptr != filter->get_column()); + REQUIRE(false == filter->has_only_expression_operands()); + REQUIRE(false == filter->is_inverted()); + REQUIRE(FilterOperation::EQ == filter->get_operation()); + REQUIRE(2 == filter->get_column()->get_descriptor_list().size()); + auto it = filter->get_column()->descriptor_begin(); + REQUIRE(DescriptorToken{"a.b"} == *it++); + REQUIRE(DescriptorToken{"c"} == *it++); + } + + SECTION("Illegal escape sequences in column name") { + auto query = GENERATE( + //"a\\:*", this case is technically legal since ':' gets escaped + "\"a\\\":*", + "a\\ :*", + "\"a\\\" :*", + "a.:*", + "\"a.\":*", + "a. :*", + "\"a.\" :*" + ); + stringstream illegal_escape{query}; + auto filter = parse_kql_expression(illegal_escape); + REQUIRE(nullptr == filter); + } + + SECTION("Empty token in column name") { + auto query = GENERATE(".a:*", "a.:*", "a..c:*", "a.b.:*"); + stringstream empty_token_column{query}; + auto filter = parse_kql_expression(empty_token_column); + REQUIRE(nullptr == filter); + } } From 477130d2c9468a4c686902a7622b9a06730b4e82 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:54:52 -0500 Subject: [PATCH 102/114] build(core-clp): Remove `boost::iostream` dependency. (#450) --- components/core/src/clp/clg/CMakeLists.txt | 2 +- components/core/src/clp/clo/CMakeLists.txt | 2 +- components/core/src/clp/clp/CMakeLists.txt | 2 +- .../make_dictionaries_readable/CMakeLists.txt | 2 +- .../clp/streaming_archive/reader/Segment.cpp | 54 +++++++++---------- .../clp/streaming_archive/reader/Segment.hpp | 6 +-- .../core/tests/test-StreamingCompression.cpp | 21 ++------ 7 files changed, 36 insertions(+), 53 deletions(-) diff --git a/components/core/src/clp/clg/CMakeLists.txt b/components/core/src/clp/clg/CMakeLists.txt index a0ca5e9d0..c3c8e3aea 100644 --- a/components/core/src/clp/clg/CMakeLists.txt +++ b/components/core/src/clp/clg/CMakeLists.txt @@ -130,7 +130,7 @@ target_compile_features(clg PRIVATE cxx_std_20) target_include_directories(clg PRIVATE "${PROJECT_SOURCE_DIR}/submodules") target_link_libraries(clg PRIVATE - Boost::filesystem Boost::iostreams Boost::program_options + Boost::filesystem Boost::program_options fmt::fmt log_surgeon::log_surgeon MariaDBClient::MariaDBClient diff --git a/components/core/src/clp/clo/CMakeLists.txt b/components/core/src/clp/clo/CMakeLists.txt index 931bffeaf..39cc72b60 100644 --- a/components/core/src/clp/clo/CMakeLists.txt +++ b/components/core/src/clp/clo/CMakeLists.txt @@ -158,7 +158,7 @@ target_compile_features(clo PRIVATE cxx_std_20) target_include_directories(clo PRIVATE "${PROJECT_SOURCE_DIR}/submodules") target_link_libraries(clo PRIVATE - Boost::filesystem Boost::iostreams Boost::program_options + Boost::filesystem Boost::program_options fmt::fmt log_surgeon::log_surgeon ${MONGOCXX_TARGET} diff --git a/components/core/src/clp/clp/CMakeLists.txt b/components/core/src/clp/clp/CMakeLists.txt index 53342f3a9..eff32ce46 100644 --- a/components/core/src/clp/clp/CMakeLists.txt +++ b/components/core/src/clp/clp/CMakeLists.txt @@ -171,7 +171,7 @@ target_compile_features(clp PRIVATE cxx_std_20) target_include_directories(clp PRIVATE "${PROJECT_SOURCE_DIR}/submodules") target_link_libraries(clp PRIVATE - Boost::filesystem Boost::iostreams Boost::program_options + Boost::filesystem Boost::program_options fmt::fmt log_surgeon::log_surgeon spdlog::spdlog diff --git a/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt b/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt index fd62a39fb..9779d137f 100644 --- a/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt +++ b/components/core/src/clp/make_dictionaries_readable/CMakeLists.txt @@ -45,7 +45,7 @@ target_compile_features(make-dictionaries-readable PRIVATE cxx_std_20) target_include_directories(make-dictionaries-readable PRIVATE "${PROJECT_SOURCE_DIR}/submodules") target_link_libraries(make-dictionaries-readable PRIVATE - Boost::filesystem Boost::iostreams Boost::program_options + Boost::filesystem Boost::program_options log_surgeon::log_surgeon spdlog::spdlog clp::string_utils diff --git a/components/core/src/clp/streaming_archive/reader/Segment.cpp b/components/core/src/clp/streaming_archive/reader/Segment.cpp index aa43e1d1f..7732dc5f8 100644 --- a/components/core/src/clp/streaming_archive/reader/Segment.cpp +++ b/components/core/src/clp/streaming_archive/reader/Segment.cpp @@ -3,12 +3,16 @@ #include #include +#include #include #include +#include +#include "../../ErrorCode.hpp" #include "../../FileReader.hpp" #include "../../spdlog_with_specializations.hpp" +#include "../../TraceableException.hpp" using std::make_unique; using std::string; @@ -33,47 +37,37 @@ ErrorCode Segment::try_open(string const& segment_dir_path, segment_id_t segment return ErrorCode_Success; } - // Get the size of the compressed segment file - boost::system::error_code boost_error_code; - size_t segment_file_size = boost::filesystem::file_size(segment_path, boost_error_code); - if (boost_error_code) { - SPDLOG_ERROR( - "streaming_archive::reader::Segment: Unable to obtain file size for segment: " - "{}", - segment_path.c_str() - ); - SPDLOG_ERROR("streaming_archive::reader::Segment: {}", boost_error_code.message().c_str()); - return ErrorCode_Failure; - } - - // Sanity check: previously used memory mapped file should be closed before opening a new - // one - if (m_memory_mapped_segment_file.is_open()) { + // Sanity check: previously used memory mapped file should be closed before opening a new one + if (m_memory_mapped_segment_file.has_value()) { SPDLOG_WARN( "streaming_archive::reader::Segment: Previous segment should be closed before " "opening new one: {}", segment_path.c_str() ); - m_memory_mapped_segment_file.close(); + m_memory_mapped_segment_file.reset(); } - // Create read only memory mapped file - boost::iostreams::mapped_file_params memory_map_params; - memory_map_params.path = segment_path; - memory_map_params.flags = boost::iostreams::mapped_file::readonly; - memory_map_params.length = segment_file_size; - // Try to map it to the same memory location as the previous memory mapped file - memory_map_params.hint = m_memory_mapped_segment_file.data(); - m_memory_mapped_segment_file.open(memory_map_params); - if (!m_memory_mapped_segment_file.is_open()) { + + // Create read-only memory mapped file + try { + m_memory_mapped_segment_file.emplace(segment_path); + } catch (TraceableException const& ex) { + auto const error_code{ex.get_error_code()}; + auto const formatted_error{ + ErrorCode_errno == error_code + ? fmt::format("errno={}", errno) + : fmt::format("error_code={}, message={}", error_code, ex.what()) + }; SPDLOG_ERROR( "streaming_archive::reader:Segment: Unable to memory map the compressed " - "segment with path: {}", - segment_path.c_str() + "segment with path: {}. Error: {}", + segment_path.c_str(), + formatted_error ); return ErrorCode_Failure; } - m_decompressor.open(m_memory_mapped_segment_file.data(), segment_file_size); + auto const view{m_memory_mapped_segment_file.value().get_view()}; + m_decompressor.open(view.data(), view.size()); m_segment_path = segment_path; return ErrorCode_Success; @@ -82,7 +76,7 @@ ErrorCode Segment::try_open(string const& segment_dir_path, segment_id_t segment void Segment::close() { if (!m_segment_path.empty()) { m_decompressor.close(); - m_memory_mapped_segment_file.close(); + m_memory_mapped_segment_file.reset(); m_segment_path.clear(); } } diff --git a/components/core/src/clp/streaming_archive/reader/Segment.hpp b/components/core/src/clp/streaming_archive/reader/Segment.hpp index 9ed40ea60..cdcd51b4d 100644 --- a/components/core/src/clp/streaming_archive/reader/Segment.hpp +++ b/components/core/src/clp/streaming_archive/reader/Segment.hpp @@ -2,12 +2,12 @@ #define CLP_STREAMING_ARCHIVE_READER_SEGMENT_HPP #include +#include #include -#include - #include "../../Defs.h" #include "../../ErrorCode.hpp" +#include "../../ReadOnlyMemoryMappedFile.hpp" #include "../../streaming_compression/passthrough/Decompressor.hpp" #include "../../streaming_compression/zstd/Decompressor.hpp" #include "../Constants.hpp" @@ -53,7 +53,7 @@ class Segment { private: std::string m_segment_path; - boost::iostreams::mapped_file_source m_memory_mapped_segment_file; + std::optional m_memory_mapped_segment_file; #if USE_PASSTHROUGH_COMPRESSION streaming_compression::passthrough::Decompressor m_decompressor; diff --git a/components/core/tests/test-StreamingCompression.cpp b/components/core/tests/test-StreamingCompression.cpp index b43316b3f..747a38a05 100644 --- a/components/core/tests/test-StreamingCompression.cpp +++ b/components/core/tests/test-StreamingCompression.cpp @@ -1,10 +1,11 @@ +#include #include #include -#include #include #include +#include "../src/clp/ReadOnlyMemoryMappedFile.hpp" #include "../src/clp/streaming_compression/passthrough/Compressor.hpp" #include "../src/clp/streaming_compression/passthrough/Decompressor.hpp" #include "../src/clp/streaming_compression/zstd/Compressor.hpp" @@ -149,22 +150,10 @@ TEST_CASE("StreamingCompression", "[StreamingCompression]") { // Decompress // Memory map compressed file - // Create memory mapping for compressed_file_path, use boost read only memory mapped file - boost::system::error_code boost_error_code; - size_t compressed_file_size - = boost::filesystem::file_size(compressed_file_path, boost_error_code); - REQUIRE(!boost_error_code); - - boost::iostreams::mapped_file_params memory_map_params; - memory_map_params.path = compressed_file_path; - memory_map_params.flags = boost::iostreams::mapped_file::readonly; - memory_map_params.length = compressed_file_size; - boost::iostreams::mapped_file_source memory_mapped_compressed_file; - memory_mapped_compressed_file.open(memory_map_params); - REQUIRE(memory_mapped_compressed_file.is_open()); - + clp::ReadOnlyMemoryMappedFile const memory_mapped_compressed_file{compressed_file_path}; clp::streaming_compression::passthrough::Decompressor decompressor; - decompressor.open(memory_mapped_compressed_file.data(), compressed_file_size); + auto const compressed_file_view{memory_mapped_compressed_file.get_view()}; + decompressor.open(compressed_file_view.data(), compressed_file_view.size()); size_t uncompressed_bytes = 0; REQUIRE(ErrorCode_Success From ac4f1c1887fff87ae576e19feedd516379ff2368 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:32:59 -0500 Subject: [PATCH 103/114] test(core): Update `network_reader_with_valid_http_header_kv_pairs` to verify the return value before parsing the read content into a JSON object. (#593) --- components/core/tests/test-NetworkReader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index f32daef14..f2995f141 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -213,9 +213,10 @@ TEST_CASE("network_reader_with_valid_http_header_kv_pairs", "[NetworkReader]") { clp::NetworkReader::cDefaultBufferSize, valid_http_header_kv_pairs }; - auto const content = nlohmann::json::parse(get_content(reader)); - auto const& headers{content.at("headers")}; + auto const content{get_content(reader)}; REQUIRE(assert_curl_error_code(CURLE_OK, reader)); + auto const parsed_content = nlohmann::json::parse(content); + auto const& headers{parsed_content.at("headers")}; for (auto const& [key, value] : valid_http_header_kv_pairs) { REQUIRE((value == headers.at(key).get())); } From d969aaf456cc2cc5caa58586d4264718fda94aa0 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:51:20 -0500 Subject: [PATCH 104/114] feat(clp-package): Add support for extracting JSON streams from archives. (#569) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../clp_package_utils/general.py | 17 +- .../clp_package_utils/scripts/decompress.py | 50 +++- .../scripts/native/decompress.py | 96 +++--- .../clp_package_utils/scripts/start_clp.py | 16 +- .../clp-py-utils/clp_py_utils/clp_config.py | 26 +- .../create-results-cache-indices.py | 10 +- .../executor/query/celeryconfig.py | 4 +- ...ract_ir_task.py => extract_stream_task.py} | 50 +++- .../executor/query/fs_search_task.py | 4 +- .../job_orchestration/scheduler/constants.py | 1 + .../job_orchestration/scheduler/job_config.py | 5 + .../scheduler/query/query_scheduler.py | 283 +++++++++++++----- .../scheduler/scheduler_data.py | 13 +- .../client/src/ui/QueryStatus.jsx | 2 +- components/log-viewer-webui/server/.env | 2 +- .../log-viewer-webui/server/settings.json | 4 +- .../log-viewer-webui/server/src/DbManager.js | 10 +- components/log-viewer-webui/server/src/app.js | 2 +- .../server/src/routes/static.js | 10 +- .../package-template/src/etc/clp-config.yml | 8 +- 20 files changed, 415 insertions(+), 198 deletions(-) rename components/job-orchestration/job_orchestration/executor/query/{extract_ir_task.py => extract_stream_task.py} (69%) diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index 4dca481b0..f42542ebc 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -33,6 +33,7 @@ # CONSTANTS EXTRACT_FILE_CMD = "x" EXTRACT_IR_CMD = "i" +EXTRACT_JSON_CMD = "j" # Paths CONTAINER_CLP_HOME = pathlib.Path("/") / "opt" / "clp" @@ -84,7 +85,7 @@ def __init__(self, clp_home: pathlib.Path, docker_clp_home: pathlib.Path): self.data_dir: typing.Optional[DockerMount] = None self.logs_dir: typing.Optional[DockerMount] = None self.archives_output_dir: typing.Optional[DockerMount] = None - self.ir_output_dir: typing.Optional[DockerMount] = None + self.stream_output_dir: typing.Optional[DockerMount] = None def get_clp_home(): @@ -251,17 +252,17 @@ def generate_container_config( container_clp_config.archive_output.directory, ) - container_clp_config.ir_output.directory = pathlib.Path("/") / "mnt" / "ir-output" + container_clp_config.stream_output.directory = pathlib.Path("/") / "mnt" / "stream-output" if not is_path_already_mounted( clp_home, CONTAINER_CLP_HOME, - clp_config.ir_output.directory, - container_clp_config.ir_output.directory, + clp_config.stream_output.directory, + container_clp_config.stream_output.directory, ): - docker_mounts.ir_output_dir = DockerMount( + docker_mounts.stream_output_dir = DockerMount( DockerMountType.BIND, - clp_config.ir_output.directory, - container_clp_config.ir_output.directory, + clp_config.stream_output.directory, + container_clp_config.stream_output.directory, ) return container_clp_config, docker_mounts @@ -482,7 +483,7 @@ def validate_results_cache_config( def validate_worker_config(clp_config: CLPConfig): clp_config.validate_input_logs_dir() clp_config.validate_archive_output_dir() - clp_config.validate_ir_output_dir() + clp_config.validate_stream_output_dir() def validate_webui_config( diff --git a/components/clp-package-utils/clp_package_utils/scripts/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/decompress.py index 1a2973fec..903107c32 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/decompress.py @@ -14,6 +14,7 @@ dump_container_config, EXTRACT_FILE_CMD, EXTRACT_IR_CMD, + EXTRACT_JSON_CMD, generate_container_config, generate_container_name, generate_container_start_cmd, @@ -146,11 +147,11 @@ def handle_extract_file_cmd( return 0 -def handle_extract_ir_cmd( +def handle_extract_stream_cmd( parsed_args, clp_home: pathlib.Path, default_config_file_path: pathlib.Path ) -> int: """ - Handles the IR extraction command. + Handles the stream extraction command. :param parsed_args: :param clp_home: :param default_config_file_path: @@ -174,29 +175,41 @@ def handle_extract_ir_cmd( ) # fmt: off + job_command = parsed_args.command extract_cmd = [ "python3", "-m", "clp_package_utils.scripts.native.decompress", "--config", str(generated_config_path_on_container), - EXTRACT_IR_CMD, - str(parsed_args.msg_ix), + job_command ] # fmt: on - if parsed_args.orig_file_id: - extract_cmd.append("--orig-file-id") - extract_cmd.append(str(parsed_args.orig_file_id)) + + if EXTRACT_IR_CMD == job_command: + extract_cmd.append(str(parsed_args.msg_ix)) + if parsed_args.orig_file_id: + extract_cmd.append("--orig-file-id") + extract_cmd.append(str(parsed_args.orig_file_id)) + else: + extract_cmd.append("--orig-file-path") + extract_cmd.append(str(parsed_args.orig_file_path)) + if parsed_args.target_uncompressed_size: + extract_cmd.append("--target-uncompressed-size") + extract_cmd.append(str(parsed_args.target_uncompressed_size)) + elif EXTRACT_JSON_CMD == job_command: + extract_cmd.append(str(parsed_args.archive_id)) + if parsed_args.target_chunk_size: + extract_cmd.append("--target-chunk-size") + extract_cmd.append(str(parsed_args.target_chunk_size)) else: - extract_cmd.append("--orig-file-path") - extract_cmd.append(str(parsed_args.orig_file_path)) - if parsed_args.target_uncompressed_size: - extract_cmd.append("--target-uncompressed-size") - extract_cmd.append(str(parsed_args.target_uncompressed_size)) + logger.error(f"Unexpected command: {job_command}") + return -1 + cmd = container_start_cmd + extract_cmd try: subprocess.run(cmd, check=True) except subprocess.CalledProcessError: - logger.exception("Docker or IR extraction command failed.") + logger.exception("Docker or stream extraction command failed.") return -1 # Remove generated files @@ -241,13 +254,20 @@ def main(argv): group.add_argument("--orig-file-id", type=str, help="Original file's ID.") group.add_argument("--orig-file-path", type=str, help="Original file's path.") + # JSON extraction command parser + json_extraction_parser = command_args_parser.add_parser(EXTRACT_JSON_CMD) + json_extraction_parser.add_argument("archive_id", type=str, help="Archive ID") + json_extraction_parser.add_argument( + "--target-chunk-size", type=int, help="Target chunk size", default=100000 + ) + parsed_args = args_parser.parse_args(argv[1:]) command = parsed_args.command if EXTRACT_FILE_CMD == command: return handle_extract_file_cmd(parsed_args, clp_home, default_config_file_path) - elif EXTRACT_IR_CMD == command: - return handle_extract_ir_cmd(parsed_args, clp_home, default_config_file_path) + elif command in (EXTRACT_IR_CMD, EXTRACT_JSON_CMD): + return handle_extract_stream_cmd(parsed_args, clp_home, default_config_file_path) else: logger.exception(f"Unexpected command: {command}") return -1 diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py index b6585b192..d4217d66d 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py @@ -12,12 +12,17 @@ from clp_py_utils.clp_config import CLP_METADATA_TABLE_PREFIX, CLPConfig, Database from clp_py_utils.sql_adapter import SQL_Adapter from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType -from job_orchestration.scheduler.job_config import ExtractIrJobConfig +from job_orchestration.scheduler.job_config import ( + ExtractIrJobConfig, + ExtractJsonJobConfig, + QueryJobConfig, +) from clp_package_utils.general import ( CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, EXTRACT_FILE_CMD, EXTRACT_IR_CMD, + EXTRACT_JSON_CMD, get_clp_home, load_config_file, ) @@ -70,45 +75,37 @@ def get_orig_file_id(db_config: Database, path: str) -> Optional[str]: return results[0]["orig_file_id"] -def submit_and_monitor_ir_extraction_job_in_db( +def submit_and_monitor_extraction_job_in_db( db_config: Database, - orig_file_id: str, - msg_ix: int, - target_uncompressed_size: Optional[int], + job_type: QueryJobType, + job_config: QueryJobConfig, ) -> int: """ - Submits an IR extraction job to the scheduler and waits until the job finishes. + Submits a stream extraction job to the scheduler and waits until it finishes. :param db_config: - :param orig_file_id: - :param msg_ix: - :param target_uncompressed_size: + :param job_type: + :param job_config: :return: 0 on success, -1 otherwise. """ - extract_ir_config = ExtractIrJobConfig( - orig_file_id=orig_file_id, - msg_ix=msg_ix, - target_uncompressed_size=target_uncompressed_size, - ) - sql_adapter = SQL_Adapter(db_config) - job_id = submit_query_job(sql_adapter, extract_ir_config, QueryJobType.EXTRACT_IR) + job_id = submit_query_job(sql_adapter, job_config, job_type) job_status = wait_for_query_job(sql_adapter, job_id) if QueryJobStatus.SUCCEEDED == job_status: - logger.info(f"Finished IR extraction job {job_id}.") + logger.info(f"Finished extraction job {job_id}.") return 0 - logger.error( - f"IR extraction job {job_id} finished with unexpected status: {job_status.to_str()}." - ) + logger.error(f"Extraction job {job_id} finished with unexpected status: {job_status.to_str()}.") return -1 -def handle_extract_ir_cmd( - parsed_args: argparse.Namespace, clp_home: pathlib.Path, default_config_file_path: pathlib.Path +def handle_extract_stream_cmd( + parsed_args: argparse.Namespace, + clp_home: pathlib.Path, + default_config_file_path: pathlib.Path, ) -> int: """ - Handles the IR extraction command. + Handles the stream extraction command. :param parsed_args: :param clp_home: :param default_config_file_path: @@ -121,26 +118,46 @@ def handle_extract_ir_cmd( if clp_config is None: return -1 - orig_file_id: str - if parsed_args.orig_file_id: - orig_file_id = parsed_args.orig_file_id + command = parsed_args.command + + job_config: QueryJobConfig + job_type: QueryJobType + if EXTRACT_IR_CMD == command: + job_type = QueryJobType.EXTRACT_IR + orig_file_id: str + if parsed_args.orig_file_id: + orig_file_id = parsed_args.orig_file_id + else: + orig_file_path = parsed_args.orig_file_path + orig_file_id = get_orig_file_id(clp_config.database, orig_file_path) + if orig_file_id is None: + logger.error(f"Cannot find orig_file_id corresponding to '{orig_file_path}'.") + return -1 + job_config = ExtractIrJobConfig( + orig_file_id=orig_file_id, + msg_ix=parsed_args.msg_ix, + target_uncompressed_size=parsed_args.target_uncompressed_size, + ) + elif EXTRACT_JSON_CMD == command: + job_type = QueryJobType.EXTRACT_JSON + job_config = ExtractJsonJobConfig( + archive_id=parsed_args.archive_id, target_chunk_size=parsed_args.target_chunk_size + ) else: - orig_file_id = get_orig_file_id(clp_config.database, parsed_args.orig_file_path) - if orig_file_id is None: - return -1 + logger.error(f"Unsupported stream extraction command: {command}") + return -1 try: return asyncio.run( run_function_in_process( - submit_and_monitor_ir_extraction_job_in_db, + submit_and_monitor_extraction_job_in_db, clp_config.database, - orig_file_id, - parsed_args.msg_ix, - parsed_args.target_uncompressed_size, + job_type, + job_config, ) ) except asyncio.CancelledError: - logger.error("IR extraction cancelled.") + logger.error("Stream extraction cancelled.") return -1 @@ -278,13 +295,20 @@ def main(argv): group.add_argument("--orig-file-id", type=str, help="Original file's ID.") group.add_argument("--orig-file-path", type=str, help="Original file's path.") + # JSON extraction command parser + json_extraction_parser = command_args_parser.add_parser(EXTRACT_JSON_CMD) + json_extraction_parser.add_argument("archive_id", type=str, help="Archive ID") + json_extraction_parser.add_argument( + "--target-chunk-size", type=int, help="Target chunk size.", required=True + ) + parsed_args = args_parser.parse_args(argv[1:]) command = parsed_args.command if EXTRACT_FILE_CMD == command: return handle_extract_file_cmd(parsed_args, clp_home, default_config_file_path) - elif EXTRACT_IR_CMD == command: - return handle_extract_ir_cmd(parsed_args, clp_home, default_config_file_path) + elif command in (EXTRACT_IR_CMD, EXTRACT_JSON_CMD): + return handle_extract_stream_cmd(parsed_args, clp_home, default_config_file_path) else: logger.exception(f"Unexpected command: {command}") return -1 diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 7c6de0200..a25756fd9 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -286,7 +286,7 @@ def create_results_cache_indices( "python3", str(clp_py_utils_dir / "create-results-cache-indices.py"), "--uri", container_clp_config.results_cache.get_uri(), - "--ir-collection", container_clp_config.results_cache.ir_collection_name, + "--stream-collection", container_clp_config.results_cache.stream_collection_name, ] # fmt: on @@ -660,10 +660,10 @@ def start_query_worker( celery_method = "job_orchestration.executor.query" celery_route = f"{QueueName.QUERY}" - query_worker_mount = [mounts.ir_output_dir] + query_worker_mount = [mounts.stream_output_dir] query_worker_env = { - "CLP_IR_OUTPUT_DIR": container_clp_config.ir_output.directory, - "CLP_IR_COLLECTION": clp_config.results_cache.ir_collection_name, + "CLP_STREAM_OUTPUT_DIR": container_clp_config.stream_output.directory, + "CLP_STREAM_COLLECTION_NAME": clp_config.results_cache.stream_collection_name, } generic_start_worker( @@ -710,7 +710,7 @@ def generic_start_worker( # Create necessary directories clp_config.archive_output.directory.mkdir(parents=True, exist_ok=True) - clp_config.ir_output.directory.mkdir(parents=True, exist_ok=True) + clp_config.stream_output.directory.mkdir(parents=True, exist_ok=True) clp_site_packages_dir = CONTAINER_CLP_HOME / "lib" / "python3" / "site-packages" # fmt: off @@ -933,9 +933,9 @@ def start_log_viewer_webui( "MongoDbHost": clp_config.results_cache.host, "MongoDbPort": clp_config.results_cache.port, "MongoDbName": clp_config.results_cache.db_name, - "MongoDbIrFilesCollectionName": clp_config.results_cache.ir_collection_name, + "MongoDbStreamFilesCollectionName": clp_config.results_cache.stream_collection_name, "ClientDir": str(container_log_viewer_webui_dir / "client"), - "IrFilesDir": str(container_clp_config.ir_output.directory), + "StreamFilesDir": str(container_clp_config.stream_output.directory), "LogViewerDir": str(container_log_viewer_webui_dir / "yscope-log-viewer"), } settings_json = read_and_update_settings_json(settings_json_path, settings_json_updates) @@ -961,7 +961,7 @@ def start_log_viewer_webui( # fmt: on necessary_mounts = [ mounts.clp_home, - mounts.ir_output_dir, + mounts.stream_output_dir, ] for mount in necessary_mounts: if mount: diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index f5a813057..4bb00bd9e 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -270,7 +270,7 @@ class ResultsCache(BaseModel): host: str = "localhost" port: int = 27017 db_name: str = "clp-query-results" - ir_collection_name: str = "ir-files" + stream_collection_name: str = "stream-files" @validator("host") def validate_host(cls, field): @@ -284,10 +284,12 @@ def validate_db_name(cls, field): raise ValueError(f"{RESULTS_CACHE_COMPONENT_NAME}.db_name cannot be empty.") return field - @validator("ir_collection_name") - def validate_ir_collection_name(cls, field): + @validator("stream_collection_name") + def validate_stream_collection_name(cls, field): if "" == field: - raise ValueError(f"{RESULTS_CACHE_COMPONENT_NAME}.ir_collection_name cannot be empty.") + raise ValueError( + f"{RESULTS_CACHE_COMPONENT_NAME}.stream_collection_name cannot be empty." + ) return field def get_uri(self): @@ -343,8 +345,8 @@ def dump_to_primitive_dict(self): return d -class IrOutput(BaseModel): - directory: pathlib.Path = pathlib.Path("var") / "data" / "ir" +class StreamOutput(BaseModel): + directory: pathlib.Path = pathlib.Path("var") / "data" / "stream" target_uncompressed_size: int = 128 * 1024 * 1024 @validator("directory") @@ -425,7 +427,7 @@ class CLPConfig(BaseModel): credentials_file_path: pathlib.Path = CLP_DEFAULT_CREDENTIALS_FILE_PATH archive_output: ArchiveOutput = ArchiveOutput() - ir_output: IrOutput = IrOutput() + stream_output: StreamOutput = StreamOutput() data_directory: pathlib.Path = pathlib.Path("var") / "data" logs_directory: pathlib.Path = pathlib.Path("var") / "log" @@ -435,7 +437,7 @@ def make_config_paths_absolute(self, clp_home: pathlib.Path): self.input_logs_directory = make_config_path_absolute(clp_home, self.input_logs_directory) self.credentials_file_path = make_config_path_absolute(clp_home, self.credentials_file_path) self.archive_output.make_config_paths_absolute(clp_home) - self.ir_output.make_config_paths_absolute(clp_home) + self.stream_output.make_config_paths_absolute(clp_home) self.data_directory = make_config_path_absolute(clp_home, self.data_directory) self.logs_directory = make_config_path_absolute(clp_home, self.logs_directory) self._os_release_file_path = make_config_path_absolute(clp_home, self._os_release_file_path) @@ -455,11 +457,11 @@ def validate_archive_output_dir(self): except ValueError as ex: raise ValueError(f"archive_output.directory is invalid: {ex}") - def validate_ir_output_dir(self): + def validate_stream_output_dir(self): try: - validate_path_could_be_dir(self.ir_output.directory) + validate_path_could_be_dir(self.stream_output.directory) except ValueError as ex: - raise ValueError(f"ir_output.directory is invalid: {ex}") + raise ValueError(f"stream_output.directory is invalid: {ex}") def validate_data_dir(self): try: @@ -528,7 +530,7 @@ def load_redis_credentials_from_file(self): def dump_to_primitive_dict(self): d = self.dict() d["archive_output"] = self.archive_output.dump_to_primitive_dict() - d["ir_output"] = self.ir_output.dump_to_primitive_dict() + d["stream_output"] = self.stream_output.dump_to_primitive_dict() # Turn paths into primitive strings d["input_logs_directory"] = str(self.input_logs_directory) d["credentials_file_path"] = str(self.credentials_file_path) diff --git a/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py b/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py index dafbd3bde..db03e9632 100644 --- a/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py +++ b/components/clp-py-utils/clp_py_utils/create-results-cache-indices.py @@ -18,19 +18,21 @@ def main(argv): args_parser = argparse.ArgumentParser(description="Creates results cache indices for CLP.") args_parser.add_argument("--uri", required=True, help="URI of the results cache.") - args_parser.add_argument("--ir-collection", required=True, help="Collection for IR metadata.") + args_parser.add_argument( + "--stream-collection", required=True, help="Collection for stream metadata." + ) parsed_args = args_parser.parse_args(argv[1:]) results_cache_uri = parsed_args.uri - ir_collection_name = parsed_args.ir_collection + stream_collection_name = parsed_args.stream_collection try: with MongoClient(results_cache_uri) as results_cache_client: - ir_collection = results_cache_client.get_default_database()[ir_collection_name] + stream_collection = results_cache_client.get_default_database()[stream_collection_name] file_split_id_index = IndexModel(["file_split_id"]) orig_file_id_index = IndexModel(["orig_file_id", "begin_msg_ix", "end_msg_ix"]) - ir_collection.create_indexes([file_split_id_index, orig_file_id_index]) + stream_collection.create_indexes([file_split_id_index, orig_file_id_index]) except Exception: logger.exception("Failed to create clp results cache indices.") return -1 diff --git a/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py b/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py index 994c0bbcf..6cf97dbd0 100644 --- a/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py +++ b/components/job-orchestration/job_orchestration/executor/query/celeryconfig.py @@ -4,12 +4,12 @@ imports = ( "job_orchestration.executor.query.fs_search_task", - "job_orchestration.executor.query.extract_ir_task", + "job_orchestration.executor.query.extract_stream_task", ) task_routes = { "job_orchestration.executor.query.fs_search_task.search": QueueName.QUERY, - "job_orchestration.executor.query.extract_ir_task.extract_ir": QueueName.QUERY, + "job_orchestration.executor.query.extract_stream_task.extract_stream": QueueName.QUERY, } task_create_missing_queues = True diff --git a/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py b/components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py similarity index 69% rename from components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py rename to components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py index 61fcbf549..9e99842ab 100644 --- a/components/job-orchestration/job_orchestration/executor/query/extract_ir_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py @@ -13,7 +13,7 @@ report_command_creation_failure, run_query_task, ) -from job_orchestration.scheduler.job_config import ExtractIrJobConfig +from job_orchestration.scheduler.job_config import ExtractIrJobConfig, ExtractJsonJobConfig from job_orchestration.scheduler.scheduler_data import QueryTaskStatus # Setup logging @@ -25,12 +25,14 @@ def make_command( clp_home: Path, archives_dir: Path, archive_id: str, - ir_output_dir: Path, - extract_ir_config: ExtractIrJobConfig, + stream_output_dir: Path, + job_config: dict, results_cache_uri: str, - ir_collection: str, + stream_collection_name: str, ) -> Optional[List[str]]: if StorageEngine.CLP == storage_engine: + logger.info("Starting IR extraction") + extract_ir_config = ExtractIrJobConfig.parse_obj(job_config) if not extract_ir_config.file_split_id: logger.error("file_split_id not supplied") return None @@ -39,13 +41,32 @@ def make_command( "i", str(archives_dir / archive_id), extract_ir_config.file_split_id, - str(ir_output_dir), + str(stream_output_dir), results_cache_uri, - ir_collection, + stream_collection_name, ] if extract_ir_config.target_uncompressed_size is not None: command.append("--target-size") command.append(str(extract_ir_config.target_uncompressed_size)) + elif StorageEngine.CLP_S == storage_engine: + logger.info("Starting JSON extraction") + extract_json_config = ExtractJsonJobConfig.parse_obj(job_config) + command = [ + str(clp_home / "bin" / "clp-s"), + "x", + str(archives_dir), + str(stream_output_dir), + "--ordered", + "--archive-id", + archive_id, + "--mongodb-uri", + results_cache_uri, + "--mongodb-collection", + stream_collection_name, + ] + if extract_json_config.target_chunk_size is not None: + command.append("--ordered-chunk-size") + command.append(str(extract_json_config.target_chunk_size)) else: logger.error(f"Unsupported storage engine {storage_engine}") return None @@ -54,16 +75,16 @@ def make_command( @app.task(bind=True) -def extract_ir( +def extract_stream( self: Task, job_id: str, task_id: int, - job_config_obj: dict, + job_config: dict, archive_id: str, clp_metadata_db_conn_params: dict, results_cache_uri: str, ) -> Dict[str, Any]: - task_name = "IR extraction" + task_name = "Stream Extraction" # Setup logging to file clp_logs_dir = Path(os.getenv("CLP_LOGS_DIR")) @@ -80,19 +101,18 @@ def extract_ir( clp_home = Path(os.getenv("CLP_HOME")) archive_directory = Path(os.getenv("CLP_ARCHIVE_OUTPUT_DIR")) clp_storage_engine = os.getenv("CLP_STORAGE_ENGINE") - ir_output_dir = Path(os.getenv("CLP_IR_OUTPUT_DIR")) - ir_collection = os.getenv("CLP_IR_COLLECTION") - extract_ir_config = ExtractIrJobConfig.parse_obj(job_config_obj) + stream_output_dir = Path(os.getenv("CLP_STREAM_OUTPUT_DIR")) + stream_collection_name = os.getenv("CLP_STREAM_COLLECTION_NAME") task_command = make_command( storage_engine=clp_storage_engine, clp_home=clp_home, archives_dir=archive_directory, archive_id=archive_id, - ir_output_dir=ir_output_dir, - extract_ir_config=extract_ir_config, + stream_output_dir=stream_output_dir, + job_config=job_config, results_cache_uri=results_cache_uri, - ir_collection=ir_collection, + stream_collection_name=stream_collection_name, ) if not task_command: return report_command_creation_failure( diff --git a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py index 162056220..598bfdcfc 100644 --- a/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/fs_search_task.py @@ -98,7 +98,7 @@ def search( self: Task, job_id: str, task_id: int, - job_config_obj: dict, + job_config: dict, archive_id: str, clp_metadata_db_conn_params: dict, results_cache_uri: str, @@ -120,7 +120,7 @@ def search( clp_home = Path(os.getenv("CLP_HOME")) archive_directory = Path(os.getenv("CLP_ARCHIVE_OUTPUT_DIR")) clp_storage_engine = os.getenv("CLP_STORAGE_ENGINE") - search_config = SearchJobConfig.parse_obj(job_config_obj) + search_config = SearchJobConfig.parse_obj(job_config) task_command = make_command( storage_engine=clp_storage_engine, diff --git a/components/job-orchestration/job_orchestration/scheduler/constants.py b/components/job-orchestration/job_orchestration/scheduler/constants.py index 131719148..cd85016a3 100644 --- a/components/job-orchestration/job_orchestration/scheduler/constants.py +++ b/components/job-orchestration/job_orchestration/scheduler/constants.py @@ -72,6 +72,7 @@ def to_str(self) -> str: class QueryJobType(IntEnum): SEARCH_OR_AGGREGATION = 0 EXTRACT_IR = auto() + EXTRACT_JSON = auto() def __str__(self) -> str: return str(self.value) diff --git a/components/job-orchestration/job_orchestration/scheduler/job_config.py b/components/job-orchestration/job_orchestration/scheduler/job_config.py index e90e2ee7f..7cf8b2324 100644 --- a/components/job-orchestration/job_orchestration/scheduler/job_config.py +++ b/components/job-orchestration/job_orchestration/scheduler/job_config.py @@ -49,6 +49,11 @@ class ExtractIrJobConfig(QueryJobConfig): target_uncompressed_size: typing.Optional[int] = None +class ExtractJsonJobConfig(QueryJobConfig): + archive_id: str + target_chunk_size: typing.Optional[int] = None + + class SearchJobConfig(QueryJobConfig): query_string: str max_num_results: int diff --git a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py index 2a0f855a3..a9c60f380 100644 --- a/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py +++ b/components/job-orchestration/job_orchestration/scheduler/query/query_scheduler.py @@ -23,6 +23,7 @@ import os import pathlib import sys +from abc import ABC, abstractmethod from pathlib import Path from typing import Any, Dict, List, Optional, Tuple @@ -39,10 +40,14 @@ from clp_py_utils.core import read_yaml_config_file from clp_py_utils.decorators import exception_default_value from clp_py_utils.sql_adapter import SQL_Adapter -from job_orchestration.executor.query.extract_ir_task import extract_ir +from job_orchestration.executor.query.extract_stream_task import extract_stream from job_orchestration.executor.query.fs_search_task import search from job_orchestration.scheduler.constants import QueryJobStatus, QueryJobType, QueryTaskStatus -from job_orchestration.scheduler.job_config import ExtractIrJobConfig, SearchJobConfig +from job_orchestration.scheduler.job_config import ( + ExtractIrJobConfig, + ExtractJsonJobConfig, + SearchJobConfig, +) from job_orchestration.scheduler.query.reducer_handler import ( handle_reducer_connection, ReducerHandlerMessage, @@ -51,6 +56,7 @@ ) from job_orchestration.scheduler.scheduler_data import ( ExtractIrJob, + ExtractJsonJob, InternalJobState, QueryJob, QueryTaskResult, @@ -67,9 +73,118 @@ # Dictionary that maps IDs of file splits being extracted to IDs of jobs waiting for them active_file_split_ir_extractions: Dict[str, List[str]] = {} +# Dictionary that maps IDs of clp-s archives being extracted to IDs of jobs waiting for them +active_archive_json_extractions: Dict[str, List[str]] = {} + reducer_connection_queue: Optional[asyncio.Queue] = None +class StreamExtractionHandle(ABC): + def __init__(self, job_id: str): + self._job_id = job_id + self._archive_id: Optional[str] = None + + def get_archive_id(self) -> Optional[str]: + return self._archive_id + + @abstractmethod + def get_stream_id(self) -> str: ... + + @abstractmethod + def is_stream_extraction_active(self) -> bool: ... + + @abstractmethod + def is_stream_extracted(self, results_cache_uri: str, stream_collection_name: str) -> bool: ... + + @abstractmethod + def mark_job_as_waiting(self) -> None: ... + + @abstractmethod + def create_stream_extraction_job(self) -> QueryJob: ... + + +class IrExtractionHandle(StreamExtractionHandle): + def __init__(self, job_id: str, job_config: Dict[str, Any], db_conn): + super().__init__(job_id) + self.__job_config = ExtractIrJobConfig.parse_obj(job_config) + self._archive_id, self.__file_split_id = get_archive_and_file_split_ids_for_ir_extraction( + db_conn, self.__job_config + ) + if self._archive_id is None: + raise ValueError("Job parameters don't resolve to an existing archive") + + self.__job_config.file_split_id = self.__file_split_id + + def get_stream_id(self) -> str: + return self.__file_split_id + + def is_stream_extraction_active(self) -> bool: + return self.__file_split_id in active_file_split_ir_extractions + + def is_stream_extracted(self, results_cache_uri: str, stream_collection_name: str) -> bool: + return document_exists( + results_cache_uri, stream_collection_name, "file_split_id", self.__file_split_id + ) + + def mark_job_as_waiting(self) -> None: + global active_file_split_ir_extractions + file_split_id = self.__file_split_id + if file_split_id not in active_file_split_ir_extractions: + active_file_split_ir_extractions[file_split_id] = [] + active_file_split_ir_extractions[file_split_id].append(self._job_id) + + def create_stream_extraction_job(self) -> QueryJob: + logger.info( + f"Creating IR extraction job {self._job_id} for file_split: {self.__file_split_id}" + ) + return ExtractIrJob( + id=self._job_id, + extract_ir_config=self.__job_config, + state=InternalJobState.WAITING_FOR_DISPATCH, + ) + + +class JsonExtractionHandle(StreamExtractionHandle): + def __init__(self, job_id: str, job_config: Dict[str, Any], db_conn): + super().__init__(job_id) + self.__job_config = ExtractJsonJobConfig.parse_obj(job_config) + self._archive_id = self.__job_config.archive_id + if not archive_exists(db_conn, self._archive_id): + raise ValueError(f"Archive {self._archive_id} doesn't exist") + + def get_stream_id(self) -> str: + return self._archive_id + + def is_stream_extraction_active(self) -> bool: + return self._archive_id in active_archive_json_extractions + + def is_stream_extracted(self, results_cache_uri: str, stream_collection_name: str) -> bool: + return document_exists( + results_cache_uri, stream_collection_name, "orig_file_id", self._archive_id + ) + + def mark_job_as_waiting(self) -> None: + global active_archive_json_extractions + archive_id = self._archive_id + if archive_id not in active_archive_json_extractions: + active_archive_json_extractions[archive_id] = [] + active_archive_json_extractions[archive_id].append(self._job_id) + + def create_stream_extraction_job(self) -> QueryJob: + logger.info(f"Creating json extraction job {self._job_id} on archive: {self._archive_id}") + return ExtractJsonJob( + id=self._job_id, + extract_json_config=self.__job_config, + state=InternalJobState.WAITING_FOR_DISPATCH, + ) + + +def document_exists(mongodb_uri, collection_name, field, value): + with pymongo.MongoClient(mongodb_uri) as mongo_client: + collection = mongo_client.get_default_database()[collection_name] + return 0 != collection.count_documents({field: value}) + + def cancel_job_except_reducer(job: SearchJob): """ Cancels the job apart from releasing the reducer since that requires an async call. @@ -282,7 +397,7 @@ def get_archives_for_search( return archives_for_search -def get_archive_and_file_split_ids_for_extraction( +def get_archive_and_file_split_ids_for_ir_extraction( db_conn, extract_ir_config: ExtractIrJobConfig, ) -> Tuple[Optional[str], Optional[str]]: @@ -333,6 +448,23 @@ def get_archive_and_file_split_ids( return results +@exception_default_value(default=False) +def archive_exists( + db_conn, + archive_id: str, +) -> bool: + query = f"""SELECT 1 + FROM {CLP_METADATA_TABLE_PREFIX}archives WHERE + id = %s + """ + with contextlib.closing(db_conn.cursor(dictionary=True)) as cursor: + cursor.execute(query, (archive_id,)) + if cursor.fetchone(): + return True + + return False + + def get_task_group_for_job( archive_ids: List[str], task_ids: List[int], @@ -340,7 +472,7 @@ def get_task_group_for_job( clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, ): - job_config_obj = job.get_config().dict() + job_config = job.get_config().dict() job_type = job.get_type() if QueryJobType.SEARCH_OR_AGGREGATION == job_type: return celery.group( @@ -348,19 +480,19 @@ def get_task_group_for_job( job_id=job.id, archive_id=archive_ids[i], task_id=task_ids[i], - job_config_obj=job_config_obj, + job_config=job_config, clp_metadata_db_conn_params=clp_metadata_db_conn_params, results_cache_uri=results_cache_uri, ) for i in range(len(archive_ids)) ) - elif QueryJobType.EXTRACT_IR == job_type: + elif job_type in (QueryJobType.EXTRACT_JSON, QueryJobType.EXTRACT_IR): return celery.group( - extract_ir.s( + extract_stream.s( job_id=job.id, archive_id=archive_ids[i], task_id=task_ids[i], - job_config_obj=job_config_obj, + job_config=job_config, clp_metadata_db_conn_params=clp_metadata_db_conn_params, results_cache_uri=results_cache_uri, ) @@ -466,11 +598,10 @@ def handle_pending_query_jobs( db_conn_pool, clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, - ir_collection_name: str, + stream_collection_name: str, num_archives_to_search_per_sub_job: int, ) -> List[asyncio.Task]: global active_jobs - global active_file_split_ir_extractions reducer_acquisition_tasks = [] pending_search_jobs = [ @@ -484,14 +615,14 @@ def handle_pending_query_jobs( for job in fetch_new_query_jobs(db_conn): job_id = str(job["job_id"]) job_type = job["type"] - job_config = job["job_config"] + job_config = msgpack.unpackb(job["job_config"]) if QueryJobType.SEARCH_OR_AGGREGATION == job_type: # Avoid double-dispatch when a job is WAITING_FOR_REDUCER if job_id in active_jobs: continue - search_config = SearchJobConfig.parse_obj(msgpack.unpackb(job_config)) + search_config = SearchJobConfig.parse_obj(job_config) archives_for_search = get_archives_for_search(db_conn, search_config) if len(archives_for_search) == 0: if set_job_or_task_status( @@ -527,12 +658,15 @@ def handle_pending_query_jobs( pending_search_jobs.append(new_search_job) active_jobs[job_id] = new_search_job - elif QueryJobType.EXTRACT_IR == job_type: - extract_ir_config = ExtractIrJobConfig.parse_obj(msgpack.unpackb(job_config)) - archive_id, file_split_id = get_archive_and_file_split_ids_for_extraction( - db_conn, extract_ir_config - ) - if not archive_id or not file_split_id: + elif job_type in (QueryJobType.EXTRACT_IR, QueryJobType.EXTRACT_JSON): + job_handle: StreamExtractionHandle + try: + if QueryJobType.EXTRACT_IR == job_type: + job_handle = IrExtractionHandle(job_id, job_config, db_conn) + else: + job_handle = JsonExtractionHandle(job_id, job_config, db_conn) + except ValueError: + logger.exception("Failed to initialize extraction job handle") if not set_job_or_task_status( db_conn, QUERY_JOBS_TABLE_NAME, @@ -546,19 +680,29 @@ def handle_pending_query_jobs( logger.error(f"Failed to set job {job_id} as failed") continue - # NOTE: The following two if blocks should not be reordered since if we first check - # whether *an* IR file has been extracted for the requested file split, it doesn't - # mean that *all* IR files have has been extracted for the file split (since the - # extraction job may still be in progress). Thus, we must first check whether the - # file split is in the process of being extracted, and then check whether it's - # already been extracted. - - # Check if the file split is currently being extracted; if so, add the job ID to the - # list of jobs waiting for it. - if file_split_id in active_file_split_ir_extractions: - active_file_split_ir_extractions[file_split_id].append(job_id) + # NOTE: The following two if blocks for `is_stream_extraction_active` and + # `is_stream_extracted` should not be reordered. + # + # The logic below works as follows: + # 1. It checks if a stream is already being extracted + # (`is_stream_extraction_active`) and if so, it marks the new job as waiting for + # the old job to finish. + # 2. Otherwise, it checks if a stream has already been extracted + # (`is_stream_extracted`) and if so, it marks the new job as complete. + # 3. Otherwise, it creates a new stream extraction job. + # + # `is_stream_extracted` only checks if a single stream has been extracted rather + # than whether all required streams have been extracted. This means that we can't + # use it to check if the old job is complete; instead, we need to employ the + # aforementioned logic. + + # Check if the required streams are currently being extracted; if so, add the job ID + # to the list of jobs waiting for it. + if job_handle.is_stream_extraction_active(): + job_handle.mark_job_as_waiting() logger.info( - f"Split {file_split_id} is being extracted, so mark job {job_id} as running" + f"Stream {job_handle.get_stream_id()} is already being extracted," + f" so mark job {job_id} as running." ) if not set_job_or_task_status( db_conn, @@ -572,12 +716,11 @@ def handle_pending_query_jobs( logger.error(f"Failed to set job {job_id} as running") continue - # Check if the file split has already been extracted - if ir_file_exists_for_file_split( - results_cache_uri, ir_collection_name, file_split_id - ): + # Check if a required stream file has already been extracted + if job_handle.is_stream_extracted(results_cache_uri, stream_collection_name): logger.info( - f"Split {file_split_id} already extracted, so mark job {job_id} as done" + f"Stream {job_handle.get_stream_id()} already extracted," + f" so mark job {job_id} as succeeded." ) if not set_job_or_task_status( db_conn, @@ -592,27 +735,20 @@ def handle_pending_query_jobs( logger.error(f"Failed to set job {job_id} as succeeded") continue - active_file_split_ir_extractions[file_split_id] = [job_id] - extract_ir_config.file_split_id = file_split_id - new_extract_ir_job = ExtractIrJob( - id=job_id, - archive_id=archive_id, - file_split_id=file_split_id, - extract_ir_config=extract_ir_config, - state=InternalJobState.WAITING_FOR_DISPATCH, - ) - target_archive = [new_extract_ir_job.archive_id] - + new_stream_extraction_job = job_handle.create_stream_extraction_job() + archive_id = job_handle.get_archive_id() dispatch_job_and_update_db( db_conn, - new_extract_ir_job, - target_archive, + new_stream_extraction_job, + [archive_id], clp_metadata_db_conn_params, results_cache_uri, 1, ) - active_jobs[new_extract_ir_job.id] = new_extract_ir_job - logger.info(f"Dispatched IR extraction job {job_id} on archive: {archive_id}") + + job_handle.mark_job_as_waiting() + active_jobs[job_id] = new_stream_extraction_job + logger.info(f"Dispatched stream extraction job {job_id} for archive: {archive_id}") else: # NOTE: We're skipping the job for this iteration, but its status will remain @@ -685,15 +821,6 @@ def found_max_num_latest_results( return max_timestamp_in_remaining_archives <= min_timestamp_in_top_results -def ir_file_exists_for_file_split( - results_cache_uri: str, ir_collection_name: str, file_split_id: str -): - with pymongo.MongoClient(results_cache_uri) as results_cache_client: - ir_collection = results_cache_client.get_default_database()[ir_collection_name] - results_count = ir_collection.count_documents({"file_split_id": file_split_id}) - return 0 != results_count - - async def handle_finished_search_job( db_conn, job: SearchJob, task_results: Optional[Any], results_cache_uri: str ) -> None: @@ -780,19 +907,20 @@ async def handle_finished_search_job( del active_jobs[job_id] -async def handle_finished_extract_ir_job( - db_conn, job: ExtractIrJob, task_results: Optional[Any] +async def handle_finished_stream_extraction_job( + db_conn, job: QueryJob, task_results: List[Any] ) -> None: global active_jobs + global active_archive_json_extractions global active_file_split_ir_extractions job_id = job.id - file_split_id = job.file_split_id new_job_status = QueryJobStatus.SUCCEEDED + num_tasks = len(task_results) if 1 != num_tasks: logger.error( - f"Unexpected number of tasks for IR extraction job {job_id}. " + f"Unexpected number of tasks for extraction job {job_id}. " f"Expected 1, got {num_tasks}." ) new_job_status = QueryJobStatus.FAILED @@ -801,13 +929,13 @@ async def handle_finished_extract_ir_job( task_id = task_result.task_id if not QueryJobStatus.SUCCEEDED == task_result.status: logger.error( - f"IR extraction task job-{job_id}-task-{task_id} failed. " + f"Extraction task job-{job_id}-task-{task_id} failed. " f"Check {task_result.error_log_path} for details." ) new_job_status = QueryJobStatus.FAILED else: logger.info( - f"IR extraction task job-{job_id}-task-{task_id} succeeded in " + f"Extraction task job-{job_id}-task-{task_id} succeeded in " f"{task_result.duration} second(s)." ) @@ -821,11 +949,18 @@ async def handle_finished_extract_ir_job( duration=(datetime.datetime.now() - job.start_time).total_seconds(), ): if new_job_status == QueryJobStatus.SUCCEEDED: - logger.info(f"Completed IR extraction job {job_id}.") + logger.info(f"Completed stream extraction job {job_id}.") else: - logger.info(f"Completed IR extraction job {job_id} with failing tasks.") + logger.info(f"Completed stream extraction job {job_id} with failing tasks.") + + waiting_jobs: List[str] + if QueryJobType.EXTRACT_IR == job.get_type(): + extract_ir_config: ExtractIrJobConfig = job.get_config() + waiting_jobs = active_file_split_ir_extractions.pop(extract_ir_config.file_split_id) + else: + extract_json_config: ExtractJsonJobConfig = job.get_config() + waiting_jobs = active_archive_json_extractions.pop(extract_json_config.archive_id) - waiting_jobs = active_file_split_ir_extractions[file_split_id] waiting_jobs.remove(job_id) for waiting_job in waiting_jobs: logger.info(f"Setting status to {new_job_status.to_str()} for waiting jobs: {waiting_job}.") @@ -839,7 +974,6 @@ async def handle_finished_extract_ir_job( duration=(datetime.datetime.now() - job.start_time).total_seconds(), ) - del active_file_split_ir_extractions[file_split_id] del active_jobs[job_id] @@ -880,9 +1014,8 @@ async def check_job_status_and_update_db(db_conn_pool, results_cache_uri): await handle_finished_search_job( db_conn, search_job, returned_results, results_cache_uri ) - elif QueryJobType.EXTRACT_IR == job_type: - extract_ir_job: ExtractIrJob = job - await handle_finished_extract_ir_job(db_conn, extract_ir_job, returned_results) + elif job_type in (QueryJobType.EXTRACT_JSON, QueryJobType.EXTRACT_IR): + await handle_finished_stream_extraction_job(db_conn, job, returned_results) else: logger.error(f"Unexpected job type: {job_type}, skipping job {job_id}") @@ -898,7 +1031,7 @@ async def handle_jobs( db_conn_pool, clp_metadata_db_conn_params: Dict[str, any], results_cache_uri: str, - ir_collection_name: str, + stream_collection_name: str, jobs_poll_delay: float, num_archives_to_search_per_sub_job: int, ) -> None: @@ -912,7 +1045,7 @@ async def handle_jobs( db_conn_pool, clp_metadata_db_conn_params, results_cache_uri, - ir_collection_name, + stream_collection_name, num_archives_to_search_per_sub_job, ) if 0 == len(reducer_acquisition_tasks): @@ -996,7 +1129,7 @@ async def main(argv: List[str]) -> int: True ), results_cache_uri=clp_config.results_cache.get_uri(), - ir_collection_name=clp_config.results_cache.ir_collection_name, + stream_collection_name=clp_config.results_cache.stream_collection_name, jobs_poll_delay=clp_config.query_scheduler.jobs_poll_delay, num_archives_to_search_per_sub_job=batch_size, ) diff --git a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py index 5ef92a5d6..4f49a7c1a 100644 --- a/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py +++ b/components/job-orchestration/job_orchestration/scheduler/scheduler_data.py @@ -11,6 +11,7 @@ ) from job_orchestration.scheduler.job_config import ( ExtractIrJobConfig, + ExtractJsonJobConfig, QueryJobConfig, SearchJobConfig, ) @@ -59,8 +60,6 @@ def get_config(self) -> QueryJobConfig: ... class ExtractIrJob(QueryJob): extract_ir_config: ExtractIrJobConfig - file_split_id: str - archive_id: str def get_type(self) -> QueryJobType: return QueryJobType.EXTRACT_IR @@ -69,6 +68,16 @@ def get_config(self) -> QueryJobConfig: return self.extract_ir_config +class ExtractJsonJob(QueryJob): + extract_json_config: ExtractJsonJobConfig + + def get_type(self) -> QueryJobType: + return QueryJobType.EXTRACT_JSON + + def get_config(self) -> QueryJobConfig: + return self.extract_json_config + + class SearchJob(QueryJob): search_config: SearchJobConfig num_archives_to_search: int diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx index c1ad9eb9e..c1bb639a6 100644 --- a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -51,7 +51,7 @@ const QueryStatus = () => { setQueryState(QUERY_LOADING_STATES.LOADING); const innerLogEventNum = logEventIdx - data.begin_msg_ix + 1; - window.location = `/log-viewer/index.html?filePath=/ir/${data.path}` + + window.location = `/log-viewer/index.html?filePath=/streams/${data.path}` + `#logEventNum=${innerLogEventNum}`; }) .catch((e) => { diff --git a/components/log-viewer-webui/server/.env b/components/log-viewer-webui/server/.env index b66dc997b..95e3054a8 100644 --- a/components/log-viewer-webui/server/.env +++ b/components/log-viewer-webui/server/.env @@ -1,5 +1,5 @@ CLIENT_DIR=../client/dist -IR_DATA_DIR=../../../build/clp-package/var/data/ir +STREAMS_DATA_DIR=../../../build/clp-package/var/data/streams LOG_VIEWER_DIR=../yscope-log-viewer/dist HOST=localhost diff --git a/components/log-viewer-webui/server/settings.json b/components/log-viewer-webui/server/settings.json index bb1aac48a..163f9a9e2 100644 --- a/components/log-viewer-webui/server/settings.json +++ b/components/log-viewer-webui/server/settings.json @@ -6,9 +6,9 @@ "MongoDbHost": "localhost", "MongoDbPort": 27017, "MongoDbName": "clp-query-results", - "MongoDbIrFilesCollectionName": "ir-files", + "MongoDbStreamFilesCollectionName": "stream-files", "ClientDir": "../client/dist", - "IrFilesDir": "../../../build/clp-package/var/data/ir", + "StreamFilesDir": "../../../build/clp-package/var/data/streams", "LogViewerDir": "../yscope-log-viewer/dist" } diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js index 5cb442795..79e097280 100644 --- a/components/log-viewer-webui/server/src/DbManager.js +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -84,7 +84,7 @@ class DbManager { /** * @type {import("mongodb").Collection} */ - #irFilesCollection; + #streamFilesCollection; #queryJobsTableName; @@ -138,7 +138,7 @@ class DbManager { * @return {Promise} A promise that resolves to the extracted IR file's metadata. */ async getExtractedIrFileMetadata (origFileId, logEventIdx) { - return await this.#irFilesCollection.findOne({ + return await this.#streamFilesCollection.findOne({ orig_file_id: origFileId, begin_msg_ix: {$lte: logEventIdx}, end_msg_ix: {$gt: logEventIdx}, @@ -177,7 +177,7 @@ class DbManager { * @param {string} config.host * @param {number} config.port * @param {string} config.database - * @param {string} config.irFilesCollectionName + * @param {string} config.StreamFilesCollectionName */ #initMongo (config) { this.#fastify.register(fastifyMongo, { @@ -187,8 +187,8 @@ class DbManager { if (err) { throw err; } - this.#irFilesCollection = - this.#fastify.mongo.db.collection(config.irFilesCollectionName); + this.#streamFilesCollection = + this.#fastify.mongo.db.collection(config.streamFilesCollectionName); }); } diff --git a/components/log-viewer-webui/server/src/app.js b/components/log-viewer-webui/server/src/app.js index 69918ea58..5d351fd39 100644 --- a/components/log-viewer-webui/server/src/app.js +++ b/components/log-viewer-webui/server/src/app.js @@ -37,7 +37,7 @@ const app = async ({ mongoConfig: { database: settings.MongoDbName, host: settings.MongoDbHost, - irFilesCollectionName: settings.MongoDbIrFilesCollectionName, + streamFilesCollectionName: settings.MongoDbStreamFilesCollectionName, port: settings.MongoDbPort, }, }); diff --git a/components/log-viewer-webui/server/src/routes/static.js b/components/log-viewer-webui/server/src/routes/static.js index 42d9048f0..6118c2855 100644 --- a/components/log-viewer-webui/server/src/routes/static.js +++ b/components/log-viewer-webui/server/src/routes/static.js @@ -18,13 +18,13 @@ const routes = async (fastify, options) => { const dirname = path.dirname(filename); const rootDirname = path.resolve(dirname, "../.."); - let irFilesDir = settings.IrFilesDir; - if (false === path.isAbsolute(irFilesDir)) { - irFilesDir = path.resolve(rootDirname, irFilesDir); + let streamFilesDir = settings.StreamFilesDir; + if (false === path.isAbsolute(streamFilesDir)) { + streamFilesDir = path.resolve(rootDirname, streamFilesDir); } await fastify.register(fastifyStatic, { - prefix: "/ir", - root: irFilesDir, + prefix: "/streams", + root: streamFilesDir, }); let logViewerDir = settings.LogViewerDir; diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index cb66f40cd..15747fe42 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -47,7 +47,7 @@ # host: "localhost" # port: 27017 # db_name: "clp-query-results" -# ir_collection_name: "ir-files" +# stream_collection_name: "stream-files" # #compression_worker: # logging_level: "INFO" @@ -82,9 +82,9 @@ # # How much data CLP should try to fit into each segment within an archive # target_segment_size: 268435456 # 256 MB # -## Where CLP IR files should be output -#ir_output: -# directory: "var/data/ir" +## Where CLP stream files (e.g., IR streams) should be output +#stream_output: +# directory: "var/data/streams" # # # How large each IR file should be before being split into a new IR file # target_uncompressed_size: 134217728 # 128 MB From 12a5f8dfcb6cd7d83d9bc0b12cafed0efd6ae9fb Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Tue, 19 Nov 2024 11:02:58 -0500 Subject: [PATCH 105/114] feat(clp-s): Record log-order at compression time. (#584) Co-authored-by: wraymo <37269683+wraymo@users.noreply.github.com> --- components/core/src/clp_s/ArchiveReader.cpp | 9 +++ components/core/src/clp_s/ArchiveReader.hpp | 6 ++ components/core/src/clp_s/ArchiveWriter.cpp | 2 + components/core/src/clp_s/ArchiveWriter.hpp | 9 ++- .../core/src/clp_s/CommandLineArguments.cpp | 8 ++- .../core/src/clp_s/CommandLineArguments.hpp | 3 + components/core/src/clp_s/JsonConstructor.cpp | 28 +++++--- components/core/src/clp_s/JsonConstructor.hpp | 2 +- components/core/src/clp_s/JsonParser.cpp | 34 ++++++++- components/core/src/clp_s/JsonParser.hpp | 23 +++++-- components/core/src/clp_s/JsonSerializer.hpp | 7 +- components/core/src/clp_s/ReaderUtils.cpp | 2 +- components/core/src/clp_s/SchemaReader.cpp | 23 +++++-- components/core/src/clp_s/SchemaReader.hpp | 21 +++++- components/core/src/clp_s/SchemaTree.cpp | 39 ++++++++--- components/core/src/clp_s/SchemaTree.hpp | 69 ++++++++++++++++--- .../core/src/clp_s/archive_constants.hpp | 16 +++++ components/core/src/clp_s/clp-s.cpp | 1 + .../src/clp_s/search/ColumnDescriptor.hpp | 3 +- components/core/src/clp_s/search/Output.cpp | 28 +++++++- components/core/src/clp_s/search/Output.hpp | 7 ++ .../core/src/clp_s/search/OutputHandler.cpp | 55 +++++++++++---- .../core/src/clp_s/search/OutputHandler.hpp | 62 ++++++++++++----- .../core/src/clp_s/search/Projection.cpp | 2 +- .../core/src/clp_s/search/SchemaMatch.cpp | 8 +-- .../core/src/clp_s/search/SearchUtils.cpp | 1 + 26 files changed, 377 insertions(+), 91 deletions(-) diff --git a/components/core/src/clp_s/ArchiveReader.cpp b/components/core/src/clp_s/ArchiveReader.cpp index 5362d32cc..7c68b301d 100644 --- a/components/core/src/clp_s/ArchiveReader.cpp +++ b/components/core/src/clp_s/ArchiveReader.cpp @@ -27,6 +27,8 @@ void ArchiveReader::open(string_view archives_dir, string_view archive_id) { m_schema_tree = ReaderUtils::read_schema_tree(archive_path_str); m_schema_map = ReaderUtils::read_schemas(archive_path_str); + m_log_event_idx_column_id = m_schema_tree->get_metadata_field_id(constants::cLogEventIdxName); + m_table_metadata_file_reader.open(archive_path_str + constants::cArchiveTableMetadataFile); m_stream_reader.open_packed_streams(archive_path_str + constants::cArchiveTablesFile); } @@ -310,6 +312,12 @@ void ArchiveReader::initialize_schema_reader( } BaseColumnReader* column_reader = append_reader_column(reader, column_id); + if (column_id == m_log_event_idx_column_id + && nullptr != dynamic_cast(column_reader)) + { + reader.mark_column_as_log_event_idx(static_cast(column_reader)); + } + if (should_extract_timestamp && column_reader && timestamp_column_ids.count(column_id) > 0) { reader.mark_column_as_timestamp(column_reader); @@ -346,6 +354,7 @@ void ArchiveReader::close() { m_cur_stream_id = 0; m_stream_buffer.reset(); m_stream_buffer_size = 0ULL; + m_log_event_idx_column_id = -1; } std::shared_ptr ArchiveReader::read_stream(size_t stream_id, bool reuse_buffer) { diff --git a/components/core/src/clp_s/ArchiveReader.hpp b/components/core/src/clp_s/ArchiveReader.hpp index 41073ec84..6b437dfd2 100644 --- a/components/core/src/clp_s/ArchiveReader.hpp +++ b/components/core/src/clp_s/ArchiveReader.hpp @@ -142,6 +142,11 @@ class ArchiveReader { m_projection = projection; } + /** + * @return true if this archive has log ordering information, and false otherwise. + */ + bool has_log_order() { return m_log_event_idx_column_id >= 0; } + private: /** * Initializes a schema reader passed by reference to become a reader for a given schema. @@ -214,6 +219,7 @@ class ArchiveReader { std::shared_ptr m_stream_buffer{}; size_t m_stream_buffer_size{0ULL}; size_t m_cur_stream_id{0ULL}; + int32_t m_log_event_idx_column_id{-1}; }; } // namespace clp_s diff --git a/components/core/src/clp_s/ArchiveWriter.cpp b/components/core/src/clp_s/ArchiveWriter.cpp index 369fd79d2..7118ce88b 100644 --- a/components/core/src/clp_s/ArchiveWriter.cpp +++ b/components/core/src/clp_s/ArchiveWriter.cpp @@ -68,6 +68,7 @@ void ArchiveWriter::close() { m_encoded_message_size = 0UL; m_uncompressed_size = 0UL; m_compressed_size = 0UL; + m_next_log_event_id = 0; } void ArchiveWriter::append_message( @@ -86,6 +87,7 @@ void ArchiveWriter::append_message( } m_encoded_message_size += schema_writer->append_message(message); + ++m_next_log_event_id; } size_t ArchiveWriter::get_data_size() { diff --git a/components/core/src/clp_s/ArchiveWriter.hpp b/components/core/src/clp_s/ArchiveWriter.hpp index 7edfe4491..87e9d11e5 100644 --- a/components/core/src/clp_s/ArchiveWriter.hpp +++ b/components/core/src/clp_s/ArchiveWriter.hpp @@ -1,6 +1,7 @@ #ifndef CLP_S_ARCHIVEWRITER_HPP #define CLP_S_ARCHIVEWRITER_HPP +#include #include #include @@ -93,10 +94,15 @@ class ArchiveWriter { * @param key * @return the node id */ - int32_t add_node(int parent_node_id, NodeType type, std::string const& key) { + int32_t add_node(int parent_node_id, NodeType type, std::string_view const key) { return m_schema_tree.add_node(parent_node_id, type, key); } + /** + * @return The Id that will be assigned to the next log event when appended to the archive. + */ + int64_t get_next_log_event_id() const { return m_next_log_event_id; } + /** * Return a schema's Id and add the schema to the * schema map if it does not already exist. @@ -174,6 +180,7 @@ class ArchiveWriter { size_t m_encoded_message_size{}; size_t m_uncompressed_size{}; size_t m_compressed_size{}; + int64_t m_next_log_event_id{}; std::string m_id; diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index cf69a066c..ace505788 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -194,6 +194,10 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { "structurize-arrays", po::bool_switch(&m_structurize_arrays), "Structurize arrays instead of compressing them as clp strings." + )( + "disable-log-order", + po::bool_switch(&m_disable_log_order), + "Do not record log order at ingestion time." ); // clang-format on @@ -296,13 +300,13 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { decompression_options.add_options()( "ordered", po::bool_switch(&m_ordered_decompression), - "Enable decompression in ascending timestamp order for this archive" + "Enable decompression in log order for this archive" )( "ordered-chunk-size", po::value(&m_ordered_chunk_size) ->default_value(m_ordered_chunk_size), "Number of records to include in each output file when decompressing records " - "in ascending timestamp order" + "in log order" ); // clang-format on extraction_options.add(decompression_options); diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 798e42728..8f2d79d8f 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -112,6 +112,8 @@ class CommandLineArguments { std::vector const& get_projection_columns() const { return m_projection_columns; } + bool get_record_log_order() const { return false == m_disable_log_order; } + private: // Methods /** @@ -178,6 +180,7 @@ class CommandLineArguments { bool m_ordered_decompression{false}; size_t m_ordered_chunk_size{0}; size_t m_minimum_table_size{1ULL * 1024 * 1024}; // 1 MB + bool m_disable_log_order{false}; // Metadata db variables std::optional m_metadata_db_config; diff --git a/components/core/src/clp_s/JsonConstructor.cpp b/components/core/src/clp_s/JsonConstructor.cpp index 90887f1e5..0c816c5e3 100644 --- a/components/core/src/clp_s/JsonConstructor.cpp +++ b/components/core/src/clp_s/JsonConstructor.cpp @@ -48,7 +48,13 @@ void JsonConstructor::store() { m_archive_reader = std::make_unique(); m_archive_reader->open(m_option.archives_dir, m_option.archive_id); m_archive_reader->read_dictionaries_and_metadata(); - if (false == m_option.ordered) { + + if (m_option.ordered && false == m_archive_reader->has_log_order()) { + SPDLOG_WARN("This archive is missing ordering information and can not be decompressed in " + "log order. Falling back to out of order decompression."); + } + + if (false == m_option.ordered || false == m_archive_reader->has_log_order()) { FileWriter writer; writer.open( m_option.output_dir + "/original", @@ -68,15 +74,15 @@ void JsonConstructor::construct_in_order() { auto tables = m_archive_reader->read_all_tables(); using ReaderPointer = std::shared_ptr; auto cmp = [](ReaderPointer& left, ReaderPointer& right) { - return left->get_next_timestamp() > right->get_next_timestamp(); + return left->get_next_log_event_idx() > right->get_next_log_event_idx(); }; std::priority_queue record_queue(tables.begin(), tables.end(), cmp); // Clear tables vector so that memory gets deallocated after we have marshalled all records for // a given table tables.clear(); - epochtime_t first_timestamp{0}; - epochtime_t last_timestamp{0}; + int64_t first_idx{0}; + int64_t last_idx{0}; size_t num_records_marshalled{0}; auto src_path = std::filesystem::path(m_option.output_dir) / m_option.archive_id; FileWriter writer; @@ -97,9 +103,11 @@ void JsonConstructor::construct_in_order() { std::vector results; auto finalize_chunk = [&](bool open_new_writer) { + // Add one to last_idx to match clp's behaviour of having the end index be exclusive + ++last_idx; writer.close(); - std::string new_file_name = src_path.string() + "_" + std::to_string(first_timestamp) + "_" - + std::to_string(last_timestamp) + ".jsonl"; + std::string new_file_name = src_path.string() + "_" + std::to_string(first_idx) + "_" + + std::to_string(last_idx) + ".jsonl"; auto new_file_path = std::filesystem::path(new_file_name); std::error_code ec; std::filesystem::rename(src_path, new_file_path, ec); @@ -119,11 +127,11 @@ void JsonConstructor::construct_in_order() { ), bsoncxx::builder::basic::kvp( constants::results_cache::decompression::cBeginMsgIx, - static_cast(first_timestamp) + first_idx ), bsoncxx::builder::basic::kvp( constants::results_cache::decompression::cEndMsgIx, - static_cast(last_timestamp) + last_idx ), bsoncxx::builder::basic::kvp( constants::results_cache::decompression::cIsLastIrChunk, @@ -140,9 +148,9 @@ void JsonConstructor::construct_in_order() { while (false == record_queue.empty()) { ReaderPointer next = record_queue.top(); record_queue.pop(); - last_timestamp = next->get_next_timestamp(); + last_idx = next->get_next_log_event_idx(); if (0 == num_records_marshalled) { - first_timestamp = last_timestamp; + first_idx = last_idx; } next->get_next_message(buffer); if (false == next->done()) { diff --git a/components/core/src/clp_s/JsonConstructor.hpp b/components/core/src/clp_s/JsonConstructor.hpp index f1f71f9d8..c38e6d00b 100644 --- a/components/core/src/clp_s/JsonConstructor.hpp +++ b/components/core/src/clp_s/JsonConstructor.hpp @@ -66,7 +66,7 @@ class JsonConstructor { private: /** * Reads all of the tables from m_archive_reader and writes all of the records - * they contain to writer in timestamp order. + * they contain to writer in log order. */ void construct_in_order(); diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index 5336c367a..9e8293510 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -15,7 +15,8 @@ JsonParser::JsonParser(JsonParserOption const& option) m_target_encoded_size(option.target_encoded_size), m_max_document_size(option.max_document_size), m_timestamp_key(option.timestamp_key), - m_structurize_arrays(option.structurize_arrays) { + m_structurize_arrays(option.structurize_arrays), + m_record_log_order(option.record_log_order) { if (false == FileUtils::validate_path(option.file_paths)) { exit(1); } @@ -447,6 +448,16 @@ bool JsonParser::parse() { m_num_messages = 0; size_t bytes_consumed_up_to_prev_archive = 0; size_t bytes_consumed_up_to_prev_record = 0; + + int32_t log_event_idx_node_id{}; + auto add_log_event_idx_node = [&]() { + if (m_record_log_order) { + log_event_idx_node_id + = add_metadata_field(constants::cLogEventIdxName, NodeType::Integer); + } + }; + add_log_event_idx_node(); + while (json_file_iterator.get_json(json_it)) { m_current_schema.clear(); @@ -467,11 +478,20 @@ bool JsonParser::parse() { return false; } + // Add log_event_idx field to metadata for record + if (m_record_log_order) { + m_current_parsed_message.add_value( + log_event_idx_node_id, + m_archive_writer->get_next_log_event_id() + ); + m_current_schema.insert_ordered(log_event_idx_node_id); + } + // Some errors from simdjson are latent until trying to access invalid JSON fields. // Instead of checking for an error every time we access a JSON field in parse_line we // just catch simdjson_error here instead. try { - parse_line(ref.value(), -1, ""); + parse_line(ref.value(), constants::cRootNodeId, constants::cRootNodeName); } catch (simdjson::simdjson_error& error) { SPDLOG_ERROR( "Encountered error - {} - while trying to parse {} after parsing {} bytes", @@ -496,6 +516,7 @@ bool JsonParser::parse() { ); bytes_consumed_up_to_prev_archive = bytes_consumed_up_to_prev_record; split_archive(); + add_log_event_idx_node(); } m_current_parsed_message.clear(); @@ -526,6 +547,15 @@ bool JsonParser::parse() { return true; } +int32_t JsonParser::add_metadata_field(std::string_view const field_name, NodeType type) { + auto metadata_subtree_id = m_archive_writer->add_node( + constants::cRootNodeId, + NodeType::Metadata, + constants::cMetadataSubtreeName + ); + return m_archive_writer->add_node(metadata_subtree_id, type, field_name); +} + void JsonParser::store() { m_archive_writer->close(); } diff --git a/components/core/src/clp_s/JsonParser.hpp b/components/core/src/clp_s/JsonParser.hpp index af6b024ef..d7cc5a2fe 100644 --- a/components/core/src/clp_s/JsonParser.hpp +++ b/components/core/src/clp_s/JsonParser.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -30,12 +31,13 @@ struct JsonParserOption { std::vector file_paths; std::string timestamp_key; std::string archives_dir; - size_t target_encoded_size; - size_t max_document_size; - size_t min_table_size; - int compression_level; - bool print_archive_stats; - bool structurize_arrays; + size_t target_encoded_size{}; + size_t max_document_size{}; + size_t min_table_size{}; + int compression_level{}; + bool print_archive_stats{}; + bool structurize_arrays{}; + bool record_log_order{true}; std::shared_ptr metadata_db; }; @@ -94,6 +96,14 @@ class JsonParser { */ void split_archive(); + /** + * Adds an internal field to the MPT and get its Id. + * + * Note: this method should be called before parsing a record so that internal fields come first + * in each table. This isn't strictly necessary, but it is a nice convention. + */ + int32_t add_metadata_field(std::string_view const field_name, NodeType type); + int m_num_messages; std::vector m_file_paths; @@ -109,6 +119,7 @@ class JsonParser { size_t m_target_encoded_size; size_t m_max_document_size; bool m_structurize_arrays{false}; + bool m_record_log_order{true}; }; } // namespace clp_s diff --git a/components/core/src/clp_s/JsonSerializer.hpp b/components/core/src/clp_s/JsonSerializer.hpp index ff46dfa24..63f845525 100644 --- a/components/core/src/clp_s/JsonSerializer.hpp +++ b/components/core/src/clp_s/JsonSerializer.hpp @@ -2,6 +2,7 @@ #define CLP_S_JSONSERIALIZER_HPP #include +#include #include #include "ColumnReader.hpp" @@ -66,7 +67,7 @@ class JsonSerializer { return false; } - void add_special_key(std::string const& key) { m_special_keys.push_back(key); } + void add_special_key(std::string_view const key) { m_special_keys.emplace_back(key); } void begin_object() { append_key(); @@ -110,13 +111,13 @@ class JsonSerializer { void append_key() { append_key(m_special_keys[m_special_keys_index++]); } - void append_key(std::string const& key) { + void append_key(std::string_view const key) { m_json_string += "\""; m_json_string += key; m_json_string += "\":"; } - void append_value(std::string const& value) { + void append_value(std::string_view const value) { m_json_string += value; m_json_string += ","; } diff --git a/components/core/src/clp_s/ReaderUtils.cpp b/components/core/src/clp_s/ReaderUtils.cpp index 11583a60d..a2ab5a34a 100644 --- a/components/core/src/clp_s/ReaderUtils.cpp +++ b/components/core/src/clp_s/ReaderUtils.cpp @@ -18,10 +18,10 @@ std::shared_ptr ReaderUtils::read_schema_tree(std::string const& arc throw OperationFailed(error_code, __FILENAME__, __LINE__); } + std::string key; for (size_t i = 0; i < num_nodes; i++) { int32_t parent_id; size_t key_length; - std::string key; uint8_t node_type; error_code = schema_tree_decompressor.try_read_numeric_value(parent_id); diff --git a/components/core/src/clp_s/SchemaReader.cpp b/components/core/src/clp_s/SchemaReader.cpp index 35c1d0a6e..8120ab323 100644 --- a/components/core/src/clp_s/SchemaReader.cpp +++ b/components/core/src/clp_s/SchemaReader.cpp @@ -37,6 +37,13 @@ void SchemaReader::mark_column_as_timestamp(BaseColumnReader* column_reader) { } } +int64_t SchemaReader::get_next_log_event_idx() const { + if (nullptr != m_log_event_idx_column) { + return std::get(m_log_event_idx_column->extract_value(m_cur_message)); + } + return 0; +} + void SchemaReader::load( std::shared_ptr stream_buffer, size_t offset, @@ -86,7 +93,7 @@ void SchemaReader::generate_json_string() { } case JsonSerializer::Op::AddIntField: { column = m_reordered_columns[column_id_index++]; - auto const& name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); + auto name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); m_json_serializer.append_key(name); m_json_serializer.append_value( std::to_string(std::get(column->extract_value(m_cur_message))) @@ -102,7 +109,7 @@ void SchemaReader::generate_json_string() { } case JsonSerializer::Op::AddFloatField: { column = m_reordered_columns[column_id_index++]; - auto const& name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); + auto name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); m_json_serializer.append_key(name); m_json_serializer.append_value( std::to_string(std::get(column->extract_value(m_cur_message))) @@ -118,7 +125,7 @@ void SchemaReader::generate_json_string() { } case JsonSerializer::Op::AddBoolField: { column = m_reordered_columns[column_id_index++]; - auto const& name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); + auto name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); m_json_serializer.append_key(name); m_json_serializer.append_value( std::get(column->extract_value(m_cur_message)) != 0 ? "true" @@ -136,7 +143,7 @@ void SchemaReader::generate_json_string() { } case JsonSerializer::Op::AddStringField: { column = m_reordered_columns[column_id_index++]; - auto const& name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); + auto name = m_global_schema_tree->get_node(column->get_id()).get_key_name(); m_json_serializer.append_key(name); m_json_serializer.append_value_from_column_with_quotes(column, m_cur_message); break; @@ -215,9 +222,10 @@ bool SchemaReader::get_next_message(std::string& message, FilterClass* filter) { return false; } -bool SchemaReader::get_next_message_with_timestamp( +bool SchemaReader::get_next_message_with_metadata( std::string& message, epochtime_t& timestamp, + int64_t& log_event_idx, FilterClass* filter ) { // TODO: If we already get max_num_results messages, we can skip messages @@ -241,6 +249,7 @@ bool SchemaReader::get_next_message_with_timestamp( } timestamp = m_get_timestamp(); + log_event_idx = get_next_log_event_idx(); m_cur_message++; return true; @@ -561,7 +570,7 @@ void SchemaReader::initialize_serializer() { // TODO: this code will have to change once we allow mixing log lines parsed by different // parsers. if (false == m_local_schema_tree.get_nodes().empty()) { - generate_json_template(m_local_schema_tree.get_root_node_id()); + generate_json_template(m_local_schema_tree.get_object_subtree_node_id()); } } @@ -572,7 +581,7 @@ void SchemaReader::generate_json_template(int32_t id) { for (int32_t child_id : children_ids) { int32_t child_global_id = m_local_id_to_global_id[child_id]; auto const& child_node = m_local_schema_tree.get_node(child_id); - std::string const& key = child_node.get_key_name(); + auto key = child_node.get_key_name(); switch (child_node.get_type()) { case NodeType::Object: { m_json_serializer.add_op(JsonSerializer::Op::BeginObject); diff --git a/components/core/src/clp_s/SchemaReader.hpp b/components/core/src/clp_s/SchemaReader.hpp index 08651cc39..75f9ff117 100644 --- a/components/core/src/clp_s/SchemaReader.hpp +++ b/components/core/src/clp_s/SchemaReader.hpp @@ -99,6 +99,7 @@ class SchemaReader { m_reordered_columns.clear(); m_timestamp_column = nullptr; m_get_timestamp = []() -> epochtime_t { return 0; }; + m_log_event_idx_column = nullptr; m_local_id_to_global_id.clear(); m_global_id_to_local_id.clear(); m_global_id_to_unordered_object.clear(); @@ -159,15 +160,17 @@ class SchemaReader { bool get_next_message(std::string& message, FilterClass* filter); /** - * Gets the next message matching a filter, and its timestamp + * Gets the next message matching a filter as well as its timestamp and log event index. * @param message * @param timestamp + * @param log_event_idx * @param filter * @return true if there is a next message */ - bool get_next_message_with_timestamp( + bool get_next_message_with_metadata( std::string& message, epochtime_t& timestamp, + int64_t& log_event_idx, FilterClass* filter ); @@ -183,6 +186,13 @@ class SchemaReader { */ void mark_column_as_timestamp(BaseColumnReader* column_reader); + /** + * Marks a column as the log_event_idx column. + */ + void mark_column_as_log_event_idx(Int64ColumnReader* column_reader) { + m_log_event_idx_column = column_reader; + } + int32_t get_schema_id() const { return m_schema_id; } /** @@ -197,6 +207,12 @@ class SchemaReader { */ epochtime_t get_next_timestamp() const { return m_get_timestamp(); } + /** + * @return the log_event_idx in the row pointed to by m_cur_message or 0 if there is no + * log_event_idx in this table. + */ + int64_t get_next_log_event_idx() const; + /** * @return true if all records in this table have been iterated over, false otherwise */ @@ -288,6 +304,7 @@ class SchemaReader { BaseColumnReader* m_timestamp_column; std::function m_get_timestamp; + Int64ColumnReader* m_log_event_idx_column{nullptr}; std::shared_ptr m_global_schema_tree; SchemaTree m_local_schema_tree; diff --git a/components/core/src/clp_s/SchemaTree.cpp b/components/core/src/clp_s/SchemaTree.cpp index e56168a2c..4408efc01 100644 --- a/components/core/src/clp_s/SchemaTree.cpp +++ b/components/core/src/clp_s/SchemaTree.cpp @@ -5,9 +5,8 @@ #include "ZstdCompressor.hpp" namespace clp_s { -int32_t SchemaTree::add_node(int32_t parent_node_id, NodeType type, std::string const& key) { - std::tuple node_key = {parent_node_id, key, type}; - auto node_it = m_node_map.find(node_key); +int32_t SchemaTree::add_node(int32_t parent_node_id, NodeType type, std::string_view const key) { + auto node_it = m_node_map.find({parent_node_id, key, type}); if (node_it != m_node_map.end()) { auto node_id = node_it->second; m_nodes[node_id].increase_count(); @@ -15,18 +14,42 @@ int32_t SchemaTree::add_node(int32_t parent_node_id, NodeType type, std::string } int32_t node_id = m_nodes.size(); - auto& node = m_nodes.emplace_back(parent_node_id, node_id, key, type, 0); + auto& node = m_nodes.emplace_back(parent_node_id, node_id, std::string{key}, type, 0); node.increase_count(); - if (parent_node_id >= 0) { + if (constants::cRootNodeId == parent_node_id) { + if (NodeType::Object == type) { + m_object_subtree_id = node_id; + } else if (NodeType::Metadata == type) { + m_metadata_subtree_id = node_id; + } + } + + if (constants::cRootNodeId != parent_node_id) { auto& parent_node = m_nodes[parent_node_id]; node.set_depth(parent_node.get_depth() + 1); parent_node.add_child(node_id); } - m_node_map[node_key] = node_id; + m_node_map.emplace(std::make_tuple(parent_node_id, node.get_key_name(), type), node_id); return node_id; } +int32_t SchemaTree::get_metadata_field_id(std::string_view const field_name) { + if (m_metadata_subtree_id < 0) { + return -1; + } + + auto& metadata_subtree_node = m_nodes[m_metadata_subtree_id]; + for (auto child_id : metadata_subtree_node.get_children_ids()) { + auto& child_node = m_nodes[child_id]; + if (child_node.get_key_name() == field_name) { + return child_id; + } + } + + return -1; +} + size_t SchemaTree::store(std::string const& archives_dir, int compression_level) { FileWriter schema_tree_writer; ZstdCompressor schema_tree_compressor; @@ -41,9 +64,9 @@ size_t SchemaTree::store(std::string const& archives_dir, int compression_level) for (auto const& node : m_nodes) { schema_tree_compressor.write_numeric_value(node.get_parent_id()); - std::string const& key = node.get_key_name(); + auto key = node.get_key_name(); schema_tree_compressor.write_numeric_value(key.size()); - schema_tree_compressor.write_string(key); + schema_tree_compressor.write(key.begin(), key.size()); schema_tree_compressor.write_numeric_value(node.get_type()); } diff --git a/components/core/src/clp_s/SchemaTree.hpp b/components/core/src/clp_s/SchemaTree.hpp index 05ed52935..438714fa2 100644 --- a/components/core/src/clp_s/SchemaTree.hpp +++ b/components/core/src/clp_s/SchemaTree.hpp @@ -5,11 +5,25 @@ #include #include #include +#include #include #include namespace clp_s { +/** + * This enum defines the valid MPT node types as well as the 8-bit number used to encode them. + * + * The number used to represent each node type can not change. That means that elements in this + * enum can never be reordered and that new node types always need to be added to the end of the + * enum (but before Unknown). + * + * Node types are used to help record the structure of a log record, with the exception of the + * "Metadata" node type. The "Metadata" type is a special type used by the implementation to + * demarcate data needed by the implementation that is not part of the log record. In particular, + * the implementation may create a special subtree of the MPT which contains fields used to record + * things like original log order. + */ enum class NodeType : uint8_t { Integer, Float, @@ -21,21 +35,37 @@ enum class NodeType : uint8_t { NullValue, DateString, StructuredArray, + Metadata, Unknown = std::underlying_type::type(~0ULL) }; +/** + * This class represents a single node in the SchemaTree. + * + * Note: the result of get_key_name is valid even if the original SchemaNode is later + * move-constructed. + */ class SchemaNode { public: // Constructor SchemaNode() : m_parent_id(-1), m_id(-1), m_type(NodeType::Integer), m_count(0) {} - SchemaNode(int32_t parent_id, int32_t id, std::string key_name, NodeType type, int32_t depth) + SchemaNode( + int32_t parent_id, + int32_t id, + std::string_view const key_name, + NodeType type, + int32_t depth + ) : m_parent_id(parent_id), m_id(id), - m_key_name(std::move(key_name)), + m_key_name_buf(std::make_unique(key_name.size())), + m_key_name(m_key_name_buf.get(), key_name.size()), m_type(type), m_count(0), - m_depth(depth) {} + m_depth(depth) { + memcpy(m_key_name_buf.get(), key_name.begin(), key_name.size()); + } /** * Getters @@ -48,7 +78,7 @@ class SchemaNode { NodeType get_type() const { return m_type; } - std::string const& get_key_name() const { return m_key_name; } + std::string_view const get_key_name() const { return m_key_name; } int32_t get_count() const { return m_count; } @@ -71,7 +101,10 @@ class SchemaNode { int32_t m_id; int32_t m_parent_id; std::vector m_children_ids; - std::string m_key_name; + // We use a buffer so that references to this key name are stable after this SchemaNode is move + // constructed + std::unique_ptr m_key_name_buf; + std::string_view m_key_name; NodeType m_type; int32_t m_count; int32_t m_depth{0}; @@ -81,7 +114,7 @@ class SchemaTree { public: SchemaTree() = default; - int32_t add_node(int parent_node_id, NodeType type, std::string const& key); + int32_t add_node(int parent_node_id, NodeType type, std::string_view const key); bool has_node(int32_t id) { return id < m_nodes.size() && id >= 0; } @@ -93,7 +126,25 @@ class SchemaTree { return m_nodes[id]; } - int32_t get_root_node_id() const { return m_nodes[0].get_id(); } + /** + * @return the Id of the root of the Object sub-tree that records the structure of JSON data. + * @return -1 if the Object sub-tree does not exist. + */ + int32_t get_object_subtree_node_id() const { return m_object_subtree_id; } + + /** + * Get the field Id for a specified field within the Metadata subtree. + * @param field_name + * + * @return the field Id if the field exists within the Metadata sub-tree, -1 otherwise. + */ + int32_t get_metadata_field_id(std::string_view const field_name); + + /** + * @return the Id of the root of the Metadata sub-tree. + * @return -1 if the Metadata sub-tree does not exist. + */ + int32_t get_metadata_subtree_node_id() { return m_metadata_subtree_id; } std::vector const& get_nodes() const { return m_nodes; } @@ -129,7 +180,9 @@ class SchemaTree { private: std::vector m_nodes; - absl::flat_hash_map, int32_t> m_node_map; + absl::flat_hash_map, int32_t> m_node_map; + int32_t m_object_subtree_id{-1}; + int32_t m_metadata_subtree_id{-1}; }; } // namespace clp_s diff --git a/components/core/src/clp_s/archive_constants.hpp b/components/core/src/clp_s/archive_constants.hpp index 30e2b78d5..604c97f66 100644 --- a/components/core/src/clp_s/archive_constants.hpp +++ b/components/core/src/clp_s/archive_constants.hpp @@ -1,6 +1,8 @@ #ifndef CLP_S_ARCHIVE_CONSTANTS_HPP #define CLP_S_ARCHIVE_CONSTANTS_HPP +#include + namespace clp_s::constants { // Schema files constexpr char cArchiveSchemaMapFile[] = "/schema_ids"; @@ -16,6 +18,12 @@ constexpr char cArchiveLogDictFile[] = "/log.dict"; constexpr char cArchiveTimestampDictFile[] = "/timestamp.dict"; constexpr char cArchiveVarDictFile[] = "/var.dict"; +// Schema tree constants +constexpr char cRootNodeName[] = ""; +constexpr int32_t cRootNodeId = -1; +constexpr char cMetadataSubtreeName[] = ""; +constexpr char cLogEventIdxName[] = "log_event_idx"; + namespace results_cache::decompression { constexpr char cPath[]{"path"}; constexpr char cOrigFileId[]{"orig_file_id"}; @@ -24,5 +32,13 @@ constexpr char cEndMsgIx[]{"end_msg_ix"}; constexpr char cIsLastIrChunk[]{"is_last_ir_chunk"}; } // namespace results_cache::decompression +namespace results_cache::search { +constexpr char cOrigFilePath[]{"orig_file_path"}; +constexpr char cLogEventIx[]{"log_event_ix"}; +constexpr char cTimestamp[]{"timestamp"}; +constexpr char cMessage[]{"message"}; +constexpr char cArchiveId[]{"archive_id"}; +} // namespace results_cache::search + } // namespace clp_s::constants #endif // CLP_S_ARCHIVE_CONSTANTS_HPP diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 8752384ae..941fd4366 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -96,6 +96,7 @@ bool compress(CommandLineArguments const& command_line_arguments) { option.timestamp_key = command_line_arguments.get_timestamp_key(); option.print_archive_stats = command_line_arguments.print_archive_stats(); option.structurize_arrays = command_line_arguments.get_structurize_arrays(); + option.record_log_order = command_line_arguments.get_record_log_order(); auto const& db_config_container = command_line_arguments.get_metadata_db_config(); if (db_config_container.has_value()) { diff --git a/components/core/src/clp_s/search/ColumnDescriptor.hpp b/components/core/src/clp_s/search/ColumnDescriptor.hpp index 7341ff07a..ea1cfd7ec 100644 --- a/components/core/src/clp_s/search/ColumnDescriptor.hpp +++ b/components/core/src/clp_s/search/ColumnDescriptor.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "Literal.hpp" @@ -22,7 +23,7 @@ class DescriptorToken { * wildcards * @param token the string to initialize the token from */ - explicit DescriptorToken(std::string const& token) + explicit DescriptorToken(std::string_view const token) : m_token(token), m_wildcard(false), m_regex(false) { diff --git a/components/core/src/clp_s/search/Output.cpp b/components/core/src/clp_s/search/Output.cpp index 4d36b4e29..c9954779b 100644 --- a/components/core/src/clp_s/search/Output.cpp +++ b/components/core/src/clp_s/search/Output.cpp @@ -62,6 +62,7 @@ bool Output::filter() { } } + populate_internal_columns(); populate_string_queries(top_level_expr); std::string message; @@ -92,9 +93,10 @@ bool Output::filter() { reader.initialize_filter(this); if (m_output_handler->should_output_metadata()) { - epochtime_t timestamp; - while (reader.get_next_message_with_timestamp(message, timestamp, this)) { - m_output_handler->write(message, timestamp, archive_id); + epochtime_t timestamp{}; + int64_t log_event_idx{}; + while (reader.get_next_message_with_metadata(message, timestamp, log_event_idx, this)) { + m_output_handler->write(message, timestamp, archive_id, log_event_idx); } } else { while (reader.get_next_message(message, this)) { @@ -136,6 +138,10 @@ void Output::init( for (auto column_reader : column_readers) { auto column_id = column_reader->get_id(); + if (0 != m_metadata_columns.count(column_id)) { + continue; + } + if ((0 != (m_wildcard_type_mask & node_to_literal_type(m_schema_tree->get_node(column_id).get_type()))) @@ -959,6 +965,19 @@ void Output::populate_string_queries(std::shared_ptr const& expr) { } } +void Output::populate_internal_columns() { + int32_t metadata_subtree_root_node_id = m_schema_tree->get_metadata_subtree_node_id(); + if (-1 == metadata_subtree_root_node_id) { + return; + } + + // This code assumes that the metadata subtree contains no nested structures + auto& metadata_node = m_schema_tree->get_node(metadata_subtree_root_node_id); + for (auto child_id : metadata_node.get_children_ids()) { + m_metadata_columns.insert(child_id); + } +} + void Output::populate_searched_wildcard_columns(std::shared_ptr const& expr) { if (expr->has_only_expression_operands()) { for (auto const& op : expr->get_op_list()) { @@ -975,6 +994,9 @@ void Output::populate_searched_wildcard_columns(std::shared_ptr cons if (Schema::schema_entry_is_unordered_object(node)) { continue; } + if (0 != m_metadata_columns.count(node)) { + continue; + } auto tree_node_type = m_schema_tree->get_node(node).get_type(); if (col->matches_type(node_to_literal_type(tree_node_type))) { auto literal_type = node_to_literal_type(tree_node_type); diff --git a/components/core/src/clp_s/search/Output.hpp b/components/core/src/clp_s/search/Output.hpp index ba4c4e1d7..bfd364457 100644 --- a/components/core/src/clp_s/search/Output.hpp +++ b/components/core/src/clp_s/search/Output.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,7 @@ class Output : public FilterClass { std::vector m_wildcard_columns; std::map> m_wildcard_to_searched_basic_columns; LiteralTypeBitmask m_wildcard_type_mask{0}; + std::unordered_set m_metadata_columns; std::stack< std::pair, @@ -342,6 +344,11 @@ class Output : public FilterClass { */ void populate_string_queries(std::shared_ptr const& expr); + /** + * Populates the set of internal columns that get ignored during dynamic wildcard expansion. + */ + void populate_internal_columns(); + /** * Constant propagates an expression * @param expr diff --git a/components/core/src/clp_s/search/OutputHandler.cpp b/components/core/src/clp_s/search/OutputHandler.cpp index 8d6a1eaa5..13771e9b5 100644 --- a/components/core/src/clp_s/search/OutputHandler.cpp +++ b/components/core/src/clp_s/search/OutputHandler.cpp @@ -10,6 +10,7 @@ #include "../../reducer/CountOperator.hpp" #include "../../reducer/network_utils.hpp" #include "../../reducer/Record.hpp" +#include "../archive_constants.hpp" using std::string; using std::string_view; @@ -31,11 +32,12 @@ NetworkOutputHandler::NetworkOutputHandler( void NetworkOutputHandler::write( string_view message, epochtime_t timestamp, - string_view archive_id + string_view archive_id, + int64_t log_event_idx ) { static constexpr string_view cOrigFilePathPlaceholder{""}; - msgpack::type::tuple const - src(timestamp, message, cOrigFilePathPlaceholder, archive_id); + msgpack::type::tuple const + src(timestamp, message, cOrigFilePathPlaceholder, archive_id, log_event_idx); msgpack::sbuffer m; msgpack::pack(m, src); @@ -72,10 +74,26 @@ ErrorCode ResultsCacheOutputHandler::flush() { try { m_results.emplace_back(std::move(bsoncxx::builder::basic::make_document( - bsoncxx::builder::basic::kvp("original_path", std::move(result.original_path)), - bsoncxx::builder::basic::kvp("message", std::move(result.message)), - bsoncxx::builder::basic::kvp("timestamp", result.timestamp), - bsoncxx::builder::basic::kvp("archive_id", std::move(result.archive_id)) + bsoncxx::builder::basic::kvp( + constants::results_cache::search::cOrigFilePath, + std::move(result.original_path) + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::search::cMessage, + std::move(result.message) + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::search::cTimestamp, + result.timestamp + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::search::cArchiveId, + std::move(result.archive_id) + ), + bsoncxx::builder::basic::kvp( + constants::results_cache::search::cLogEventIx, + result.log_event_idx + ) ))); count++; @@ -103,17 +121,26 @@ ErrorCode ResultsCacheOutputHandler::flush() { void ResultsCacheOutputHandler::write( string_view message, epochtime_t timestamp, - string_view archive_id + string_view archive_id, + int64_t log_event_idx ) { if (m_latest_results.size() < m_max_num_results) { - m_latest_results.emplace( - std::make_unique(string_view{}, message, timestamp, archive_id) - ); + m_latest_results.emplace(std::make_unique( + string_view{}, + message, + timestamp, + archive_id, + log_event_idx + )); } else if (m_latest_results.top()->timestamp < timestamp) { m_latest_results.pop(); - m_latest_results.emplace( - std::make_unique(string_view{}, message, timestamp, archive_id) - ); + m_latest_results.emplace(std::make_unique( + string_view{}, + message, + timestamp, + archive_id, + log_event_idx + )); } } diff --git a/components/core/src/clp_s/search/OutputHandler.hpp b/components/core/src/clp_s/search/OutputHandler.hpp index ca12e32d3..f033d37e8 100644 --- a/components/core/src/clp_s/search/OutputHandler.hpp +++ b/components/core/src/clp_s/search/OutputHandler.hpp @@ -43,9 +43,14 @@ class OutputHandler { * @param message The message in the log event. * @param timestamp The timestamp of the log event. * @param archive_id The archive containing the log event. + * @param log_event_idx The index of the log event within an archive. */ - virtual void write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) - = 0; + virtual void write( + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id, + int64_t log_event_idx + ) = 0; /** * Writes a message to the output handler. @@ -84,9 +89,13 @@ class StandardOutputHandler : public OutputHandler { : OutputHandler(should_output_metadata, true) {} // Methods inherited from OutputHandler - void - write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override { - std::cout << archive_id << ": " << timestamp << " " << message; + void write( + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id, + int64_t log_event_idx + ) override { + std::cout << archive_id << ": " << log_event_idx << ": " << timestamp << " " << message; } void write(std::string_view message) override { std::cout << message; } @@ -120,10 +129,14 @@ class NetworkOutputHandler : public OutputHandler { } // Methods inherited from OutputHandler - void - write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override; + void write( + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id, + int64_t log_event_idx + ) override; - void write(std::string_view message) override { write(message, 0, {}); } + void write(std::string_view message) override { write(message, 0, {}, 0); } private: std::string m_host; @@ -143,17 +156,20 @@ class ResultsCacheOutputHandler : public OutputHandler { std::string_view original_path, std::string_view message, epochtime_t timestamp, - std::string_view archive_id + std::string_view archive_id, + int64_t log_event_idx ) : original_path(original_path), message(message), timestamp(timestamp), - archive_id(archive_id) {} + archive_id(archive_id), + log_event_idx(log_event_idx) {} std::string original_path; std::string message; epochtime_t timestamp; std::string archive_id; + int64_t log_event_idx; }; struct QueryResultGreaterTimestampComparator { @@ -189,10 +205,14 @@ class ResultsCacheOutputHandler : public OutputHandler { */ ErrorCode flush() override; - void - write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override; + void write( + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id, + int64_t log_event_idx + ) override; - void write(std::string_view message) override { write(message, 0, {}); } + void write(std::string_view message) override { write(message, 0, {}, 0); } private: mongocxx::client m_client; @@ -216,8 +236,12 @@ class CountOutputHandler : public OutputHandler { CountOutputHandler(int reducer_socket_fd); // Methods inherited from OutputHandler - void - write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override {} + void write( + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id, + int64_t log_event_idx + ) override {} void write(std::string_view message) override; @@ -246,8 +270,12 @@ class CountByTimeOutputHandler : public OutputHandler { m_count_by_time_bucket_size{count_by_time_bucket_size} {} // Methods inherited from OutputHandler - void - write(std::string_view message, epochtime_t timestamp, std::string_view archive_id) override { + void write( + std::string_view message, + epochtime_t timestamp, + std::string_view archive_id, + int64_t log_event_idx + ) override { int64_t bucket = (timestamp / m_count_by_time_bucket_size) * m_count_by_time_bucket_size; m_bucket_counts[bucket] += 1; } diff --git a/components/core/src/clp_s/search/Projection.cpp b/components/core/src/clp_s/search/Projection.cpp index 69836e312..b1c453776 100644 --- a/components/core/src/clp_s/search/Projection.cpp +++ b/components/core/src/clp_s/search/Projection.cpp @@ -52,7 +52,7 @@ void Projection::resolve_column( * what we need. */ - auto cur_node_id = tree->get_root_node_id(); + auto cur_node_id = tree->get_object_subtree_node_id(); auto it = column->descriptor_begin(); while (it != column->descriptor_end()) { bool matched_any{false}; diff --git a/components/core/src/clp_s/search/SchemaMatch.cpp b/components/core/src/clp_s/search/SchemaMatch.cpp index 82c9af866..203634000 100644 --- a/components/core/src/clp_s/search/SchemaMatch.cpp +++ b/components/core/src/clp_s/search/SchemaMatch.cpp @@ -76,7 +76,7 @@ std::shared_ptr SchemaMatch::populate_column_mapping(std::shared_ptr auto const* node = &m_tree->get_node(node_id); auto literal_type = node_to_literal_type(node->get_type()); DescriptorList descriptors; - while (node->get_id() != m_tree->get_root_node_id()) { + while (node->get_id() != m_tree->get_object_subtree_node_id()) { // may have to explicitly mark non-regex descriptors.emplace_back(node->get_key_name()); node = &m_tree->get_node(node->get_parent_id()); @@ -111,9 +111,9 @@ bool SchemaMatch::populate_column_mapping(ColumnDescriptor* column) { return matched; } - // TODO: once we start supporting multi-rooted MPTs this (and anything that uses - // get_root_node_id, or assumes root node id is 0) will have to change - auto const& root = m_tree->get_node(m_tree->get_root_node_id()); + // TODO: Once we start supporting mixing different types of logs we will have to match against + // more than just the object subtree. + auto const& root = m_tree->get_node(m_tree->get_object_subtree_node_id()); for (int32_t child_node_id : root.get_children_ids()) { matched |= populate_column_mapping(column, child_node_id); } diff --git a/components/core/src/clp_s/search/SearchUtils.cpp b/components/core/src/clp_s/search/SearchUtils.cpp index 3f7c522cb..39ae694a0 100644 --- a/components/core/src/clp_s/search/SearchUtils.cpp +++ b/components/core/src/clp_s/search/SearchUtils.cpp @@ -34,6 +34,7 @@ LiteralType node_to_literal_type(NodeType type) { return LiteralType::NullT; case NodeType::DateString: return LiteralType::EpochDateT; + case NodeType::Metadata: case NodeType::Unknown: default: return LiteralType::UnknownT; From ee7e493c0978375e1cece737b299899c3a042b3a Mon Sep 17 00:00:00 2001 From: Devin Gibson Date: Tue, 19 Nov 2024 19:47:48 -0500 Subject: [PATCH 106/114] feat(clp-s): Chunk output by size (in bytes) during ordered decompression. (#600) Co-authored-by: haiqi96 <14502009+haiqi96@users.noreply.github.com> Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../clp_package_utils/scripts/decompress.py | 4 +++- .../scripts/native/decompress.py | 2 +- .../core/src/clp_s/CommandLineArguments.cpp | 16 +++++++++------- .../core/src/clp_s/CommandLineArguments.hpp | 4 ++-- components/core/src/clp_s/JsonConstructor.cpp | 18 +++++++++--------- components/core/src/clp_s/JsonConstructor.hpp | 2 +- components/core/src/clp_s/clp-s.cpp | 2 +- .../executor/query/extract_stream_task.py | 2 +- 8 files changed, 27 insertions(+), 23 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/decompress.py index 903107c32..9085fb162 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/decompress.py @@ -258,7 +258,9 @@ def main(argv): json_extraction_parser = command_args_parser.add_parser(EXTRACT_JSON_CMD) json_extraction_parser.add_argument("archive_id", type=str, help="Archive ID") json_extraction_parser.add_argument( - "--target-chunk-size", type=int, help="Target chunk size", default=100000 + "--target-chunk-size", + type=int, + help="Target chunk size (B).", ) parsed_args = args_parser.parse_args(argv[1:]) diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py index d4217d66d..7cce5d92a 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py @@ -299,7 +299,7 @@ def main(argv): json_extraction_parser = command_args_parser.add_parser(EXTRACT_JSON_CMD) json_extraction_parser.add_argument("archive_id", type=str, help="Archive ID") json_extraction_parser.add_argument( - "--target-chunk-size", type=int, help="Target chunk size.", required=True + "--target-chunk-size", type=int, help="Target chunk size (B)." ) parsed_args = args_parser.parse_args(argv[1:]) diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index ace505788..d174b4a23 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -302,11 +302,12 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { po::bool_switch(&m_ordered_decompression), "Enable decompression in log order for this archive" )( - "ordered-chunk-size", - po::value(&m_ordered_chunk_size) - ->default_value(m_ordered_chunk_size), - "Number of records to include in each output file when decompressing records " - "in log order" + "target-ordered-chunk-size", + po::value(&m_target_ordered_chunk_size) + ->default_value(m_target_ordered_chunk_size) + ->value_name("SIZE"), + "Chunk size (B) for each output file when decompressing records in log order." + " When set to 0, no chunking is performed." ); // clang-format on extraction_options.add(decompression_options); @@ -369,8 +370,9 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { throw std::invalid_argument("No output directory specified"); } - if (0 != m_ordered_chunk_size && false == m_ordered_decompression) { - throw std::invalid_argument("ordered-chunk-size must be used with ordered argument" + if (0 != m_target_ordered_chunk_size && false == m_ordered_decompression) { + throw std::invalid_argument( + "target-ordered-chunk-size must be used with ordered argument" ); } diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 8f2d79d8f..913e27fbc 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -106,7 +106,7 @@ class CommandLineArguments { bool get_ordered_decompression() const { return m_ordered_decompression; } - size_t get_ordered_chunk_size() const { return m_ordered_chunk_size; } + size_t get_target_ordered_chunk_size() const { return m_target_ordered_chunk_size; } size_t get_minimum_table_size() const { return m_minimum_table_size; } @@ -178,7 +178,7 @@ class CommandLineArguments { size_t m_max_document_size{512ULL * 1024 * 1024}; // 512 MB bool m_structurize_arrays{false}; bool m_ordered_decompression{false}; - size_t m_ordered_chunk_size{0}; + size_t m_target_ordered_chunk_size{}; size_t m_minimum_table_size{1ULL * 1024 * 1024}; // 1 MB bool m_disable_log_order{false}; diff --git a/components/core/src/clp_s/JsonConstructor.cpp b/components/core/src/clp_s/JsonConstructor.cpp index 0c816c5e3..95e3fa2c5 100644 --- a/components/core/src/clp_s/JsonConstructor.cpp +++ b/components/core/src/clp_s/JsonConstructor.cpp @@ -81,9 +81,9 @@ void JsonConstructor::construct_in_order() { // a given table tables.clear(); - int64_t first_idx{0}; - int64_t last_idx{0}; - size_t num_records_marshalled{0}; + int64_t first_idx{}; + int64_t last_idx{}; + size_t chunk_size{}; auto src_path = std::filesystem::path(m_option.output_dir) / m_option.archive_id; FileWriter writer; writer.open(src_path, FileWriter::OpenMode::CreateForWriting); @@ -149,7 +149,7 @@ void JsonConstructor::construct_in_order() { ReaderPointer next = record_queue.top(); record_queue.pop(); last_idx = next->get_next_log_event_idx(); - if (0 == num_records_marshalled) { + if (0 == chunk_size) { first_idx = last_idx; } next->get_next_message(buffer); @@ -157,17 +157,17 @@ void JsonConstructor::construct_in_order() { record_queue.emplace(std::move(next)); } writer.write(buffer.c_str(), buffer.length()); - num_records_marshalled += 1; + chunk_size += buffer.length(); - if (0 != m_option.ordered_chunk_size - && num_records_marshalled >= m_option.ordered_chunk_size) + if (0 != m_option.target_ordered_chunk_size + && chunk_size >= m_option.target_ordered_chunk_size) { finalize_chunk(true); - num_records_marshalled = 0; + chunk_size = 0; } } - if (num_records_marshalled > 0) { + if (chunk_size > 0) { finalize_chunk(false); } else { writer.close(); diff --git a/components/core/src/clp_s/JsonConstructor.hpp b/components/core/src/clp_s/JsonConstructor.hpp index c38e6d00b..3d9228a02 100644 --- a/components/core/src/clp_s/JsonConstructor.hpp +++ b/components/core/src/clp_s/JsonConstructor.hpp @@ -30,7 +30,7 @@ struct JsonConstructorOption { std::string archive_id; std::string output_dir; bool ordered{false}; - size_t ordered_chunk_size{0}; + size_t target_ordered_chunk_size{}; std::optional metadata_db; }; diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index 941fd4366..a74693e33 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -300,7 +300,7 @@ int main(int argc, char const* argv[]) { option.output_dir = command_line_arguments.get_output_dir(); option.ordered = command_line_arguments.get_ordered_decompression(); option.archives_dir = archives_dir; - option.ordered_chunk_size = command_line_arguments.get_ordered_chunk_size(); + option.target_ordered_chunk_size = command_line_arguments.get_target_ordered_chunk_size(); if (false == command_line_arguments.get_mongodb_uri().empty()) { option.metadata_db = {command_line_arguments.get_mongodb_uri(), diff --git a/components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py b/components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py index 9e99842ab..423ebb757 100644 --- a/components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py +++ b/components/job-orchestration/job_orchestration/executor/query/extract_stream_task.py @@ -65,7 +65,7 @@ def make_command( stream_collection_name, ] if extract_json_config.target_chunk_size is not None: - command.append("--ordered-chunk-size") + command.append("--target-ordered-chunk-size") command.append(str(extract_json_config.target_chunk_size)) else: logger.error(f"Unsupported storage engine {storage_engine}") From 7d85ad33254c2e3971e1f3612f62c53e250906d3 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Thu, 21 Nov 2024 18:05:06 -0500 Subject: [PATCH 107/114] feat(webui): Support viewing search results in context for JSON logs (clp-json). (#596) Co-authored-by: Junhao Liao --- .../clp_package_utils/scripts/start_clp.py | 1 + .../clp-py-utils/clp_py_utils/clp_config.py | 2 +- .../log-viewer-webui/client/src/api/query.js | 29 ++++++--- .../client/src/ui/QueryStatus.jsx | 50 +++++++++++++--- .../log-viewer-webui/server/settings.json | 1 + .../log-viewer-webui/server/src/DbManager.js | 56 ++++++++++++++---- .../server/src/routes/query.js | 59 ++++++++++++------- .../package-template/src/etc/clp-config.yml | 2 +- .../SearchResultsTable/index.jsx | 55 +++++++++++------ 9 files changed, 187 insertions(+), 68 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index a25756fd9..6732ded0b 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -936,6 +936,7 @@ def start_log_viewer_webui( "MongoDbStreamFilesCollectionName": clp_config.results_cache.stream_collection_name, "ClientDir": str(container_log_viewer_webui_dir / "client"), "StreamFilesDir": str(container_clp_config.stream_output.directory), + "StreamTargetUncompressedSize": container_clp_config.stream_output.target_uncompressed_size, "LogViewerDir": str(container_log_viewer_webui_dir / "yscope-log-viewer"), } settings_json = read_and_update_settings_json(settings_json_path, settings_json_updates) diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index 4bb00bd9e..79a94505d 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -346,7 +346,7 @@ def dump_to_primitive_dict(self): class StreamOutput(BaseModel): - directory: pathlib.Path = pathlib.Path("var") / "data" / "stream" + directory: pathlib.Path = pathlib.Path("var") / "data" / "streams" target_uncompressed_size: int = 128 * 1024 * 1024 @validator("directory") diff --git a/components/log-viewer-webui/client/src/api/query.js b/components/log-viewer-webui/client/src/api/query.js index be17d0fc8..eda1db21c 100644 --- a/components/log-viewer-webui/client/src/api/query.js +++ b/components/log-viewer-webui/client/src/api/query.js @@ -13,20 +13,31 @@ import axios from "axios"; */ /** - * Submits a job to extract the split of an original file that contains a given log event. The file - * is extracted as a CLP IR file. + * @typedef {object} ExtractJsonResp + * @property {number} begin_msg_ix + * @property {number} end_msg_ix + * @property {boolean} is_last_ir_chunk + * @property {string} orig_file_id + * @property {string} path + * @property {string} _id + */ + +/** + * Submits a job to extract the stream that contains a given log event. The stream is extracted + * either as a CLP IR or a JSON Lines file. * - * @param {number|string} origFileId The ID of the original file - * @param {number} logEventIdx The index of the log event + * @param {QUERY_JOB_TYPE} extractJobType + * @param {string} streamId + * @param {number} logEventIdx * @param {Function} onUploadProgress Callback to handle upload progress events. - * @return {Promise>} + * @return {Promise>} */ -const submitExtractIrJob = async (origFileId, logEventIdx, onUploadProgress) => { +const submitExtractStreamJob = async (extractJobType, streamId, logEventIdx, onUploadProgress) => { return await axios.post( - "/query/extract-ir", - {logEventIdx, origFileId}, + "/query/extract-stream", + {extractJobType, streamId, logEventIdx}, {onUploadProgress} ); }; -export {submitExtractIrJob}; +export {submitExtractStreamJob}; diff --git a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx index c1bb639a6..56a995980 100644 --- a/components/log-viewer-webui/client/src/ui/QueryStatus.jsx +++ b/components/log-viewer-webui/client/src/ui/QueryStatus.jsx @@ -6,11 +6,37 @@ import { import {AxiosError} from "axios"; -import {submitExtractIrJob} from "../api/query.js"; +import {submitExtractStreamJob} from "../api/query.js"; import {QUERY_LOADING_STATES} from "../typings/query.js"; import Loading from "./Loading.jsx"; +let enumQueryType; +/* eslint-disable sort-keys */ +/** + * Note: This enum is duplicated from server, as it is non-trivial to include server enums from the + * client. + * + * Enum of job types, matching the `QueryJobType` class in + * `job_orchestration.query_scheduler.constants`. + * + * @enum {number} + */ +const QUERY_JOB_TYPE = Object.freeze({ + SEARCH_OR_AGGREGATION: (enumQueryType = 0), + EXTRACT_IR: ++enumQueryType, + EXTRACT_JSON: ++enumQueryType, +}); +/* eslint-enable sort-keys */ + +/** + * Mapping between job type enums and stream type + */ +const EXTRACT_JOB_TYPE = Object.freeze({ + ir: QUERY_JOB_TYPE.EXTRACT_IR, + json: QUERY_JOB_TYPE.EXTRACT_JSON, +}); + /** * Submits queries and renders the query states. * @@ -28,20 +54,30 @@ const QueryStatus = () => { isFirstRun.current = false; const searchParams = new URLSearchParams(window.location.search); - const origFileId = searchParams.get("origFileId"); + const streamType = searchParams.get("type"); + const streamId = searchParams.get("streamId"); const logEventIdx = searchParams.get("logEventIdx"); - if (null === origFileId || null === logEventIdx) { - const error = "Either `origFileId` or `logEventIdx` are missing from the URL " + - "parameters. Note that non-IR-extraction queries are not supported at the moment."; + if (null === streamType || null === streamId || null === logEventIdx) { + const error = "Queries parameters are missing from the URL parameters."; + console.error(error); + setErrorMsg(error); + + return; + } + + const extractJobType = EXTRACT_JOB_TYPE[streamType]; + if ("undefined" === typeof extractJobType) { + const error = `Unsupported Stream type: ${streamType}`; console.error(error); setErrorMsg(error); return; } - submitExtractIrJob( - origFileId, + submitExtractStreamJob( + extractJobType, + streamId, Number(logEventIdx), () => { setQueryState(QUERY_LOADING_STATES.WAITING); diff --git a/components/log-viewer-webui/server/settings.json b/components/log-viewer-webui/server/settings.json index 163f9a9e2..9e749e144 100644 --- a/components/log-viewer-webui/server/settings.json +++ b/components/log-viewer-webui/server/settings.json @@ -10,5 +10,6 @@ "ClientDir": "../client/dist", "StreamFilesDir": "../../../build/clp-package/var/data/streams", + "StreamTargetUncompressedSize": 134217728, "LogViewerDir": "../yscope-log-viewer/dist" } diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js index 79e097280..e1ec00812 100644 --- a/components/log-viewer-webui/server/src/DbManager.js +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -62,9 +62,18 @@ let enumQueryType; const QUERY_JOB_TYPE = Object.freeze({ SEARCH_OR_AGGREGATION: (enumQueryType = 0), EXTRACT_IR: ++enumQueryType, + EXTRACT_JSON: ++enumQueryType, }); /* eslint-enable sort-keys */ +/** + * List of valid extract job types. + */ +const EXTRACT_JOB_TYPES = Object.freeze([ + QUERY_JOB_TYPE.EXTRACT_IR, + QUERY_JOB_TYPE.EXTRACT_JSON, +]); + /** * Class to manage connections to the jobs database (MySQL) and results cache (MongoDB). */ @@ -101,12 +110,35 @@ class DbManager { } /** - * Submits an IR extraction job to the scheduler and waits for it to finish. + * Submits a stream extraction job to the scheduler and waits for it to finish. * - * @param {object} jobConfig + * @param {number} jobType + * @param {number} logEventIdx + * @param {string} streamId + * @param {number} targetUncompressedSize * @return {Promise} The ID of the job or null if an error occurred. */ - async submitAndWaitForExtractIrJob (jobConfig) { + async submitAndWaitForExtractStreamJob ({ + jobType, + logEventIdx, + streamId, + targetUncompressedSize, + }) { + let jobConfig; + if (QUERY_JOB_TYPE.EXTRACT_IR === jobType) { + jobConfig = { + file_split_id: null, + msg_ix: logEventIdx, + orig_file_id: streamId, + target_uncompressed_size: targetUncompressedSize, + }; + } else if (QUERY_JOB_TYPE.EXTRACT_JSON === jobType) { + jobConfig = { + archive_id: streamId, + target_chunk_size: targetUncompressedSize, + }; + } + let jobId; try { const [result] = await this.#mysqlConnectionPool.query( @@ -114,7 +146,7 @@ class DbManager { VALUES (?, ?)`, [ Buffer.from(msgpackEncode(jobConfig)), - QUERY_JOB_TYPE.EXTRACT_IR, + jobType, ] ); @@ -130,16 +162,16 @@ class DbManager { } /** - * Gets the metadata for an IR file extracted from part of an original file, where the original - * file has the given ID and the extracted part contains the given log event index. + * Gets the metadata for the extracted stream that has the given streamId and contains the + * given logEventIdx. * - * @param {string} origFileId + * @param {string} streamId * @param {number} logEventIdx - * @return {Promise} A promise that resolves to the extracted IR file's metadata. + * @return {Promise} A promise that resolves to the extracted stream's metadata. */ - async getExtractedIrFileMetadata (origFileId, logEventIdx) { + async getExtractedStreamFileMetadata (streamId, logEventIdx) { return await this.#streamFilesCollection.findOne({ - orig_file_id: origFileId, + orig_file_id: streamId, begin_msg_ix: {$lte: logEventIdx}, end_msg_ix: {$gt: logEventIdx}, }); @@ -236,6 +268,10 @@ class DbManager { } } +export { + EXTRACT_JOB_TYPES, + QUERY_JOB_TYPE, +}; export default fastifyPlugin(async (app, options) => { await app.decorate("dbManager", new DbManager(app, options)); }); diff --git a/components/log-viewer-webui/server/src/routes/query.js b/components/log-viewer-webui/server/src/routes/query.js index 628bcd053..452f6480a 100644 --- a/components/log-viewer-webui/server/src/routes/query.js +++ b/components/log-viewer-webui/server/src/routes/query.js @@ -1,5 +1,8 @@ -// eslint-disable-next-line no-magic-numbers -const EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE = 128 * 1024 * 1024; +import {StatusCodes} from "http-status-codes"; + +import settings from "../../settings.json" with {type: "json"}; +import {EXTRACT_JOB_TYPES} from "../DbManager.js"; + /** * Creates query routes. @@ -9,37 +12,51 @@ const EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE = 128 * 1024 * 1024; * @return {Promise} */ const routes = async (fastify, options) => { - fastify.post("/query/extract-ir", async (req, resp) => { - const {origFileId, logEventIdx} = req.body; - const sanitizedLogEventIdx = Number(logEventIdx); + fastify.post("/query/extract-stream", async (req, resp) => { + const {extractJobType, logEventIdx, streamId} = req.body; + if (false === EXTRACT_JOB_TYPES.includes(extractJobType)) { + resp.code(StatusCodes.BAD_REQUEST); + throw new Error(`Invalid extractJobType="${extractJobType}".`); + } + + if ("string" !== typeof streamId || 0 === streamId.trim().length) { + resp.code(StatusCodes.BAD_REQUEST); + throw new Error("\"streamId\" must be a non-empty string."); + } - let irMetadata = await fastify.dbManager.getExtractedIrFileMetadata( - origFileId, + const sanitizedLogEventIdx = Number(logEventIdx); + let streamMetadata = await fastify.dbManager.getExtractedStreamFileMetadata( + streamId, sanitizedLogEventIdx ); - if (null === irMetadata) { - const extractResult = await fastify.dbManager.submitAndWaitForExtractIrJob({ - file_split_id: null, - msg_ix: sanitizedLogEventIdx, - orig_file_id: origFileId, - target_uncompressed_size: EXTRACT_IR_TARGET_UNCOMPRESSED_SIZE, + if (null === streamMetadata) { + const extractResult = await fastify.dbManager.submitAndWaitForExtractStreamJob({ + jobType: extractJobType, + logEventIdx: sanitizedLogEventIdx, + streamId: streamId, + targetUncompressedSize: settings.StreamTargetUncompressedSize, }); if (null === extractResult) { - const err = new Error("Unable to extract IR for file with " + - `origFileId=${origFileId} at logEventIdx=${sanitizedLogEventIdx}`); - - err.statusCode = 400; - throw err; + resp.code(StatusCodes.BAD_REQUEST); + throw new Error("Unable to extract stream with " + + `streamId=${streamId} at logEventIdx=${sanitizedLogEventIdx}`); } - irMetadata = await fastify.dbManager.getExtractedIrFileMetadata( - origFileId, + + streamMetadata = await fastify.dbManager.getExtractedStreamFileMetadata( + streamId, sanitizedLogEventIdx ); + + if (null === streamMetadata) { + resp.code(StatusCodes.BAD_REQUEST); + throw new Error("Unable to find the metadata of extracted stream with " + + `streamId=${streamId} at logEventIdx=${sanitizedLogEventIdx}`); + } } - return irMetadata; + return streamMetadata; }); }; diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index 15747fe42..f19b93463 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -86,7 +86,7 @@ #stream_output: # directory: "var/data/streams" # -# # How large each IR file should be before being split into a new IR file +# # How large each stream file should be before being split into a new stream file # target_uncompressed_size: 134217728 # 128 MB # ## Location where other data (besides archives) are stored. It will be created if diff --git a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx index 83b251cca..c7fa62a25 100644 --- a/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx +++ b/components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx @@ -28,6 +28,25 @@ import "./SearchResultsTable.scss"; */ const SEARCH_RESULT_MESSAGE_LINE_HEIGHT = 1.5; +const IS_IR_STREAM = ("clp" === Meteor.settings.public.ClpStorageEngine); +const STREAM_TYPE = IS_IR_STREAM ? + "ir" : + "json"; + + +/** + * Gets the stream id for an extraction job from the search result. + * + * @param {object} searchResult + * @return {string} stream_id + */ +const getStreamId = (searchResult) => { + return IS_IR_STREAM ? + searchResult.orig_file_id : + searchResult.archive_id; +}; + + /** * Represents a table component to display search results. * @@ -93,10 +112,6 @@ const SearchResultsTable = ({ ); }, [maxLinesPerResult]); - // eslint-disable-next-line no-warning-comments - // TODO: remove this flag once "Extract IR" support is added for ClpStorageEngine "clp-s" - const isExtractIrSupported = ("clp" === Meteor.settings.public.ClpStorageEngine); - return (
    {result.message} - {isExtractIrSupported && - } + > + {IS_IR_STREAM ? + result.orig_file_path : + "Original File"} + + ))} From a864e42faf0287971b9d8e4efdf3093d899da331 Mon Sep 17 00:00:00 2001 From: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:07:05 -0500 Subject: [PATCH 108/114] fix(gh-macos-build): Check if pkg-config is installed before trying to install it (fixes #610). (#611) --- .../core/tools/scripts/lib_install/macos/install-all.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/core/tools/scripts/lib_install/macos/install-all.sh b/components/core/tools/scripts/lib_install/macos/install-all.sh index 99e178e92..97e41903d 100755 --- a/components/core/tools/scripts/lib_install/macos/install-all.sh +++ b/components/core/tools/scripts/lib_install/macos/install-all.sh @@ -21,5 +21,12 @@ brew install \ mongo-cxx-driver \ msgpack-cxx \ spdlog \ - pkg-config \ zstd + +# Install pkg-config if it isn't already installed +# NOTE: We might expect that pkg-config is installed through brew, so trying to install it again +# would be harmless; however, in certain environments, like the macOS GitHub hosted runner, +# pkg-config is installed by other means, meaning a brew install would cause conflicts. +if ! command -v pkg-config ; then + brew install pkg-config +fi From 7aea6262556a9f3a6f84cc648acf397e5544718d Mon Sep 17 00:00:00 2001 From: Bingran Hu Date: Sat, 23 Nov 2024 04:49:32 -0500 Subject: [PATCH 109/114] refactor(core): Fix clang-tidy warnings in the streaming compressor interface and its implementations; Modernize and refactor `test-StreamingCompression` for conciseness. (#599) Co-authored-by: Bingran Hu Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> --- .../core/src/clp/TraceableException.hpp | 1 + .../clp/streaming_compression/Compressor.hpp | 45 ++- .../passthrough/Compressor.cpp | 15 +- .../passthrough/Compressor.hpp | 41 ++- .../streaming_compression/zstd/Compressor.cpp | 73 ++--- .../streaming_compression/zstd/Compressor.hpp | 57 ++-- .../streaming_compression/zstd/Constants.hpp | 5 +- .../core/tests/test-StreamingCompression.cpp | 291 ++++++------------ 8 files changed, 225 insertions(+), 303 deletions(-) diff --git a/components/core/src/clp/TraceableException.hpp b/components/core/src/clp/TraceableException.hpp index cd8e33f4b..f60273f93 100644 --- a/components/core/src/clp/TraceableException.hpp +++ b/components/core/src/clp/TraceableException.hpp @@ -39,6 +39,7 @@ class TraceableException : public std::exception { // Macros // Define a version of __FILE__ that's relative to the source directory #ifdef SOURCE_PATH_SIZE + // NOLINTNEXTLINE #define __FILENAME__ ((__FILE__) + SOURCE_PATH_SIZE) #else // We don't know the source path size, so just default to __FILE__ diff --git a/components/core/src/clp/streaming_compression/Compressor.hpp b/components/core/src/clp/streaming_compression/Compressor.hpp index 165696091..ac55bd270 100644 --- a/components/core/src/clp/streaming_compression/Compressor.hpp +++ b/components/core/src/clp/streaming_compression/Compressor.hpp @@ -1,14 +1,19 @@ #ifndef CLP_STREAMING_COMPRESSION_COMPRESSOR_HPP #define CLP_STREAMING_COMPRESSION_COMPRESSOR_HPP -#include -#include +#include +#include + +#include "../ErrorCode.hpp" +#include "../FileWriter.hpp" #include "../TraceableException.hpp" #include "../WriterInterface.hpp" -#include "Constants.hpp" namespace clp::streaming_compression { +/** + * Abstract compressor interface. + */ class Compressor : public WriterInterface { public: // Types @@ -16,23 +21,27 @@ class Compressor : public WriterInterface { public: // Constructors OperationFailed(ErrorCode error_code, char const* const filename, int line_number) - : TraceableException(error_code, filename, line_number) {} + : TraceableException{error_code, filename, line_number} {} // Methods - char const* what() const noexcept override { + [[nodiscard]] auto what() const noexcept -> char const* override { return "streaming_compression::Compressor operation failed"; } }; // Constructor - explicit Compressor(CompressorType type) : m_type(type) {} + Compressor() = default; // Destructor virtual ~Compressor() = default; - // Explicitly disable copy and move constructor/assignment + // Delete copy constructor and assignment operator Compressor(Compressor const&) = delete; - Compressor& operator=(Compressor const&) = delete; + auto operator=(Compressor const&) -> Compressor& = delete; + + // Default move constructor and assignment operator + Compressor(Compressor&&) noexcept = default; + auto operator=(Compressor&&) noexcept -> Compressor& = default; // Methods implementing the WriterInterface /** @@ -40,24 +49,30 @@ class Compressor : public WriterInterface { * @param pos * @return ErrorCode_Unsupported */ - ErrorCode try_seek_from_begin(size_t pos) override { return ErrorCode_Unsupported; } + [[nodiscard]] auto try_seek_from_begin([[maybe_unused]] size_t pos) -> ErrorCode override { + return ErrorCode_Unsupported; + } /** * Unsupported operation * @param pos * @return ErrorCode_Unsupported */ - ErrorCode try_seek_from_current(off_t offset) override { return ErrorCode_Unsupported; } + [[nodiscard]] auto try_seek_from_current([[maybe_unused]] off_t offset) -> ErrorCode override { + return ErrorCode_Unsupported; + } // Methods /** - * Closes the compression stream + * Closes the compressor */ - virtual void close() = 0; + virtual auto close() -> void = 0; -protected: - // Variables - CompressorType m_type; + /** + * Initializes the compression stream + * @param file_writer + */ + virtual auto open(FileWriter& file_writer) -> void = 0; }; } // namespace clp::streaming_compression diff --git a/components/core/src/clp/streaming_compression/passthrough/Compressor.cpp b/components/core/src/clp/streaming_compression/passthrough/Compressor.cpp index 750ab48c1..d4ab89dbe 100644 --- a/components/core/src/clp/streaming_compression/passthrough/Compressor.cpp +++ b/components/core/src/clp/streaming_compression/passthrough/Compressor.cpp @@ -1,9 +1,12 @@ #include "Compressor.hpp" -#include "../../Defs.h" +#include + +#include "../../ErrorCode.hpp" +#include "../../TraceableException.hpp" namespace clp::streaming_compression::passthrough { -void Compressor::write(char const* data, size_t const data_length) { +auto Compressor::write(char const* data, size_t const data_length) -> void { if (nullptr == m_compressed_stream_file_writer) { throw OperationFailed(ErrorCode_NotInit, __FILENAME__, __LINE__); } @@ -19,7 +22,7 @@ void Compressor::write(char const* data, size_t const data_length) { m_compressed_stream_file_writer->write(data, data_length); } -void Compressor::flush() { +auto Compressor::flush() -> void { if (nullptr == m_compressed_stream_file_writer) { throw OperationFailed(ErrorCode_NotInit, __FILENAME__, __LINE__); } @@ -27,7 +30,7 @@ void Compressor::flush() { m_compressed_stream_file_writer->flush(); } -ErrorCode Compressor::try_get_pos(size_t& pos) const { +auto Compressor::try_get_pos(size_t& pos) const -> ErrorCode { if (nullptr == m_compressed_stream_file_writer) { return ErrorCode_NotInit; } @@ -35,11 +38,11 @@ ErrorCode Compressor::try_get_pos(size_t& pos) const { return m_compressed_stream_file_writer->try_get_pos(pos); } -void Compressor::close() { +auto Compressor::close() -> void { m_compressed_stream_file_writer = nullptr; } -void Compressor::open(FileWriter& file_writer) { +auto Compressor::open(FileWriter& file_writer) -> void { m_compressed_stream_file_writer = &file_writer; } } // namespace clp::streaming_compression::passthrough diff --git a/components/core/src/clp/streaming_compression/passthrough/Compressor.hpp b/components/core/src/clp/streaming_compression/passthrough/Compressor.hpp index b3735bd1e..f7ccd5004 100644 --- a/components/core/src/clp/streaming_compression/passthrough/Compressor.hpp +++ b/components/core/src/clp/streaming_compression/passthrough/Compressor.hpp @@ -1,6 +1,9 @@ #ifndef CLP_STREAMING_COMPRESSION_PASSTHROUGH_COMPRESSOR_HPP #define CLP_STREAMING_COMPRESSION_PASSTHROUGH_COMPRESSOR_HPP +#include + +#include "../../ErrorCode.hpp" #include "../../FileWriter.hpp" #include "../../TraceableException.hpp" #include "../Compressor.hpp" @@ -16,22 +19,27 @@ class Compressor : public ::clp::streaming_compression::Compressor { public: // Constructors OperationFailed(ErrorCode error_code, char const* const filename, int line_number) - : TraceableException(error_code, filename, line_number) {} + : TraceableException{error_code, filename, line_number} {} // Methods - char const* what() const noexcept override { + [[nodiscard]] auto what() const noexcept -> char const* override { return "streaming_compression::passthrough::Compressor operation failed"; } }; - // Constructors - Compressor() - : ::clp::streaming_compression::Compressor(CompressorType::Passthrough), - m_compressed_stream_file_writer(nullptr) {} + // Constructor + Compressor() = default; + + // Destructor + ~Compressor() override = default; - // Explicitly disable copy and move constructor/assignment + // Delete copy constructor and assignment operator Compressor(Compressor const&) = delete; - Compressor& operator=(Compressor const&) = delete; + auto operator=(Compressor const&) -> Compressor& = delete; + + // Default move constructor and assignment operator + Compressor(Compressor&&) noexcept = default; + auto operator=(Compressor&&) noexcept -> Compressor& = default; // Methods implementing the WriterInterface /** @@ -39,35 +47,36 @@ class Compressor : public ::clp::streaming_compression::Compressor { * @param data * @param data_length */ - void write(char const* data, size_t data_length) override; + auto write(char const* data, size_t data_length) -> void override; + /** * Flushes any buffered data */ - void flush() override; + auto flush() -> void override; + /** * Tries to get the current position of the write head * @param pos Position of the write head * @return ErrorCode_NotInit if the compressor is not open * @return Same as FileWriter::try_get_pos */ - ErrorCode try_get_pos(size_t& pos) const override; + [[nodiscard]] auto try_get_pos(size_t& pos) const -> ErrorCode override; // Methods implementing the Compressor interface /** * Closes the compressor */ - void close() override; + auto close() -> void override; - // Methods /** - * Initializes the compressor + * Initializes the compression stream * @param file_writer */ - void open(FileWriter& file_writer); + auto open(FileWriter& file_writer) -> void override; private: // Variables - FileWriter* m_compressed_stream_file_writer; + FileWriter* m_compressed_stream_file_writer{nullptr}; }; } // namespace clp::streaming_compression::passthrough diff --git a/components/core/src/clp/streaming_compression/zstd/Compressor.cpp b/components/core/src/clp/streaming_compression/zstd/Compressor.cpp index ebbf9b574..948ec1967 100644 --- a/components/core/src/clp/streaming_compression/zstd/Compressor.cpp +++ b/components/core/src/clp/streaming_compression/zstd/Compressor.cpp @@ -1,14 +1,21 @@ #include "Compressor.hpp" -#include "../../Defs.h" -#include "../../spdlog_with_specializations.hpp" +#include + +#include +#include + +#include "../../ErrorCode.hpp" +#include "../../FileWriter.hpp" +#include "../../TraceableException.hpp" namespace clp::streaming_compression::zstd { Compressor::Compressor() - : ::clp::streaming_compression::Compressor(CompressorType::ZSTD), - m_compression_stream_contains_data(false), - m_compressed_stream_file_writer(nullptr) { - m_compression_stream = ZSTD_createCStream(); + : m_compressed_stream_block{ + .dst = m_compressed_stream_block_buffer.data(), + .size = m_compressed_stream_block_buffer.size(), + .pos = 0 + } { if (nullptr == m_compression_stream) { SPDLOG_ERROR("streaming_compression::zstd::Compressor: ZSTD_createCStream() error"); throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__); @@ -19,20 +26,14 @@ Compressor::~Compressor() { ZSTD_freeCStream(m_compression_stream); } -void Compressor::open(FileWriter& file_writer, int const compression_level) { +auto Compressor::open(FileWriter& file_writer, int compression_level) -> void { if (nullptr != m_compressed_stream_file_writer) { throw OperationFailed(ErrorCode_NotReady, __FILENAME__, __LINE__); } - // Setup compressed stream parameters - size_t compressed_stream_block_size = ZSTD_CStreamOutSize(); - m_compressed_stream_block_buffer = std::make_unique(compressed_stream_block_size); - m_compressed_stream_block.dst = m_compressed_stream_block_buffer.get(); - m_compressed_stream_block.size = compressed_stream_block_size; - // Setup compression stream - auto init_result = ZSTD_initCStream(m_compression_stream, compression_level); - if (ZSTD_isError(init_result)) { + auto const init_result{ZSTD_initCStream(m_compression_stream, compression_level)}; + if (0 != ZSTD_isError(init_result)) { SPDLOG_ERROR( "streaming_compression::zstd::Compressor: ZSTD_initCStream() error: {}", ZSTD_getErrorName(init_result) @@ -45,7 +46,7 @@ void Compressor::open(FileWriter& file_writer, int const compression_level) { m_uncompressed_stream_pos = 0; } -void Compressor::close() { +auto Compressor::close() -> void { if (nullptr == m_compressed_stream_file_writer) { throw OperationFailed(ErrorCode_NotInit, __FILENAME__, __LINE__); } @@ -54,7 +55,7 @@ void Compressor::close() { m_compressed_stream_file_writer = nullptr; } -void Compressor::write(char const* data, size_t data_length) { +auto Compressor::write(char const* data, size_t data_length) -> void { if (nullptr == m_compressed_stream_file_writer) { throw OperationFailed(ErrorCode_NotInit, __FILENAME__, __LINE__); } @@ -70,23 +71,23 @@ void Compressor::write(char const* data, size_t data_length) { ZSTD_inBuffer uncompressed_stream_block = {data, data_length, 0}; while (uncompressed_stream_block.pos < uncompressed_stream_block.size) { m_compressed_stream_block.pos = 0; - auto error = ZSTD_compressStream( + auto const compress_result{ZSTD_compressStream( m_compression_stream, &m_compressed_stream_block, &uncompressed_stream_block - ); - if (ZSTD_isError(error)) { + )}; + if (0 != ZSTD_isError(compress_result)) { SPDLOG_ERROR( "streaming_compression::zstd::Compressor: ZSTD_compressStream() error: {}", - ZSTD_getErrorName(error) + ZSTD_getErrorName(compress_result) ); throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__); } - if (m_compressed_stream_block.pos) { + if (m_compressed_stream_block.pos > 0) { // Write to disk only if there is data in the compressed stream // block buffer m_compressed_stream_file_writer->write( - reinterpret_cast(m_compressed_stream_block.dst), + static_cast(m_compressed_stream_block.dst), m_compressed_stream_block.pos ); } @@ -96,14 +97,14 @@ void Compressor::write(char const* data, size_t data_length) { m_uncompressed_stream_pos += data_length; } -void Compressor::flush() { +auto Compressor::flush() -> void { if (false == m_compression_stream_contains_data) { return; } m_compressed_stream_block.pos = 0; - auto end_stream_result = ZSTD_endStream(m_compression_stream, &m_compressed_stream_block); - if (end_stream_result) { + auto const end_stream_result{ZSTD_endStream(m_compression_stream, &m_compressed_stream_block)}; + if (0 != ZSTD_isError(end_stream_result)) { // Note: Output buffer is large enough that it is guaranteed to have enough room to be // able to flush the entire buffer, so this can only be an error SPDLOG_ERROR( @@ -113,14 +114,14 @@ void Compressor::flush() { throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__); } m_compressed_stream_file_writer->write( - reinterpret_cast(m_compressed_stream_block.dst), + static_cast(m_compressed_stream_block.dst), m_compressed_stream_block.pos ); m_compression_stream_contains_data = false; } -ErrorCode Compressor::try_get_pos(size_t& pos) const { +auto Compressor::try_get_pos(size_t& pos) const -> ErrorCode { if (nullptr == m_compressed_stream_file_writer) { return ErrorCode_NotInit; } @@ -129,28 +130,28 @@ ErrorCode Compressor::try_get_pos(size_t& pos) const { return ErrorCode_Success; } -void Compressor::flush_without_ending_frame() { +auto Compressor::flush_without_ending_frame() -> void { if (false == m_compression_stream_contains_data) { return; } while (true) { m_compressed_stream_block.pos = 0; - auto result = ZSTD_flushStream(m_compression_stream, &m_compressed_stream_block); - if (ZSTD_isError(result)) { + auto const flush_result{ZSTD_flushStream(m_compression_stream, &m_compressed_stream_block)}; + if (0 != ZSTD_isError(flush_result)) { SPDLOG_ERROR( - "streaming_compression::zstd::Compressor: ZSTD_compressStream2() error: {}", - ZSTD_getErrorName(result) + "streaming_compression::zstd::Compressor: ZSTD_flushStream() error: {}", + ZSTD_getErrorName(flush_result) ); throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__); } - if (m_compressed_stream_block.pos) { + if (m_compressed_stream_block.pos > 0) { m_compressed_stream_file_writer->write( - reinterpret_cast(m_compressed_stream_block.dst), + static_cast(m_compressed_stream_block.dst), m_compressed_stream_block.pos ); } - if (0 == result) { + if (0 == flush_result) { break; } } diff --git a/components/core/src/clp/streaming_compression/zstd/Compressor.hpp b/components/core/src/clp/streaming_compression/zstd/Compressor.hpp index 75971dfa8..f55275f3e 100644 --- a/components/core/src/clp/streaming_compression/zstd/Compressor.hpp +++ b/components/core/src/clp/streaming_compression/zstd/Compressor.hpp @@ -1,12 +1,12 @@ #ifndef CLP_STREAMING_COMPRESSION_ZSTD_COMPRESSOR_HPP #define CLP_STREAMING_COMPRESSION_ZSTD_COMPRESSOR_HPP -#include -#include +#include #include -#include +#include "../../Array.hpp" +#include "../../ErrorCode.hpp" #include "../../FileWriter.hpp" #include "../../TraceableException.hpp" #include "../Compressor.hpp" @@ -20,11 +20,12 @@ class Compressor : public ::clp::streaming_compression::Compressor { public: // Constructors OperationFailed(ErrorCode error_code, char const* const filename, int line_number) - : TraceableException(error_code, filename, line_number) {} + : TraceableException{error_code, filename, line_number} {} // Methods - char const* what() const noexcept override { - return "streaming_compression::zstd::Compressor operation failed"; + [[nodiscard]] auto what() const noexcept -> char const* override { + return "streaming_compression::zstd::Compressor " + "operation failed"; } }; @@ -32,11 +33,15 @@ class Compressor : public ::clp::streaming_compression::Compressor { Compressor(); // Destructor - ~Compressor(); + ~Compressor() override; - // Explicitly disable copy and move constructor/assignment + // Delete copy constructor and assignment operator Compressor(Compressor const&) = delete; - Compressor& operator=(Compressor const&) = delete; + auto operator=(Compressor const&) -> Compressor& = delete; + + // Default move constructor and assignment operator + Compressor(Compressor&&) noexcept = default; + auto operator=(Compressor&&) noexcept -> Compressor& = default; // Methods implementing the WriterInterface /** @@ -44,11 +49,12 @@ class Compressor : public ::clp::streaming_compression::Compressor { * @param data * @param data_length */ - void write(char const* data, size_t data_length) override; + auto write(char const* data, size_t data_length) -> void override; + /** * Writes any internally buffered data to file and ends the current frame */ - void flush() override; + auto flush() -> void override; /** * Tries to get the current position of the write head @@ -56,39 +62,46 @@ class Compressor : public ::clp::streaming_compression::Compressor { * @return ErrorCode_NotInit if the compressor is not open * @return ErrorCode_Success on success */ - ErrorCode try_get_pos(size_t& pos) const override; + [[nodiscard]] auto try_get_pos(size_t& pos) const -> ErrorCode override; // Methods implementing the Compressor interface /** * Closes the compressor */ - void close() override; + auto close() -> void override; + + /** + * Initializes the compression stream with the default compression level + * @param file_writer + */ + auto open(FileWriter& file_writer) -> void override { + this->open(file_writer, cDefaultCompressionLevel); + } - // Methods /** - * Initialize streaming compressor + * Initializes the compression stream with the given compression level * @param file_writer * @param compression_level */ - void open(FileWriter& file_writer, int compression_level = cDefaultCompressionLevel); + auto open(FileWriter& file_writer, int compression_level) -> void; /** * Flushes the stream without ending the current frame */ - void flush_without_ending_frame(); + auto flush_without_ending_frame() -> void; private: // Variables - FileWriter* m_compressed_stream_file_writer; + FileWriter* m_compressed_stream_file_writer{nullptr}; // Compressed stream variables - ZSTD_CStream* m_compression_stream; - bool m_compression_stream_contains_data; + ZSTD_CStream* m_compression_stream{ZSTD_createCStream()}; + bool m_compression_stream_contains_data{false}; + Array m_compressed_stream_block_buffer{ZSTD_CStreamOutSize()}; ZSTD_outBuffer m_compressed_stream_block; - std::unique_ptr m_compressed_stream_block_buffer; - size_t m_uncompressed_stream_pos; + size_t m_uncompressed_stream_pos{0}; }; } // namespace clp::streaming_compression::zstd diff --git a/components/core/src/clp/streaming_compression/zstd/Constants.hpp b/components/core/src/clp/streaming_compression/zstd/Constants.hpp index a0e57e3e1..153478377 100644 --- a/components/core/src/clp/streaming_compression/zstd/Constants.hpp +++ b/components/core/src/clp/streaming_compression/zstd/Constants.hpp @@ -1,11 +1,8 @@ #ifndef CLP_STREAMING_COMPRESSION_ZSTD_CONSTANTS_HPP #define CLP_STREAMING_COMPRESSION_ZSTD_CONSTANTS_HPP -#include -#include - namespace clp::streaming_compression::zstd { -constexpr int cDefaultCompressionLevel = 3; +constexpr int cDefaultCompressionLevel{3}; } // namespace clp::streaming_compression::zstd #endif // CLP_STREAMING_COMPRESSION_ZSTD_CONSTANTS_HPP diff --git a/components/core/tests/test-StreamingCompression.cpp b/components/core/tests/test-StreamingCompression.cpp index 747a38a05..0fbae9e3a 100644 --- a/components/core/tests/test-StreamingCompression.cpp +++ b/components/core/tests/test-StreamingCompression.cpp @@ -1,230 +1,113 @@ +#include +#include #include +#include +#include #include -#include +#include #include #include +#include "../src/clp/Array.hpp" +#include "../src/clp/ErrorCode.hpp" +#include "../src/clp/FileWriter.hpp" #include "../src/clp/ReadOnlyMemoryMappedFile.hpp" +#include "../src/clp/streaming_compression/Compressor.hpp" +#include "../src/clp/streaming_compression/Decompressor.hpp" #include "../src/clp/streaming_compression/passthrough/Compressor.hpp" #include "../src/clp/streaming_compression/passthrough/Decompressor.hpp" #include "../src/clp/streaming_compression/zstd/Compressor.hpp" #include "../src/clp/streaming_compression/zstd/Decompressor.hpp" +using clp::Array; using clp::ErrorCode_Success; using clp::FileWriter; +using clp::streaming_compression::Compressor; +using clp::streaming_compression::Decompressor; TEST_CASE("StreamingCompression", "[StreamingCompression]") { - // Initialize data to test compression and decompression - size_t uncompressed_data_size = 128L * 1024 * 1024; // 128MB - char* uncompressed_data = new char[uncompressed_data_size]; - for (size_t i = 0; i < uncompressed_data_size; ++i) { - uncompressed_data[i] = (char)('a' + (i % 26)); + // Initialize constants + constexpr size_t cBufferSize{128L * 1024 * 1024}; // 128MB + constexpr auto cCompressionChunkSizes = std::to_array( + {cBufferSize / 100, + cBufferSize / 50, + cBufferSize / 25, + cBufferSize / 10, + cBufferSize / 5, + cBufferSize / 2, + cBufferSize} + ); + constexpr size_t cAlphabetLength{26}; + std::string const compressed_file_path{"test_streaming_compressed_file.bin"}; + + // Initialize compression devices + std::unique_ptr compressor; + std::unique_ptr decompressor; + + SECTION("ZStd single phase compression") { + compressor = std::make_unique(); + decompressor = std::make_unique(); } - // Create output buffer - char* decompressed_data = new char[uncompressed_data_size]; - - SECTION("zstd single phase compression") { - // Clear output buffer - memset(decompressed_data, 0, uncompressed_data_size); - std::string compressed_file_path = "compressed_file.zstd.bin.1"; - - // Compress - FileWriter file_writer; - file_writer.open(compressed_file_path, FileWriter::OpenMode::CREATE_FOR_WRITING); - clp::streaming_compression::zstd::Compressor compressor; - compressor.open(file_writer); - compressor.write(uncompressed_data, ZSTD_CStreamInSize()); - compressor.write(uncompressed_data, uncompressed_data_size / 100); - compressor.write(uncompressed_data, uncompressed_data_size / 50); - compressor.write(uncompressed_data, uncompressed_data_size / 25); - compressor.write(uncompressed_data, uncompressed_data_size / 10); - compressor.write(uncompressed_data, uncompressed_data_size / 5); - compressor.write(uncompressed_data, uncompressed_data_size / 2); - compressor.write(uncompressed_data, uncompressed_data_size); - compressor.close(); - file_writer.close(); - - // Decompress - clp::streaming_compression::zstd::Decompressor decompressor; - REQUIRE(ErrorCode_Success == decompressor.open(compressed_file_path)); - size_t uncompressed_bytes = 0; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - ZSTD_CStreamInSize() - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, ZSTD_CStreamInSize()) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += ZSTD_CStreamInSize(); - - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 100 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 100) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 100; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 50 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 50) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 50; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 25 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 25) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 25; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 10 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 10) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 10; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 5 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 5) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 5; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 2 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 2) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 2; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size; - - // Cleanup - boost::filesystem::remove(compressed_file_path); + SECTION("Passthrough compression") { + compressor = std::make_unique(); + decompressor = std::make_unique(); } - SECTION("passthrough compression") { - // Clear output buffer - memset(decompressed_data, 0, uncompressed_data_size); - std::string compressed_file_path = "compressed_file.passthrough.bin"; - - // Compress - FileWriter file_writer; - file_writer.open(compressed_file_path, FileWriter::OpenMode::CREATE_FOR_WRITING); - clp::streaming_compression::passthrough::Compressor compressor; - compressor.open(file_writer); - compressor.write(uncompressed_data, uncompressed_data_size / 100); - compressor.write(uncompressed_data, uncompressed_data_size / 50); - compressor.write(uncompressed_data, uncompressed_data_size / 25); - compressor.write(uncompressed_data, uncompressed_data_size / 10); - compressor.write(uncompressed_data, uncompressed_data_size / 5); - compressor.write(uncompressed_data, uncompressed_data_size / 2); - compressor.write(uncompressed_data, uncompressed_data_size); - compressor.close(); - file_writer.close(); - - // Decompress - // Memory map compressed file - clp::ReadOnlyMemoryMappedFile const memory_mapped_compressed_file{compressed_file_path}; - clp::streaming_compression::passthrough::Decompressor decompressor; - auto const compressed_file_view{memory_mapped_compressed_file.get_view()}; - decompressor.open(compressed_file_view.data(), compressed_file_view.size()); + // Initialize buffers + Array uncompressed_buffer{cBufferSize}; + for (size_t i{0}; i < cBufferSize; ++i) { + uncompressed_buffer.at(i) = static_cast(('a' + (i % cAlphabetLength))); + } - size_t uncompressed_bytes = 0; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 100 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 100) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 100; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 50 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 50) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 50; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 25 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 25) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 25; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 10 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 10) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 10; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 5 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 5) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 5; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size / 2 - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size / 2) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size / 2; - REQUIRE(ErrorCode_Success - == decompressor.get_decompressed_stream_region( - uncompressed_bytes, - decompressed_data, - uncompressed_data_size - )); - REQUIRE(memcmp(uncompressed_data, decompressed_data, uncompressed_data_size) == 0); - memset(decompressed_data, 0, uncompressed_data_size); - uncompressed_bytes += uncompressed_data_size; + Array decompressed_buffer{cBufferSize}; - // Cleanup - boost::filesystem::remove(compressed_file_path); + // Compress + FileWriter file_writer; + file_writer.open(compressed_file_path, FileWriter::OpenMode::CREATE_FOR_WRITING); + compressor->open(file_writer); + for (auto const chunk_size : cCompressionChunkSizes) { + compressor->write(uncompressed_buffer.data(), chunk_size); } + compressor->close(); + file_writer.close(); + + // Decompress and compare + clp::ReadOnlyMemoryMappedFile const memory_mapped_compressed_file{compressed_file_path}; + auto const compressed_file_view{memory_mapped_compressed_file.get_view()}; + decompressor->open(compressed_file_view.data(), compressed_file_view.size()); + + size_t num_uncompressed_bytes{0}; + for (auto const chunk_size : cCompressionChunkSizes) { + // Clear the buffer to ensure that we are not comparing values from a previous test + std::ranges::fill(decompressed_buffer.begin(), decompressed_buffer.end(), 0); + REQUIRE( + (ErrorCode_Success + == decompressor->get_decompressed_stream_region( + num_uncompressed_bytes, + decompressed_buffer.data(), + chunk_size + )) + ); + REQUIRE(std::equal( + uncompressed_buffer.begin(), + uncompressed_buffer.begin() + chunk_size, + decompressed_buffer.begin() + )); + num_uncompressed_bytes += chunk_size; + } + + // Sanity check + REQUIRE( + (std::accumulate( + cCompressionChunkSizes.cbegin(), + cCompressionChunkSizes.cend(), + size_t{0} + ) + == num_uncompressed_bytes) + ); // Cleanup - delete[] uncompressed_data; - delete[] decompressed_data; + boost::filesystem::remove(compressed_file_path); } From b8e22dacaa6532a970f0d717bc9ab57fa616e732 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:54:47 -0500 Subject: [PATCH 110/114] feat(clp-package): Add support for deleting archives that are exclusively within a time range. (#594) Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- .../clp_package_utils/__init__.py | 13 ++ .../clp_package_utils/general.py | 2 +- .../clp_package_utils/scripts/compress.py | 10 +- .../clp_package_utils/scripts/decompress.py | 14 +- .../clp_package_utils/scripts/del_archives.py | 103 +++++++++++++ .../scripts/native/compress.py | 8 - .../scripts/native/decompress.py | 8 - .../scripts/native/del_archives.py | 139 ++++++++++++++++++ .../scripts/native/search.py | 8 - .../clp_package_utils/scripts/search.py | 10 +- .../clp_package_utils/scripts/start_clp.py | 10 +- .../clp_package_utils/scripts/stop_clp.py | 10 +- .../src/sbin/admin-tools/del-archives.sh | 9 ++ 13 files changed, 272 insertions(+), 72 deletions(-) create mode 100644 components/clp-package-utils/clp_package_utils/scripts/del_archives.py create mode 100644 components/clp-package-utils/clp_package_utils/scripts/native/del_archives.py create mode 100755 components/package-template/src/sbin/admin-tools/del-archives.sh diff --git a/components/clp-package-utils/clp_package_utils/__init__.py b/components/clp-package-utils/clp_package_utils/__init__.py index e69de29bb..5253a87e5 100644 --- a/components/clp-package-utils/clp_package_utils/__init__.py +++ b/components/clp-package-utils/clp_package_utils/__init__.py @@ -0,0 +1,13 @@ +import logging + +# Set up console logging +logging_console_handler = logging.StreamHandler() +logging_formatter = logging.Formatter( + "%(asctime)s.%(msecs)03d %(levelname)s [%(module)s] %(message)s", datefmt="%Y-%m-%dT%H:%M:%S" +) +logging_console_handler.setFormatter(logging_formatter) + +# Set up root logger +root_logger = logging.getLogger() +root_logger.setLevel(logging.INFO) +root_logger.addHandler(logging_console_handler) diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index f42542ebc..5fae8166f 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -107,7 +107,7 @@ def get_clp_home(): return clp_home.resolve() -def generate_container_name(job_type: JobType) -> str: +def generate_container_name(job_type: str) -> str: """ :param job_type: :return: A unique container name for the given job type. diff --git a/components/clp-package-utils/clp_package_utils/scripts/compress.py b/components/clp-package-utils/clp_package_utils/scripts/compress.py index d0aa30913..efd3180ae 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/compress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/compress.py @@ -18,15 +18,7 @@ validate_and_load_db_credentials_file, ) -# Setup logging -# Create logger logger = logging.getLogger(__file__) -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) def main(argv): @@ -66,7 +58,7 @@ def main(argv): logger.exception("Failed to load config.") return -1 - container_name = generate_container_name(JobType.COMPRESSION) + container_name = generate_container_name(str(JobType.COMPRESSION)) container_clp_config, mounts = generate_container_config(clp_config, clp_home) generated_config_path_on_container, generated_config_path_on_host = dump_container_config( diff --git a/components/clp-package-utils/clp_package_utils/scripts/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/decompress.py index 9085fb162..325f2add6 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/decompress.py @@ -25,15 +25,7 @@ validate_path_could_be_dir, ) -# Setup logging -# Create logger -logger = logging.getLogger("clp") -logger.setLevel(logging.DEBUG) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) +logger = logging.getLogger(__file__) def validate_and_load_config( @@ -89,7 +81,7 @@ def handle_extract_file_cmd( if clp_config is None: return -1 - container_name = generate_container_name(JobType.FILE_EXTRACTION) + container_name = generate_container_name(str(JobType.FILE_EXTRACTION)) container_clp_config, mounts = generate_container_config(clp_config, clp_home) generated_config_path_on_container, generated_config_path_on_host = dump_container_config( container_clp_config, clp_config, container_name @@ -164,7 +156,7 @@ def handle_extract_stream_cmd( if clp_config is None: return -1 - container_name = generate_container_name(JobType.IR_EXTRACTION) + container_name = generate_container_name(str(JobType.IR_EXTRACTION)) container_clp_config, mounts = generate_container_config(clp_config, clp_home) generated_config_path_on_container, generated_config_path_on_host = dump_container_config( container_clp_config, clp_config, container_name diff --git a/components/clp-package-utils/clp_package_utils/scripts/del_archives.py b/components/clp-package-utils/clp_package_utils/scripts/del_archives.py new file mode 100644 index 000000000..54d959771 --- /dev/null +++ b/components/clp-package-utils/clp_package_utils/scripts/del_archives.py @@ -0,0 +1,103 @@ +import argparse +import logging +import subprocess +import sys +from pathlib import Path + +from clp_package_utils.general import ( + CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, + dump_container_config, + generate_container_config, + generate_container_name, + generate_container_start_cmd, + get_clp_home, + load_config_file, + validate_and_load_db_credentials_file, +) + +logger = logging.getLogger(__file__) + + +def main(argv): + clp_home = get_clp_home() + default_config_file_path = clp_home / CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH + + args_parser = argparse.ArgumentParser( + description="Deletes archives that fall within the specified time range." + ) + args_parser.add_argument( + "--config", + "-c", + default=str(default_config_file_path), + help="CLP package configuration file.", + ) + args_parser.add_argument( + "--begin-ts", + type=int, + default=0, + help="Time-range lower-bound (inclusive) as milliseconds from the UNIX epoch.", + ) + args_parser.add_argument( + "--end-ts", + type=int, + required=True, + help="Time-range upper-bound (include) as milliseconds from the UNIX epoch.", + ) + parsed_args = args_parser.parse_args(argv[1:]) + + # Validate and load config file + try: + config_file_path = Path(parsed_args.config) + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) + clp_config.validate_logs_dir() + + # Validate and load necessary credentials + validate_and_load_db_credentials_file(clp_config, clp_home, False) + except: + logger.exception("Failed to load config.") + return -1 + + # Validate the input timestamp + begin_ts = parsed_args.begin_ts + end_ts = parsed_args.end_ts + if begin_ts > end_ts: + logger.error("begin-ts must be <= end-ts") + return -1 + if end_ts < 0 or begin_ts < 0: + logger.error("begin_ts and end_ts must be non-negative.") + return -1 + + container_name = generate_container_name("del-archives") + + container_clp_config, mounts = generate_container_config(clp_config, clp_home) + generated_config_path_on_container, generated_config_path_on_host = dump_container_config( + container_clp_config, clp_config, container_name + ) + + necessary_mounts = [mounts.clp_home, mounts.logs_dir, mounts.archives_output_dir] + container_start_cmd = generate_container_start_cmd( + container_name, necessary_mounts, clp_config.execution_container + ) + + # fmt: off + del_archive_cmd = [ + "python3", + "-m", "clp_package_utils.scripts.native.del_archives", + "--config", str(generated_config_path_on_container), + str(begin_ts), + str(end_ts) + + ] + # fmt: on + + cmd = container_start_cmd + del_archive_cmd + subprocess.run(cmd, check=True) + + # Remove generated files + generated_config_path_on_host.unlink() + + return 0 + + +if "__main__" == __name__: + sys.exit(main(sys.argv)) diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/compress.py b/components/clp-package-utils/clp_package_utils/scripts/native/compress.py index cb495204f..b6d9bb7eb 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/compress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/compress.py @@ -23,15 +23,7 @@ load_config_file, ) -# Setup logging -# Create logger logger = logging.getLogger(__file__) -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) def print_compression_job_status(job_row, current_time): diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py index 7cce5d92a..d16cdcb6f 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/decompress.py @@ -32,15 +32,7 @@ wait_for_query_job, ) -# Setup logging -# Create logger logger = logging.getLogger(__file__) -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) def get_orig_file_id(db_config: Database, path: str) -> Optional[str]: diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/del_archives.py b/components/clp-package-utils/clp_package_utils/scripts/native/del_archives.py new file mode 100644 index 000000000..735bf299d --- /dev/null +++ b/components/clp-package-utils/clp_package_utils/scripts/native/del_archives.py @@ -0,0 +1,139 @@ +import argparse +import logging +import shutil +import sys +from contextlib import closing +from pathlib import Path +from typing import List + +from clp_py_utils.clp_config import Database +from clp_py_utils.sql_adapter import SQL_Adapter + +from clp_package_utils.general import ( + CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH, + get_clp_home, + load_config_file, +) + +logger = logging.getLogger(__file__) + + +def main(argv): + clp_home = get_clp_home() + default_config_file_path = clp_home / CLP_DEFAULT_CONFIG_FILE_RELATIVE_PATH + + args_parser = argparse.ArgumentParser( + description="Deletes archives that fall within the specified time range." + ) + args_parser.add_argument( + "--config", + "-c", + required=True, + default=str(default_config_file_path), + help="CLP configuration file.", + ) + args_parser.add_argument( + "begin_ts", + type=int, + help="Time-range lower-bound (inclusive) as milliseconds from the UNIX epoch.", + ) + args_parser.add_argument( + "end_ts", + type=int, + help="Time-range upper-bound (include) as milliseconds from the UNIX epoch.", + ) + parsed_args = args_parser.parse_args(argv[1:]) + + # Validate and load config file + config_file_path = Path(parsed_args.config) + try: + clp_config = load_config_file(config_file_path, default_config_file_path, clp_home) + clp_config.validate_logs_dir() + except: + logger.exception("Failed to load config.") + return -1 + + database_config = clp_config.database + archives_dir = clp_config.archive_output.directory + if not archives_dir.exists(): + logger.error("`archive_output.directory` doesn't exist.") + return -1 + + return _delete_archives( + archives_dir, + database_config, + parsed_args.begin_ts, + parsed_args.end_ts, + ) + + +def _delete_archives( + archives_dir: Path, + database_config: Database, + begin_ts: int, + end_ts: int, +) -> int: + """ + Deletes all archives where `begin_ts <= archive.begin_timestamp` and + `archive.end_timestamp <= end_ts` from both the metadata database and disk. + :param archives_dir: + :param database_config: + :param begin_ts: + :param end_ts: + :return: 0 on success, -1 otherwise. + """ + + archive_ids: List[str] + logger.info("Starting to delete archives from the database.") + try: + sql_adapter = SQL_Adapter(database_config) + clp_db_connection_params = database_config.get_clp_connection_params_and_type(True) + table_prefix = clp_db_connection_params["table_prefix"] + with closing(sql_adapter.create_connection(True)) as db_conn, closing( + db_conn.cursor(dictionary=True) + ) as db_cursor: + db_cursor.execute( + f""" + DELETE FROM `{table_prefix}archives` + WHERE begin_timestamp >= %s AND end_timestamp <= %s + RETURNING id + """, + (begin_ts, end_ts), + ) + results = db_cursor.fetchall() + + if 0 == len(results): + logger.info("No archives (exclusively) within the specified time range.") + return 0 + + archive_ids = [result["id"] for result in results] + db_cursor.execute( + f""" + DELETE FROM `{table_prefix}files` + WHERE archive_id in ({', '.join(['%s'] * len(archive_ids))}) + """, + archive_ids, + ) + db_conn.commit() + except Exception: + logger.exception("Failed to delete archives from the database. Aborting deletion.") + return -1 + + logger.info(f"Finished deleting archives from the database.") + + for archive_id in archive_ids: + archive_path = archives_dir / archive_id + if not archive_path.is_dir(): + logger.warning(f"Archive {archive_id} is not a directory. Skipping deletion.") + continue + + logger.info(f"Deleting archive {archive_id} from disk.") + shutil.rmtree(archive_path) + + logger.info(f"Finished deleting archives from disk.") + + return 0 + + +if "__main__" == __name__: + sys.exit(main(sys.argv)) diff --git a/components/clp-package-utils/clp_package_utils/scripts/native/search.py b/components/clp-package-utils/clp_package_utils/scripts/native/search.py index 7dd247fa5..d166cf35f 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/native/search.py +++ b/components/clp-package-utils/clp_package_utils/scripts/native/search.py @@ -26,15 +26,7 @@ wait_for_query_job, ) -# Setup logging -# Create logger logger = logging.getLogger(__file__) -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) def create_and_monitor_job_in_db( diff --git a/components/clp-package-utils/clp_package_utils/scripts/search.py b/components/clp-package-utils/clp_package_utils/scripts/search.py index f3f02046d..beb7fb0b0 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/search.py +++ b/components/clp-package-utils/clp_package_utils/scripts/search.py @@ -20,15 +20,7 @@ validate_and_load_db_credentials_file, ) -# Setup logging -# Create logger logger = logging.getLogger(__file__) -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) def main(argv): @@ -82,7 +74,7 @@ def main(argv): logger.exception("Failed to load config.") return -1 - container_name = generate_container_name(JobType.SEARCH) + container_name = generate_container_name(str(JobType.SEARCH)) container_clp_config, mounts = generate_container_config(clp_config, clp_home) generated_config_path_on_container, generated_config_path_on_host = dump_container_config( diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 6732ded0b..8097929f1 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -59,15 +59,7 @@ validate_worker_config, ) -# Setup logging -# Create logger -logger = logging.getLogger("clp") -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) +logger = logging.getLogger(__file__) def container_exists(container_name): diff --git a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py index f100a098a..a55d7a795 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/stop_clp.py @@ -31,15 +31,7 @@ validate_and_load_queue_credentials_file, ) -# Setup logging -# Create logger -logger = logging.getLogger("clp") -logger.setLevel(logging.INFO) -# Setup console logging -logging_console_handler = logging.StreamHandler() -logging_formatter = logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s] %(message)s") -logging_console_handler.setFormatter(logging_formatter) -logger.addHandler(logging_console_handler) +logger = logging.getLogger(__file__) def stop_running_container(container_name: str, already_exited_containers: List[str], force: bool): diff --git a/components/package-template/src/sbin/admin-tools/del-archives.sh b/components/package-template/src/sbin/admin-tools/del-archives.sh new file mode 100755 index 000000000..4d7ebc6b7 --- /dev/null +++ b/components/package-template/src/sbin/admin-tools/del-archives.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +package_root="$script_dir/../.." + +PYTHONPATH=$(readlink -f "$package_root/lib/python3/site-packages") \ + python3 \ + -m clp_package_utils.scripts.del_archives \ + "$@" From f1876cd63a56dd79a6243f6c8b6b6a7fd48348cc Mon Sep 17 00:00:00 2001 From: wraymo <37269683+wraymo@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:36:34 -0500 Subject: [PATCH 111/114] feat(clp-s): Add the write path for single-file archives. (#563) Co-authored-by: Devin Gibson --- components/core/src/clp_s/ArchiveWriter.cpp | 192 +++++++++++++++--- components/core/src/clp_s/ArchiveWriter.hpp | 66 +++++- .../core/src/clp_s/CommandLineArguments.cpp | 4 + .../core/src/clp_s/CommandLineArguments.hpp | 3 + components/core/src/clp_s/JsonParser.cpp | 1 + components/core/src/clp_s/JsonParser.hpp | 1 + .../core/src/clp_s/SingleFileArchiveDefs.hpp | 59 ++++++ .../src/clp_s/TimestampDictionaryWriter.cpp | 60 ++---- .../src/clp_s/TimestampDictionaryWriter.hpp | 43 ++-- components/core/src/clp_s/TimestampEntry.cpp | 23 ++- components/core/src/clp_s/TimestampEntry.hpp | 6 +- components/core/src/clp_s/Utils.hpp | 12 ++ .../core/src/clp_s/archive_constants.hpp | 3 + components/core/src/clp_s/clp-s.cpp | 1 + 14 files changed, 359 insertions(+), 115 deletions(-) create mode 100644 components/core/src/clp_s/SingleFileArchiveDefs.hpp diff --git a/components/core/src/clp_s/ArchiveWriter.cpp b/components/core/src/clp_s/ArchiveWriter.cpp index 7118ce88b..d627479de 100644 --- a/components/core/src/clp_s/ArchiveWriter.cpp +++ b/components/core/src/clp_s/ArchiveWriter.cpp @@ -1,6 +1,8 @@ #include "ArchiveWriter.hpp" #include +#include +#include #include @@ -13,18 +15,23 @@ void ArchiveWriter::open(ArchiveWriterOption const& option) { m_id = boost::uuids::to_string(option.id); m_compression_level = option.compression_level; m_print_archive_stats = option.print_archive_stats; + m_single_file_archive = option.single_file_archive; m_min_table_size = option.min_table_size; - auto archive_path = boost::filesystem::path(option.archives_dir) / m_id; + m_archives_dir = option.archives_dir; + std::string working_dir_name = m_id; + if (option.single_file_archive) { + working_dir_name += constants::cTmpPostfix; + } + auto archive_path = std::filesystem::path(option.archives_dir) / working_dir_name; - boost::system::error_code boost_error_code; - bool path_exists = boost::filesystem::exists(archive_path, boost_error_code); - if (path_exists) { + std::error_code ec; + if (std::filesystem::exists(archive_path, ec)) { SPDLOG_ERROR("Archive path already exists: {}", archive_path.c_str()); throw OperationFailed(ErrorCodeUnsupported, __FILENAME__, __LINE__); } m_archive_path = archive_path.string(); - if (false == boost::filesystem::create_directory(m_archive_path)) { + if (false == std::filesystem::create_directory(m_archive_path, ec)) { throw OperationFailed(ErrorCodeErrno, __FILENAME__, __LINE__); } @@ -39,20 +46,42 @@ void ArchiveWriter::open(ArchiveWriterOption const& option) { std::string array_dict_path = m_archive_path + constants::cArchiveArrayDictFile; m_array_dict = std::make_shared(); m_array_dict->open(array_dict_path, m_compression_level, UINT64_MAX); - - std::string timestamp_dict_path = m_archive_path + constants::cArchiveTimestampDictFile; - m_timestamp_dict = std::make_shared(); - m_timestamp_dict->open(timestamp_dict_path, m_compression_level); } void ArchiveWriter::close() { - m_compressed_size += m_var_dict->close(); - m_compressed_size += m_log_dict->close(); - m_compressed_size += m_array_dict->close(); - m_compressed_size += m_timestamp_dict->close(); - m_compressed_size += m_schema_tree.store(m_archive_path, m_compression_level); - m_compressed_size += m_schema_map.store(m_archive_path, m_compression_level); - m_compressed_size += store_tables(); + auto var_dict_compressed_size = m_var_dict->close(); + auto log_dict_compressed_size = m_log_dict->close(); + auto array_dict_compressed_size = m_array_dict->close(); + auto schema_tree_compressed_size = m_schema_tree.store(m_archive_path, m_compression_level); + auto schema_map_compressed_size = m_schema_map.store(m_archive_path, m_compression_level); + auto [table_metadata_compressed_size, table_compressed_size] = store_tables(); + + if (m_single_file_archive) { + std::vector files{ + {constants::cArchiveSchemaTreeFile, schema_tree_compressed_size}, + {constants::cArchiveSchemaMapFile, schema_map_compressed_size}, + {constants::cArchiveTableMetadataFile, table_metadata_compressed_size}, + {constants::cArchiveVarDictFile, var_dict_compressed_size}, + {constants::cArchiveLogDictFile, log_dict_compressed_size}, + {constants::cArchiveArrayDictFile, array_dict_compressed_size}, + {constants::cArchiveTablesFile, table_compressed_size} + }; + uint64_t offset = 0; + for (auto& file : files) { + uint64_t original_size = file.o; + file.o = offset; + offset += original_size; + } + write_single_file_archive(files); + } else { + // Timestamp dictionary written separately here until we transition to moving it inside of + // the metadata region of multi-file archives. + auto timestamp_dict_compressed_size = write_timestamp_dict(); + m_compressed_size = var_dict_compressed_size + log_dict_compressed_size + + array_dict_compressed_size + timestamp_dict_compressed_size + + schema_tree_compressed_size + schema_map_compressed_size + + table_metadata_compressed_size + table_compressed_size; + } if (m_metadata_db) { update_metadata_db(); @@ -65,12 +94,130 @@ void ArchiveWriter::close() { m_id_to_schema_writer.clear(); m_schema_tree.clear(); m_schema_map.clear(); + m_timestamp_dict.clear(); m_encoded_message_size = 0UL; m_uncompressed_size = 0UL; m_compressed_size = 0UL; m_next_log_event_id = 0; } +size_t ArchiveWriter::write_timestamp_dict() { + std::string timestamp_dict_path = m_archive_path + constants::cArchiveTimestampDictFile; + FileWriter timestamp_dict_file_writer; + ZstdCompressor timestamp_dict_compressor; + timestamp_dict_file_writer.open(timestamp_dict_path, FileWriter::OpenMode::CreateForWriting); + timestamp_dict_compressor.open(timestamp_dict_file_writer, m_compression_level); + std::stringstream timestamp_dict_stream; + m_timestamp_dict.write(timestamp_dict_stream); + std::string encoded_timestamp_dict = timestamp_dict_stream.str(); + timestamp_dict_compressor.write(encoded_timestamp_dict.data(), encoded_timestamp_dict.size()); + timestamp_dict_compressor.close(); + auto compressed_size = timestamp_dict_file_writer.get_pos(); + timestamp_dict_file_writer.close(); + return compressed_size; +} + +void ArchiveWriter::write_single_file_archive(std::vector const& files) { + std::string single_file_archive_path = (std::filesystem::path(m_archives_dir) / m_id).string(); + FileWriter archive_writer; + archive_writer.open(single_file_archive_path, FileWriter::OpenMode::CreateForWriting); + + write_archive_metadata(archive_writer, files); + size_t metadata_section_size = archive_writer.get_pos() - sizeof(ArchiveHeader); + write_archive_files(archive_writer, files); + m_compressed_size = archive_writer.get_pos(); + write_archive_header(archive_writer, metadata_section_size); + + archive_writer.close(); + std::error_code ec; + if (false == std::filesystem::remove(m_archive_path, ec)) { + throw OperationFailed(ErrorCodeFileExists, __FILENAME__, __LINE__); + } +} + +void ArchiveWriter::write_archive_metadata( + FileWriter& archive_writer, + std::vector const& files +) { + archive_writer.seek_from_begin(sizeof(ArchiveHeader)); + + ZstdCompressor compressor; + compressor.open(archive_writer, m_compression_level); + compressor.write_numeric_value(static_cast(3U)); // Number of packets + + // Write archive info + ArchiveInfoPacket archive_info{.num_segments = 1}; + std::stringstream msgpack_buffer; + msgpack::pack(msgpack_buffer, archive_info); + std::string archive_info_str = msgpack_buffer.str(); + compressor.write_numeric_value(ArchiveMetadataPacketType::ArchiveInfo); + compressor.write_numeric_value(static_cast(archive_info_str.size())); + compressor.write_string(archive_info_str); + + // Write archive file info + ArchiveFileInfoPacket archive_file_info{.files{files}}; + msgpack_buffer = std::stringstream{}; + msgpack::pack(msgpack_buffer, archive_file_info); + std::string archive_file_info_str = msgpack_buffer.str(); + compressor.write_numeric_value(ArchiveMetadataPacketType::ArchiveFileInfo); + compressor.write_numeric_value(static_cast(archive_file_info_str.size())); + compressor.write_string(archive_file_info_str); + + // Write timestamp dictionary + compressor.write_numeric_value(ArchiveMetadataPacketType::TimestampDictionary); + std::stringstream timestamp_dict_stream; + m_timestamp_dict.write(timestamp_dict_stream); + std::string encoded_timestamp_dict = timestamp_dict_stream.str(); + compressor.write_numeric_value(static_cast(encoded_timestamp_dict.size())); + compressor.write(encoded_timestamp_dict.data(), encoded_timestamp_dict.size()); + + compressor.close(); +} + +void ArchiveWriter::write_archive_files( + FileWriter& archive_writer, + std::vector const& files +) { + FileReader reader; + for (auto const& file : files) { + std::string file_path = m_archive_path + file.n; + reader.open(file_path); + char read_buffer[cReadBlockSize]; + while (true) { + size_t num_bytes_read{0}; + ErrorCode const error_code + = reader.try_read(read_buffer, cReadBlockSize, num_bytes_read); + if (ErrorCodeEndOfFile == error_code) { + break; + } else if (ErrorCodeSuccess != error_code) { + throw OperationFailed(error_code, __FILENAME__, __LINE__); + } + archive_writer.write(read_buffer, num_bytes_read); + } + reader.close(); + if (false == std::filesystem::remove(file_path)) { + throw OperationFailed(ErrorCodeFileExists, __FILENAME__, __LINE__); + } + } +} + +void ArchiveWriter::write_archive_header(FileWriter& archive_writer, size_t metadata_section_size) { + ArchiveHeader header{ + .magic_number{0}, + .version + = (cArchiveMajorVersion << 24) | (cArchiveMinorVersion << 16) | cArchivePatchVersion, + .uncompressed_size = m_uncompressed_size, + .compressed_size = m_compressed_size, + .reserved_padding{0}, + .metadata_section_size = static_cast(metadata_section_size), + .compression_type = static_cast(ArchiveCompressionType::Zstd), + .padding = 0 + }; + std::memcpy(&header.magic_number, cStructuredSFAMagicNumber, sizeof(header.magic_number)); + archive_writer.seek_from_begin(0); + archive_writer.write(reinterpret_cast(&header), sizeof(header)); +} + void ArchiveWriter::append_message( int32_t schema_id, Schema const& schema, @@ -132,8 +279,7 @@ void ArchiveWriter::initialize_schema_writer(SchemaWriter* writer, Schema const& } } -size_t ArchiveWriter::store_tables() { - size_t compressed_size = 0; +std::pair ArchiveWriter::store_tables() { m_tables_file_writer.open( m_archive_path + constants::cArchiveTablesFile, FileWriter::OpenMode::CreateForWriting @@ -243,13 +389,13 @@ size_t ArchiveWriter::store_tables() { } m_table_metadata_compressor.close(); - compressed_size += m_table_metadata_file_writer.get_pos(); - compressed_size += m_tables_file_writer.get_pos(); + auto table_metadata_compressed_size = m_table_metadata_file_writer.get_pos(); + auto table_compressed_size = m_tables_file_writer.get_pos(); m_table_metadata_file_writer.close(); m_tables_file_writer.close(); - return compressed_size; + return {table_metadata_compressed_size, table_compressed_size}; } void ArchiveWriter::update_metadata_db() { @@ -262,8 +408,8 @@ void ArchiveWriter::update_metadata_db() { metadata.increment_static_compressed_size(m_compressed_size); metadata.increment_static_uncompressed_size(m_uncompressed_size); metadata.expand_time_range( - m_timestamp_dict->get_begin_timestamp(), - m_timestamp_dict->get_end_timestamp() + m_timestamp_dict.get_begin_timestamp(), + m_timestamp_dict.get_end_timestamp() ); m_metadata_db->add_archive(m_id, metadata); diff --git a/components/core/src/clp_s/ArchiveWriter.hpp b/components/core/src/clp_s/ArchiveWriter.hpp index 87e9d11e5..3b13f4426 100644 --- a/components/core/src/clp_s/ArchiveWriter.hpp +++ b/components/core/src/clp_s/ArchiveWriter.hpp @@ -14,6 +14,7 @@ #include "SchemaMap.hpp" #include "SchemaTree.hpp" #include "SchemaWriter.hpp" +#include "SingleFileArchiveDefs.hpp" #include "TimestampDictionaryWriter.hpp" namespace clp_s { @@ -22,6 +23,7 @@ struct ArchiveWriterOption { std::string archives_dir; int compression_level; bool print_archive_stats; + bool single_file_archive; size_t min_table_size; }; @@ -125,7 +127,7 @@ class ArchiveWriter { std::string const& timestamp, uint64_t& pattern_id ) { - return m_timestamp_dict->ingest_entry(key, node_id, timestamp, pattern_id); + return m_timestamp_dict.ingest_entry(key, node_id, timestamp, pattern_id); } /** @@ -135,21 +137,24 @@ class ArchiveWriter { * @param timestamp */ void ingest_timestamp_entry(std::string const& key, int32_t node_id, double timestamp) { - m_timestamp_dict->ingest_entry(key, node_id, timestamp); + m_timestamp_dict.ingest_entry(key, node_id, timestamp); } void ingest_timestamp_entry(std::string const& key, int32_t node_id, int64_t timestamp) { - m_timestamp_dict->ingest_entry(key, node_id, timestamp); + m_timestamp_dict.ingest_entry(key, node_id, timestamp); } /** - * Increments the size of the compressed data written to the archive + * Increments the size of the original (uncompressed) logs ingested into the archive. This size + * tracks the raw input size before any encoding or compression. * @param size */ void increment_uncompressed_size(size_t size) { m_uncompressed_size += size; } /** - * @return Size of the uncompressed data written to the archive + * @return The total size of the encoded (uncompressed) data written to the archive. This + * reflects the size of the data after encoding but before compression. + * TODO: Add the size of schema tree, schema map and timestamp dictionary */ size_t get_data_size(); @@ -162,10 +167,40 @@ class ArchiveWriter { void initialize_schema_writer(SchemaWriter* writer, Schema const& schema); /** - * Stores the tables - * @return Size of the compressed data in bytes + * Compresses and stores the tables. + * @return A pair containing: + * - The size of the compressed table metadata in bytes. + * - The size of the compressed tables in bytes. */ - [[nodiscard]] size_t store_tables(); + [[nodiscard]] std::pair store_tables(); + + /** + * Writes the archive to a single file + * @param files + */ + void write_single_file_archive(std::vector const& files); + + /** + * Writes the metadata section of the single file archive + * @param archive_writer + * @param files + */ + void + write_archive_metadata(FileWriter& archive_writer, std::vector const& files); + + /** + * Writes the file section of the single file archive + * @param archive_writer + * @param files + */ + void write_archive_files(FileWriter& archive_writer, std::vector const& files); + + /** + * Writes the header section of the single file archive + * @param archive_writer + * @param metadata_section_size + */ + void write_archive_header(FileWriter& archive_writer, size_t metadata_section_size); /** * Updates the metadata db with the archive's metadata (id, size, timestamp ranges, etc.) @@ -177,6 +212,17 @@ class ArchiveWriter { */ void print_archive_stats(); + /** + * Write the timestamp dictionary as a dedicated file for multi-file archives. + * + * Note: the timestamp dictionary will be moved into the metadata region of multi-file archives + * in a follow-up PR. + * @return the compressed size of the Timestamp Dictionary in bytes + */ + size_t write_timestamp_dict(); + + static constexpr size_t cReadBlockSize = 4 * 1024; + size_t m_encoded_message_size{}; size_t m_uncompressed_size{}; size_t m_compressed_size{}; @@ -184,16 +230,18 @@ class ArchiveWriter { std::string m_id; + std::string m_archives_dir; std::string m_archive_path; std::string m_encoded_messages_dir; std::shared_ptr m_var_dict; std::shared_ptr m_log_dict; std::shared_ptr m_array_dict; // log type dictionary for arrays - std::shared_ptr m_timestamp_dict; + TimestampDictionaryWriter m_timestamp_dict; std::shared_ptr m_metadata_db; int m_compression_level{}; bool m_print_archive_stats{}; + bool m_single_file_archive{}; size_t m_min_table_size{}; SchemaMap m_schema_map; diff --git a/components/core/src/clp_s/CommandLineArguments.cpp b/components/core/src/clp_s/CommandLineArguments.cpp index d174b4a23..99539b627 100644 --- a/components/core/src/clp_s/CommandLineArguments.cpp +++ b/components/core/src/clp_s/CommandLineArguments.cpp @@ -190,6 +190,10 @@ CommandLineArguments::parse_arguments(int argc, char const** argv) { "print-archive-stats", po::bool_switch(&m_print_archive_stats), "Print statistics (json) about the archive after it's compressed." + )( + "single-file-archive", + po::bool_switch(&m_single_file_archive), + "Create a single archive file instead of multiple files." )( "structurize-arrays", po::bool_switch(&m_structurize_arrays), diff --git a/components/core/src/clp_s/CommandLineArguments.hpp b/components/core/src/clp_s/CommandLineArguments.hpp index 913e27fbc..a87e9b6bd 100644 --- a/components/core/src/clp_s/CommandLineArguments.hpp +++ b/components/core/src/clp_s/CommandLineArguments.hpp @@ -102,6 +102,8 @@ class CommandLineArguments { OutputHandlerType get_output_handler_type() const { return m_output_handler_type; } + bool get_single_file_archive() const { return m_single_file_archive; } + bool get_structurize_arrays() const { return m_structurize_arrays; } bool get_ordered_decompression() const { return m_ordered_decompression; } @@ -176,6 +178,7 @@ class CommandLineArguments { size_t m_target_encoded_size{8ULL * 1024 * 1024 * 1024}; // 8 GiB bool m_print_archive_stats{false}; size_t m_max_document_size{512ULL * 1024 * 1024}; // 512 MB + bool m_single_file_archive{false}; bool m_structurize_arrays{false}; bool m_ordered_decompression{false}; size_t m_target_ordered_chunk_size{}; diff --git a/components/core/src/clp_s/JsonParser.cpp b/components/core/src/clp_s/JsonParser.cpp index 9e8293510..d14a221b3 100644 --- a/components/core/src/clp_s/JsonParser.cpp +++ b/components/core/src/clp_s/JsonParser.cpp @@ -37,6 +37,7 @@ JsonParser::JsonParser(JsonParserOption const& option) m_archive_options.archives_dir = option.archives_dir; m_archive_options.compression_level = option.compression_level; m_archive_options.print_archive_stats = option.print_archive_stats; + m_archive_options.single_file_archive = option.single_file_archive; m_archive_options.min_table_size = option.min_table_size; m_archive_options.id = m_generator(); diff --git a/components/core/src/clp_s/JsonParser.hpp b/components/core/src/clp_s/JsonParser.hpp index d7cc5a2fe..bfd423c22 100644 --- a/components/core/src/clp_s/JsonParser.hpp +++ b/components/core/src/clp_s/JsonParser.hpp @@ -38,6 +38,7 @@ struct JsonParserOption { bool print_archive_stats{}; bool structurize_arrays{}; bool record_log_order{true}; + bool single_file_archive{false}; std::shared_ptr metadata_db; }; diff --git a/components/core/src/clp_s/SingleFileArchiveDefs.hpp b/components/core/src/clp_s/SingleFileArchiveDefs.hpp new file mode 100644 index 000000000..7eabeb6db --- /dev/null +++ b/components/core/src/clp_s/SingleFileArchiveDefs.hpp @@ -0,0 +1,59 @@ +#ifndef CLP_S_ARCHIVEDEFS_HPP +#define CLP_S_ARCHIVEDEFS_HPP + +#include + +#include "msgpack.hpp" + +namespace clp_s { +// define the version +constexpr uint8_t cArchiveMajorVersion = 0; +constexpr uint8_t cArchiveMinorVersion = 2; +constexpr uint16_t cArchivePatchVersion = 0; + +// define the magic number +constexpr uint8_t cStructuredSFAMagicNumber[] = {0xFD, 0x2F, 0xC5, 0x30}; + +struct ArchiveHeader { + uint8_t magic_number[4]; + uint32_t version; + uint64_t uncompressed_size; + uint64_t compressed_size; + uint64_t reserved_padding[4]; + uint32_t metadata_section_size; + uint16_t compression_type; + uint16_t padding; +}; + +enum class ArchiveCompressionType : uint16_t { + Zstd = 0, +}; + +enum struct ArchiveMetadataPacketType : uint8_t { + ArchiveInfo = 0, + ArchiveFileInfo = 1, + TimestampDictionary = 2, +}; + +struct ArchiveInfoPacket { + uint64_t num_segments; + // TODO: Add more fields in the future + + MSGPACK_DEFINE_MAP(num_segments); +}; + +struct ArchiveFileInfo { + std::string n; // name + uint64_t o; // offset + + MSGPACK_DEFINE_MAP(n, o); +}; + +struct ArchiveFileInfoPacket { + std::vector files; + + MSGPACK_DEFINE_MAP(files); +}; +} // namespace clp_s + +#endif // CLP_S_ARCHIVEDEFS_HPP diff --git a/components/core/src/clp_s/TimestampDictionaryWriter.cpp b/components/core/src/clp_s/TimestampDictionaryWriter.cpp index 7b02fd3a5..39e66a6af 100644 --- a/components/core/src/clp_s/TimestampDictionaryWriter.cpp +++ b/components/core/src/clp_s/TimestampDictionaryWriter.cpp @@ -1,63 +1,34 @@ #include "TimestampDictionaryWriter.hpp" +#include + #include "Utils.hpp" namespace clp_s { void TimestampDictionaryWriter::write_timestamp_entries( std::map const& ranges, - ZstdCompressor& compressor + std::stringstream& stream ) { - compressor.write_numeric_value(ranges.size()); + write_numeric_value(stream, ranges.size()); for (auto const& range : ranges) { - range.second.write_to_file(compressor); + range.second.write_to_stream(stream); } } -void TimestampDictionaryWriter::write_and_flush_to_disk() { - write_timestamp_entries(m_column_key_to_range, m_dictionary_compressor); +void TimestampDictionaryWriter::write(std::stringstream& stream) { + merge_range(); + write_timestamp_entries(m_column_key_to_range, stream); - m_dictionary_compressor.write_numeric_value(m_pattern_to_id.size()); + write_numeric_value(stream, m_pattern_to_id.size()); for (auto& it : m_pattern_to_id) { // write pattern ID - m_dictionary_compressor.write_numeric_value(it.second); + write_numeric_value(stream, it.second); std::string const& pattern = it.first->get_format(); - m_dictionary_compressor.write_numeric_value(pattern.length()); - m_dictionary_compressor.write_string(pattern); - } - - m_dictionary_compressor.flush(); - m_dictionary_file_writer.flush(); -} - -void TimestampDictionaryWriter::open(std::string const& dictionary_path, int compression_level) { - if (m_is_open) { - throw OperationFailed(ErrorCodeNotReady, __FILENAME__, __LINE__); - } - - m_dictionary_file_writer.open(dictionary_path, FileWriter::OpenMode::CreateForWriting); - m_dictionary_compressor.open(m_dictionary_file_writer, compression_level); - - m_next_id = 0; - m_is_open = true; -} - -size_t TimestampDictionaryWriter::close() { - if (false == m_is_open) { - throw OperationFailed(ErrorCodeNotInit, __FILENAME__, __LINE__); + write_numeric_value(stream, pattern.length()); + stream.write(pattern.data(), pattern.size()); } - - // merge before writing overall archive because this - // happens before the last sub-archive is written - merge_range(); - write_and_flush_to_disk(); - m_dictionary_compressor.close(); - size_t compressed_size = m_dictionary_file_writer.get_pos(); - m_dictionary_file_writer.close(); - - m_is_open = false; - return compressed_size; } uint64_t TimestampDictionaryWriter::get_pattern_id(TimestampPattern const* pattern) { @@ -180,4 +151,11 @@ epochtime_t TimestampDictionaryWriter::get_end_timestamp() const { return it->second.get_end_timestamp(); } + +void TimestampDictionaryWriter::clear() { + m_next_id = 0; + m_pattern_to_id.clear(); + m_column_key_to_range.clear(); + m_column_id_to_range.clear(); +} } // namespace clp_s diff --git a/components/core/src/clp_s/TimestampDictionaryWriter.hpp b/components/core/src/clp_s/TimestampDictionaryWriter.hpp index 81266b187..29288fd48 100644 --- a/components/core/src/clp_s/TimestampDictionaryWriter.hpp +++ b/components/core/src/clp_s/TimestampDictionaryWriter.hpp @@ -1,15 +1,15 @@ #ifndef CLP_S_TIMESTAMPDICTIONARYWRITER_HPP #define CLP_S_TIMESTAMPDICTIONARYWRITER_HPP +#include +#include #include #include #include -#include "FileWriter.hpp" #include "SchemaTree.hpp" #include "TimestampEntry.hpp" #include "TimestampPattern.hpp" -#include "ZstdCompressor.hpp" namespace clp_s { class TimestampDictionaryWriter { @@ -23,25 +23,13 @@ class TimestampDictionaryWriter { }; // Constructors - TimestampDictionaryWriter() : m_is_open(false) {} + TimestampDictionaryWriter() {} /** - * Opens the timestamp dictionary for writing - * @param dictionary_path - * @param compression_level + * Writes the timestamp dictionary to a buffered stream. + * @param stream */ - void open(std::string const& dictionary_path, int compression_level); - - /** - * Closes the timestamp dictionary - * @return the compressed size of the global timestamp dictionary in bytes - */ - [[nodiscard]] size_t close(); - - /** - * Writes the timestamp dictionary to disk - */ - void write_and_flush_to_disk(); + void write(std::stringstream& stream); /** * Gets the pattern id for a given pattern @@ -91,33 +79,30 @@ class TimestampDictionaryWriter { */ epochtime_t get_end_timestamp() const; + /** + * Clears and resets all internal state. + */ + void clear(); + private: /** - * Merges timestamp ranges with the same key name + * Merges timestamp ranges with the same key name but different node ids. */ void merge_range(); /** - * Writes timestamp entries to the disk + * Writes timestamp entries to a buffered stream. * @param ranges * @param compressor */ static void write_timestamp_entries( std::map const& ranges, - ZstdCompressor& compressor + std::stringstream& stream ); using pattern_to_id_t = std::unordered_map; // Variables - bool m_is_open; - - // Variables related to on-disk storage - FileWriter m_dictionary_file_writer; - ZstdCompressor m_dictionary_compressor; - FileWriter m_dictionary_file_writer_local; - ZstdCompressor m_dictionary_compressor_local; - pattern_to_id_t m_pattern_to_id; uint64_t m_next_id{}; diff --git a/components/core/src/clp_s/TimestampEntry.cpp b/components/core/src/clp_s/TimestampEntry.cpp index 54b27d22e..19d422066 100644 --- a/components/core/src/clp_s/TimestampEntry.cpp +++ b/components/core/src/clp_s/TimestampEntry.cpp @@ -1,6 +1,9 @@ #include "TimestampEntry.hpp" #include +#include + +#include "Utils.hpp" namespace clp_s { void TimestampEntry::ingest_timestamp(epochtime_t timestamp) { @@ -54,21 +57,21 @@ void TimestampEntry::merge_range(TimestampEntry const& entry) { } } -void TimestampEntry::write_to_file(ZstdCompressor& compressor) const { - compressor.write_numeric_value(m_key_name.size()); - compressor.write_string(m_key_name); - compressor.write_numeric_value(m_column_ids.size()); +void TimestampEntry::write_to_stream(std::stringstream& stream) const { + write_numeric_value(stream, m_key_name.size()); + stream.write(m_key_name.data(), m_key_name.size()); + write_numeric_value(stream, m_column_ids.size()); for (auto const& id : m_column_ids) { - compressor.write_numeric_value(id); + write_numeric_value(stream, id); } - compressor.write_numeric_value(m_encoding); + write_numeric_value(stream, m_encoding); if (m_encoding == Epoch) { - compressor.write_numeric_value(m_epoch_start); - compressor.write_numeric_value(m_epoch_end); + write_numeric_value(stream, m_epoch_start); + write_numeric_value(stream, m_epoch_end); } else if (m_encoding == DoubleEpoch) { - compressor.write_numeric_value(m_epoch_start_double); - compressor.write_numeric_value(m_epoch_end_double); + write_numeric_value(stream, m_epoch_start_double); + write_numeric_value(stream, m_epoch_end_double); } } diff --git a/components/core/src/clp_s/TimestampEntry.hpp b/components/core/src/clp_s/TimestampEntry.hpp index ad40b4b89..326ed9d73 100644 --- a/components/core/src/clp_s/TimestampEntry.hpp +++ b/components/core/src/clp_s/TimestampEntry.hpp @@ -1,6 +1,7 @@ #ifndef CLP_S_TIMESTAMPENTRY_HPP #define CLP_S_TIMESTAMPENTRY_HPP +#include #include #include #include @@ -9,7 +10,6 @@ #include "ErrorCode.hpp" #include "search/FilterOperation.hpp" #include "Utils.hpp" -#include "ZstdCompressor.hpp" #include "ZstdDecompressor.hpp" using clp_s::search::FilterOperation; @@ -66,10 +66,10 @@ class TimestampEntry { void merge_range(TimestampEntry const& entry); /** - * Write the timestamp entry to a file + * Write the timestamp entry to a buffered stream. * @param compressor */ - void write_to_file(ZstdCompressor& compressor) const; + void write_to_stream(std::stringstream& stream) const; /** * Try to read the timestamp entry from a file diff --git a/components/core/src/clp_s/Utils.hpp b/components/core/src/clp_s/Utils.hpp index d6deb3280..553f7e608 100644 --- a/components/core/src/clp_s/Utils.hpp +++ b/components/core/src/clp_s/Utils.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -254,6 +255,17 @@ inline T2 bit_cast(T1 t1) { return t2; } +/** + * Writes a numeric value to a stringstream. + * @param stream + * @param value + * @tparam ValueType + */ +template +void write_numeric_value(std::stringstream& stream, ValueType value) { + stream.write(reinterpret_cast(&value), sizeof(value)); +} + /** * A span of memory where the underlying memory may not be aligned correctly for type T. * diff --git a/components/core/src/clp_s/archive_constants.hpp b/components/core/src/clp_s/archive_constants.hpp index 604c97f66..b76af2944 100644 --- a/components/core/src/clp_s/archive_constants.hpp +++ b/components/core/src/clp_s/archive_constants.hpp @@ -4,6 +4,9 @@ #include namespace clp_s::constants { +// Single file archive +constexpr char cTmpPostfix[] = ".tmp"; + // Schema files constexpr char cArchiveSchemaMapFile[] = "/schema_ids"; constexpr char cArchiveSchemaTreeFile[] = "/schema_tree"; diff --git a/components/core/src/clp_s/clp-s.cpp b/components/core/src/clp_s/clp-s.cpp index a74693e33..b76683caf 100644 --- a/components/core/src/clp_s/clp-s.cpp +++ b/components/core/src/clp_s/clp-s.cpp @@ -95,6 +95,7 @@ bool compress(CommandLineArguments const& command_line_arguments) { option.compression_level = command_line_arguments.get_compression_level(); option.timestamp_key = command_line_arguments.get_timestamp_key(); option.print_archive_stats = command_line_arguments.print_archive_stats(); + option.single_file_archive = command_line_arguments.get_single_file_archive(); option.structurize_arrays = command_line_arguments.get_structurize_arrays(); option.record_log_order = command_line_arguments.get_record_log_order(); From 12cdf6d6b96b0bd8719bbfaf224146d1b0139b35 Mon Sep 17 00:00:00 2001 From: "Xiaochong(Eddy) Wei" <40865608+anlowee@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:52:30 -0500 Subject: [PATCH 112/114] test: Allow multiple trials when unittesting http headers (#613) Co-authored-by: Xiaochong Wei --- components/core/tests/test-NetworkReader.cpp | 38 ++++++++++++-------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/components/core/tests/test-NetworkReader.cpp b/components/core/tests/test-NetworkReader.cpp index f2995f141..552775ea8 100644 --- a/components/core/tests/test-NetworkReader.cpp +++ b/components/core/tests/test-NetworkReader.cpp @@ -196,26 +196,36 @@ TEST_CASE("network_reader_with_valid_http_header_kv_pairs", "[NetworkReader]") { std::unordered_map valid_http_header_kv_pairs; // We use httpbin (https://httpbin.org/) to test the user-specified headers. On success, it is // supposed to respond all the user-specified headers as key-value pairs in JSON form. - constexpr int cNumHttpHeaderKeyValuePairs{10}; + constexpr size_t cNumHttpHeaderKeyValuePairs{10}; for (size_t i{0}; i < cNumHttpHeaderKeyValuePairs; ++i) { valid_http_header_kv_pairs.emplace( fmt::format("Unit-Test-Key{}", i), fmt::format("Unit-Test-Value{}", i) ); } - clp::NetworkReader reader{ - "https://httpbin.org/headers", - 0, - false, - clp::CurlDownloadHandler::cDefaultOverallTimeout, - clp::CurlDownloadHandler::cDefaultConnectionTimeout, - clp::NetworkReader::cDefaultBufferPoolSize, - clp::NetworkReader::cDefaultBufferSize, - valid_http_header_kv_pairs - }; - auto const content{get_content(reader)}; - REQUIRE(assert_curl_error_code(CURLE_OK, reader)); - auto const parsed_content = nlohmann::json::parse(content); + std::optional> optional_content; + // Retry the unit test a limited number of times to handle transient server-side HTTP errors. + // This ensures the test is not marked as failed due to temporary issues beyond our control. + constexpr size_t cNumMaxTrials{10}; + for (size_t i{0}; i < cNumMaxTrials; ++i) { + clp::NetworkReader reader{ + "https://httpbin.org/headers", + 0, + false, + clp::CurlDownloadHandler::cDefaultOverallTimeout, + clp::CurlDownloadHandler::cDefaultConnectionTimeout, + clp::NetworkReader::cDefaultBufferPoolSize, + clp::NetworkReader::cDefaultBufferSize, + valid_http_header_kv_pairs + }; + auto const content = get_content(reader); + if (assert_curl_error_code(CURLE_OK, reader)) { + optional_content.emplace(content); + break; + } + } + REQUIRE(optional_content.has_value()); + auto const parsed_content = nlohmann::json::parse(optional_content.value()); auto const& headers{parsed_content.at("headers")}; for (auto const& [key, value] : valid_http_header_kv_pairs) { REQUIRE((value == headers.at(key).get())); From 5881b9c6125918db75aa77b37f9d854a7c17642d Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Fri, 29 Nov 2024 03:54:23 -0500 Subject: [PATCH 113/114] chore(log-viewer-webui): Update `yscope-log-viewer` to the latest version. (#615) --- components/log-viewer-webui/yscope-log-viewer | 2 +- deps-tasks.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/log-viewer-webui/yscope-log-viewer b/components/log-viewer-webui/yscope-log-viewer index 4c69bc11d..969ff35b2 160000 --- a/components/log-viewer-webui/yscope-log-viewer +++ b/components/log-viewer-webui/yscope-log-viewer @@ -1 +1 @@ -Subproject commit 4c69bc11dbe8a5d87b5fbfb0e43a2f2a06f04866 +Subproject commit 969ff35b2387bcdc3580b441907e3656640ce16d diff --git a/deps-tasks.yml b/deps-tasks.yml index 64a218a47..3c60af001 100644 --- a/deps-tasks.yml +++ b/deps-tasks.yml @@ -421,8 +421,8 @@ tasks: vars: DEST: "{{.DEST}}" FLAGS: "--extract" - SRC_NAME: "yscope-log-viewer-4c69bc11dbe8a5d87b5fbfb0e43a2f2a06f04866" - SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/4c69bc1.zip" + SRC_NAME: "yscope-log-viewer-969ff35b2387bcdc3580b441907e3656640ce16d" + SRC_URL: "https://github.com/y-scope/yscope-log-viewer/archive/969ff35.zip" # This command must be last - task: ":utils:compute-checksum" vars: From 88d83bf419e5dddb54475e9b6720d751b0d4f461 Mon Sep 17 00:00:00 2001 From: Abigail Matthews Date: Mon, 2 Dec 2024 00:48:07 -0500 Subject: [PATCH 114/114] test(clp-s): Add end-to-end test case for compression and extraction. (#595) --- components/core/CMakeLists.txt | 54 +++++- .../core/tests/test-clp_s-end_to_end.cpp | 158 ++++++++++++++++++ .../test_no_floats_sorted.jsonl | 4 + .../install-prebuilt-packages.sh | 2 + .../ubuntu-focal/install-prebuilt-packages.sh | 1 + .../ubuntu-jammy/install-prebuilt-packages.sh | 1 + 6 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 components/core/tests/test-clp_s-end_to_end.cpp create mode 100644 components/core/tests/test_log_files/test_no_floats_sorted.jsonl diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index e5c9b06c8..1b4fdb1be 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -241,6 +241,42 @@ add_subdirectory(src/clp_s) add_subdirectory(src/reducer) set(SOURCE_FILES_clp_s_unitTest + src/clp_s/ArchiveReader.cpp + src/clp_s/ArchiveReader.hpp + src/clp_s/ArchiveWriter.cpp + src/clp_s/ArchiveWriter.hpp + src/clp_s/ColumnReader.cpp + src/clp_s/ColumnReader.hpp + src/clp_s/ColumnWriter.cpp + src/clp_s/ColumnWriter.hpp + src/clp_s/DictionaryEntry.cpp + src/clp_s/DictionaryEntry.hpp + src/clp_s/DictionaryWriter.cpp + src/clp_s/DictionaryWriter.hpp + src/clp_s/FileReader.cpp + src/clp_s/FileReader.hpp + src/clp_s/FileWriter.cpp + src/clp_s/FileWriter.hpp + src/clp_s/JsonConstructor.cpp + src/clp_s/JsonConstructor.hpp + src/clp_s/JsonFileIterator.cpp + src/clp_s/JsonFileIterator.hpp + src/clp_s/JsonParser.cpp + src/clp_s/JsonParser.hpp + src/clp_s/PackedStreamReader.cpp + src/clp_s/PackedStreamReader.hpp + src/clp_s/ReaderUtils.cpp + src/clp_s/ReaderUtils.hpp + src/clp_s/Schema.cpp + src/clp_s/Schema.hpp + src/clp_s/SchemaMap.cpp + src/clp_s/SchemaMap.hpp + src/clp_s/SchemaReader.cpp + src/clp_s/SchemaReader.hpp + src/clp_s/SchemaTree.cpp + src/clp_s/SchemaTree.hpp + src/clp_s/SchemaWriter.cpp + src/clp_s/SchemaWriter.hpp src/clp_s/search/AndExpr.cpp src/clp_s/search/AndExpr.hpp src/clp_s/search/BooleanLiteral.cpp @@ -273,11 +309,24 @@ set(SOURCE_FILES_clp_s_unitTest src/clp_s/search/StringLiteral.hpp src/clp_s/search/Transformation.hpp src/clp_s/search/Value.hpp - src/clp_s/SchemaTree.hpp + src/clp_s/TimestampDictionaryReader.cpp + src/clp_s/TimestampDictionaryReader.hpp + src/clp_s/TimestampDictionaryWriter.cpp + src/clp_s/TimestampDictionaryWriter.hpp + src/clp_s/TimestampEntry.cpp + src/clp_s/TimestampEntry.hpp src/clp_s/TimestampPattern.cpp src/clp_s/TimestampPattern.hpp src/clp_s/Utils.cpp src/clp_s/Utils.hpp + src/clp_s/VariableDecoder.cpp + src/clp_s/VariableDecoder.hpp + src/clp_s/VariableEncoder.cpp + src/clp_s/VariableEncoder.hpp + src/clp_s/ZstdCompressor.cpp + src/clp_s/ZstdCompressor.hpp + src/clp_s/ZstdDecompressor.cpp + src/clp_s/ZstdDecompressor.hpp ) set(SOURCE_FILES_unitTest @@ -499,6 +548,7 @@ set(SOURCE_FILES_unitTest tests/LogSuppressor.hpp tests/test-Array.cpp tests/test-BufferedFileReader.cpp + tests/test-clp_s-end_to_end.cpp tests/test-EncodedVariableInterpreter.cpp tests/test-encoding_methods.cpp tests/test-ffi_IrUnitHandlerInterface.cpp @@ -542,6 +592,8 @@ target_link_libraries(unitTest log_surgeon::log_surgeon LibArchive::LibArchive MariaDBClient::MariaDBClient + ${MONGOCXX_TARGET} + simdjson spdlog::spdlog OpenSSL::Crypto ${sqlite_LIBRARY_DEPENDENCIES} diff --git a/components/core/tests/test-clp_s-end_to_end.cpp b/components/core/tests/test-clp_s-end_to_end.cpp new file mode 100644 index 000000000..3f138b472 --- /dev/null +++ b/components/core/tests/test-clp_s-end_to_end.cpp @@ -0,0 +1,158 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "../src/clp_s/JsonConstructor.hpp" +#include "../src/clp_s/JsonParser.hpp" + +constexpr std::string_view cTestEndToEndArchiveDirectory{"test-end-to-end-archive"}; +constexpr std::string_view cTestEndToEndOutputDirectory{"test-end-to-end-out"}; +constexpr std::string_view cTestEndToEndOutputSortedJson{"test-end-to-end_sorted.jsonl"}; +constexpr std::string_view cTestEndToEndInputFileDirectory{"test_log_files"}; +constexpr std::string_view cTestEndToEndInputFile{"test_no_floats_sorted.jsonl"}; + +namespace { +/** + * A class that deletes the directories and files created by test cases, both before and after each + * test case where the class is instantiated. + */ +class TestOutputCleaner { +public: + TestOutputCleaner() { delete_files(); } + + ~TestOutputCleaner() { delete_files(); } + + // Delete copy & move constructors and assignment operators + TestOutputCleaner(TestOutputCleaner const&) = delete; + TestOutputCleaner(TestOutputCleaner&&) = delete; + auto operator=(TestOutputCleaner const&) -> TestOutputCleaner& = delete; + auto operator=(TestOutputCleaner&&) -> TestOutputCleaner& = delete; + +private: + static void delete_files() { + std::filesystem::remove_all(cTestEndToEndArchiveDirectory); + std::filesystem::remove_all(cTestEndToEndOutputDirectory); + std::filesystem::remove(cTestEndToEndOutputSortedJson); + } +}; + +auto get_test_input_path_relative_to_tests_dir() -> std::filesystem::path; +auto get_test_input_local_path() -> std::string; +void compress(bool structurize_arrays); +auto extract() -> std::filesystem::path; +void compare(std::filesystem::path const& extracted_json_path); + +auto get_test_input_path_relative_to_tests_dir() -> std::filesystem::path { + return std::filesystem::path{cTestEndToEndInputFileDirectory} / cTestEndToEndInputFile; +} + +auto get_test_input_local_path() -> std::string { + std::filesystem::path const current_file_path{__FILE__}; + auto const tests_dir{current_file_path.parent_path()}; + return (tests_dir / get_test_input_path_relative_to_tests_dir()).string(); +} + +void compress(bool structurize_arrays) { + constexpr auto cDefaultTargetEncodedSize = 8ULL * 1024 * 1024 * 1024; // 8 GiB + constexpr auto cDefaultMaxDocumentSize = 512ULL * 1024 * 1024; // 512 MiB + constexpr auto cDefaultMinTableSize = 1ULL * 1024 * 1024; // 1 MiB + constexpr auto cDefaultCompressionLevel = 3; + constexpr auto cDefaultPrintArchiveStats = false; + + std::filesystem::create_directory(cTestEndToEndArchiveDirectory); + REQUIRE((std::filesystem::is_directory(cTestEndToEndArchiveDirectory))); + + clp_s::JsonParserOption parser_option{}; + parser_option.file_paths.push_back(get_test_input_local_path()); + parser_option.archives_dir = cTestEndToEndArchiveDirectory; + parser_option.target_encoded_size = cDefaultTargetEncodedSize; + parser_option.max_document_size = cDefaultMaxDocumentSize; + parser_option.min_table_size = cDefaultMinTableSize; + parser_option.compression_level = cDefaultCompressionLevel; + parser_option.print_archive_stats = cDefaultPrintArchiveStats; + parser_option.structurize_arrays = structurize_arrays; + + clp_s::JsonParser parser{parser_option}; + REQUIRE(parser.parse()); + parser.store(); + + REQUIRE((false == std::filesystem::is_empty(cTestEndToEndArchiveDirectory))); +} + +auto extract() -> std::filesystem::path { + constexpr auto cDefaultOrdered = false; + constexpr auto cDefaultTargetOrderedChunkSize = 0; + + std::filesystem::create_directory(cTestEndToEndOutputDirectory); + REQUIRE(std::filesystem::is_directory(cTestEndToEndOutputDirectory)); + + clp_s::JsonConstructorOption constructor_option{}; + constructor_option.archives_dir = cTestEndToEndArchiveDirectory; + constructor_option.output_dir = cTestEndToEndOutputDirectory; + constructor_option.ordered = cDefaultOrdered; + constructor_option.target_ordered_chunk_size = cDefaultTargetOrderedChunkSize; + for (auto const& entry : std::filesystem::directory_iterator(constructor_option.archives_dir)) { + if (false == entry.is_directory()) { + // Skip non-directories + continue; + } + + constructor_option.archive_id = entry.path().filename(); + clp_s::JsonConstructor constructor{constructor_option}; + constructor.store(); + } + std::filesystem::path extracted_json_path{cTestEndToEndOutputDirectory}; + extracted_json_path /= "original"; + REQUIRE(std::filesystem::exists(extracted_json_path)); + + return extracted_json_path; +} + +// Silence the checks below since our use of `std::system` is safe in the context of testing. +// NOLINTBEGIN(cert-env33-c,concurrency-mt-unsafe) +void compare(std::filesystem::path const& extracted_json_path) { + int result{std::system("command -v jq >/dev/null 2>&1")}; + REQUIRE((0 == result)); + auto command = fmt::format( + "jq --sort-keys --compact-output '.' {} | sort > {}", + extracted_json_path.string(), + cTestEndToEndOutputSortedJson + ); + result = std::system(command.c_str()); + REQUIRE((0 == result)); + + REQUIRE((false == std::filesystem::is_empty(cTestEndToEndOutputSortedJson))); + + result = std::system("command -v diff >/dev/null 2>&1"); + REQUIRE((0 == result)); + command = fmt::format( + "diff --unified {} {} > /dev/null", + cTestEndToEndOutputSortedJson, + get_test_input_local_path() + ); + result = std::system(command.c_str()); + REQUIRE((true == WIFEXITED(result))); + REQUIRE((0 == WEXITSTATUS(result))); +} + +// NOLINTEND(cert-env33-c,concurrency-mt-unsafe) +} // namespace + +TEST_CASE("clp-s-compress-extract-no-floats", "[clp-s][end-to-end]") { + auto structurize_arrays = GENERATE(true, false); + + TestOutputCleaner const test_cleanup; + + compress(structurize_arrays); + + auto extracted_json_path = extract(); + + compare(extracted_json_path); +} diff --git a/components/core/tests/test_log_files/test_no_floats_sorted.jsonl b/components/core/tests/test_log_files/test_no_floats_sorted.jsonl new file mode 100644 index 000000000..8dfcd85f6 --- /dev/null +++ b/components/core/tests/test_log_files/test_no_floats_sorted.jsonl @@ -0,0 +1,4 @@ +{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_array":[],"empty_object":{},"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"null":null,"string":"short_string","true":true} +{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_array":[],"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"nonempty_object":{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_array":[],"empty_object":{},"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"null":null,"string":"short_string","true":true},"null":null,"string":"short_string","true":true} +{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_array":[],"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"nonempty_object":{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_array":[],"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"non_empty_object2":{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_array":[],"empty_object":{},"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"null":null,"string":"short_string","true":true},"null":null,"string":"short_string","true":true},"null":null,"string":"short_string","true":true} +{"clp_string":"uid=0, CPU usage:99.99%, \"user_name\"=YScope","empty_object":{},"false":false,"int16_max":32767,"int16_min":-32768,"int32_max":2147483647,"int32_min":-2147483648,"int64_max_jq_losslessly_represents":9824299763229016,"int64_min_jq_losslessly_represents":-9007199254740992,"int8_max":127,"int8_min":-128,"nonempty_array":[1,2,3,4,5],"null":null,"string":"short_string","true":true} diff --git a/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh b/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh index e90f54733..66ea4ac4f 100755 --- a/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh +++ b/components/core/tools/scripts/lib_install/centos-stream-9/install-prebuilt-packages.sh @@ -8,9 +8,11 @@ set -u dnf install -y \ cmake \ + diffutils \ gcc-c++ \ git \ java-11-openjdk \ + jq \ libarchive-devel \ libcurl-devel \ libzstd-devel \ diff --git a/components/core/tools/scripts/lib_install/ubuntu-focal/install-prebuilt-packages.sh b/components/core/tools/scripts/lib_install/ubuntu-focal/install-prebuilt-packages.sh index 706674764..8997ffe01 100755 --- a/components/core/tools/scripts/lib_install/ubuntu-focal/install-prebuilt-packages.sh +++ b/components/core/tools/scripts/lib_install/ubuntu-focal/install-prebuilt-packages.sh @@ -17,6 +17,7 @@ DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ gcc \ gcc-10 \ git \ + jq \ libcurl4 \ libcurl4-openssl-dev \ libmariadb-dev \ diff --git a/components/core/tools/scripts/lib_install/ubuntu-jammy/install-prebuilt-packages.sh b/components/core/tools/scripts/lib_install/ubuntu-jammy/install-prebuilt-packages.sh index 92d965b9b..9ed6b9b10 100755 --- a/components/core/tools/scripts/lib_install/ubuntu-jammy/install-prebuilt-packages.sh +++ b/components/core/tools/scripts/lib_install/ubuntu-jammy/install-prebuilt-packages.sh @@ -14,6 +14,7 @@ DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ curl \ build-essential \ git \ + jq \ libboost-filesystem-dev \ libboost-iostreams-dev \ libboost-program-options-dev \