commit c6ba83f5d782c116e5192787da9067c72f50d2c3 Author: anian Date: Sun Jul 19 01:16:28 2026 +0800 1.13.1原版 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..444940d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,520 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 4 +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_wrap_on_typing = false + +[*.java] +max_line_length = 100 +ij_continuation_indent_size = 4 +ij_java_align_consecutive_assignments = false +ij_java_align_consecutive_variable_declarations = false +ij_java_align_group_field_declarations = false +ij_java_align_multiline_annotation_parameters = false +ij_java_align_multiline_array_initializer_expression = false +ij_java_align_multiline_assignment = false +ij_java_align_multiline_binary_operation = false +ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_extends_list = false +ij_java_align_multiline_for = true +ij_java_align_multiline_method_parentheses = false +ij_java_align_multiline_parameters = false +ij_java_align_multiline_parameters_in_calls = false +ij_java_align_multiline_parenthesized_expression = false +ij_java_align_multiline_records = true +ij_java_align_multiline_resources = true +ij_java_align_multiline_ternary_operation = false +ij_java_align_multiline_text_blocks = false +ij_java_align_multiline_throws_list = false +ij_java_align_subsequent_simple_methods = false +ij_java_align_throws_keyword = false +ij_java_annotation_parameter_wrap = off +ij_java_array_initializer_new_line_after_left_brace = false +ij_java_array_initializer_right_brace_on_new_line = false +ij_java_array_initializer_wrap = normal +ij_java_assert_statement_colon_on_next_line = false +ij_java_assert_statement_wrap = normal +ij_java_assignment_wrap = normal +ij_java_binary_operation_sign_on_next_line = true +ij_java_binary_operation_wrap = normal +ij_java_blank_lines_after_anonymous_class_header = 0 +ij_java_blank_lines_after_class_header = 0 +ij_java_blank_lines_after_imports = 1 +ij_java_blank_lines_after_package = 1 +ij_java_blank_lines_around_class = 1 +ij_java_blank_lines_around_field = 0 +ij_java_blank_lines_around_field_in_interface = 0 +ij_java_blank_lines_around_initializer = 1 +ij_java_blank_lines_around_method = 1 +ij_java_blank_lines_around_method_in_interface = 1 +ij_java_blank_lines_before_class_end = 0 +ij_java_blank_lines_before_imports = 0 +ij_java_blank_lines_before_method_body = 0 +ij_java_blank_lines_before_package = 1 +ij_java_block_brace_style = end_of_line +ij_java_block_comment_at_first_column = false +ij_java_call_parameters_new_line_after_left_paren = false +ij_java_call_parameters_right_paren_on_new_line = false +ij_java_call_parameters_wrap = normal +ij_java_case_statement_on_separate_line = true +ij_java_catch_on_new_line = false +ij_java_class_annotation_wrap = split_into_lines +ij_java_class_brace_style = end_of_line +ij_java_class_count_to_use_import_on_demand = 999 +ij_java_class_names_in_javadoc = 1 +ij_java_do_not_indent_top_level_class_members = false +ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_while_brace_force = always +ij_java_doc_add_blank_line_after_description = true +ij_java_doc_add_blank_line_after_param_comments = false +ij_java_doc_add_blank_line_after_return = false +ij_java_doc_add_p_tag_on_empty_lines = true +ij_java_doc_align_exception_comments = true +ij_java_doc_align_param_comments = false +ij_java_doc_do_not_wrap_if_one_line = false +ij_java_doc_enable_formatting = true +ij_java_doc_enable_leading_asterisks = true +ij_java_doc_indent_on_continuation = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_return_tag = true +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true +ij_java_doc_param_description_on_new_line = false +ij_java_doc_preserve_line_breaks = false +ij_java_doc_use_throws_not_exception_tag = true +ij_java_else_on_new_line = false +ij_java_enum_constants_wrap = normal +ij_java_extends_keyword_wrap = normal +ij_java_extends_list_wrap = normal +ij_java_field_annotation_wrap = split_into_lines +ij_java_finally_on_new_line = false +ij_java_for_brace_force = always +ij_java_for_statement_new_line_after_left_paren = false +ij_java_for_statement_right_paren_on_new_line = false +ij_java_for_statement_wrap = normal +ij_java_generate_final_locals = false +ij_java_generate_final_parameters = false +ij_java_if_brace_force = always +ij_java_imports_layout = $*, |, *, |, * +ij_java_indent_case_from_switch = true +ij_java_insert_inner_class_imports = false +ij_java_insert_override_annotation = true +ij_java_keep_blank_lines_before_right_brace = 2 +ij_java_keep_blank_lines_between_package_declaration_and_header = 2 +ij_java_keep_blank_lines_in_code = 2 +ij_java_keep_blank_lines_in_declarations = 2 +ij_java_keep_control_statement_in_one_line = true +ij_java_keep_first_column_comment = true +ij_java_keep_indents_on_empty_lines = false +ij_java_keep_line_breaks = true +ij_java_keep_multiple_expressions_in_one_line = false +ij_java_keep_simple_blocks_in_one_line = false +ij_java_keep_simple_classes_in_one_line = false +ij_java_keep_simple_lambdas_in_one_line = false +ij_java_keep_simple_methods_in_one_line = false +ij_java_label_indent_absolute = false +ij_java_label_indent_size = 0 +ij_java_lambda_brace_style = end_of_line +ij_java_layout_static_imports_separately = true +ij_java_line_comment_add_space = true +ij_java_line_comment_at_first_column = false +ij_java_method_annotation_wrap = split_into_lines +ij_java_method_brace_style = end_of_line +ij_java_method_call_chain_wrap = normal +ij_java_method_parameters_new_line_after_left_paren = false +ij_java_method_parameters_right_paren_on_new_line = false +ij_java_method_parameters_wrap = normal +ij_java_modifier_list_wrap = false +ij_java_names_count_to_use_import_on_demand = 999 +ij_java_new_line_after_lparen_in_record_header = false +ij_java_parameter_annotation_wrap = normal +ij_java_parentheses_expression_new_line_after_left_paren = false +ij_java_parentheses_expression_right_paren_on_new_line = false +ij_java_place_assignment_sign_on_next_line = false +ij_java_prefer_longer_names = true +ij_java_prefer_parameters_wrap = false +ij_java_record_components_wrap = normal +ij_java_repeat_synchronized = true +ij_java_replace_instanceof_and_cast = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true +ij_java_resource_list_new_line_after_left_paren = false +ij_java_resource_list_right_paren_on_new_line = false +ij_java_resource_list_wrap = normal +ij_java_rparen_on_new_line_in_record_header = false +ij_java_space_after_closing_angle_bracket_in_type_argument = false +ij_java_space_after_colon = true +ij_java_space_after_comma = true +ij_java_space_after_comma_in_type_arguments = true +ij_java_space_after_for_semicolon = true +ij_java_space_after_quest = true +ij_java_space_after_type_cast = true +ij_java_space_before_annotation_array_initializer_left_brace = false +ij_java_space_before_annotation_parameter_list = false +ij_java_space_before_array_initializer_left_brace = true +ij_java_space_before_catch_keyword = true +ij_java_space_before_catch_left_brace = true +ij_java_space_before_catch_parentheses = true +ij_java_space_before_class_left_brace = true +ij_java_space_before_colon = true +ij_java_space_before_colon_in_foreach = true +ij_java_space_before_comma = false +ij_java_space_before_do_left_brace = true +ij_java_space_before_else_keyword = true +ij_java_space_before_else_left_brace = true +ij_java_space_before_finally_keyword = true +ij_java_space_before_finally_left_brace = true +ij_java_space_before_for_left_brace = true +ij_java_space_before_for_parentheses = true +ij_java_space_before_for_semicolon = false +ij_java_space_before_if_left_brace = true +ij_java_space_before_if_parentheses = true +ij_java_space_before_method_call_parentheses = false +ij_java_space_before_method_left_brace = true +ij_java_space_before_method_parentheses = false +ij_java_space_before_opening_angle_bracket_in_type_parameter = false +ij_java_space_before_quest = true +ij_java_space_before_switch_left_brace = true +ij_java_space_before_switch_parentheses = true +ij_java_space_before_synchronized_left_brace = true +ij_java_space_before_synchronized_parentheses = true +ij_java_space_before_try_left_brace = true +ij_java_space_before_try_parentheses = true +ij_java_space_before_type_parameter_list = false +ij_java_space_before_while_keyword = true +ij_java_space_before_while_left_brace = true +ij_java_space_before_while_parentheses = true +ij_java_space_inside_one_line_enum_braces = false +ij_java_space_within_empty_array_initializer_braces = false +ij_java_space_within_empty_method_call_parentheses = false +ij_java_space_within_empty_method_parentheses = false +ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_assignment_operators = true +ij_java_spaces_around_bitwise_operators = true +ij_java_spaces_around_equality_operators = true +ij_java_spaces_around_lambda_arrow = true +ij_java_spaces_around_logical_operators = true +ij_java_spaces_around_method_ref_dbl_colon = false +ij_java_spaces_around_multiplicative_operators = true +ij_java_spaces_around_relational_operators = true +ij_java_spaces_around_shift_operators = true +ij_java_spaces_around_type_bounds_in_type_parameters = true +ij_java_spaces_around_unary_operator = false +ij_java_spaces_within_angle_brackets = false +ij_java_spaces_within_annotation_parentheses = false +ij_java_spaces_within_array_initializer_braces = false +ij_java_spaces_within_braces = false +ij_java_spaces_within_brackets = false +ij_java_spaces_within_cast_parentheses = false +ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_for_parentheses = false +ij_java_spaces_within_if_parentheses = false +ij_java_spaces_within_method_call_parentheses = false +ij_java_spaces_within_method_parentheses = false +ij_java_spaces_within_parentheses = false +ij_java_spaces_within_switch_parentheses = false +ij_java_spaces_within_synchronized_parentheses = false +ij_java_spaces_within_try_parentheses = false +ij_java_spaces_within_while_parentheses = false +ij_java_special_else_if_treatment = true +ij_java_subclass_name_suffix = Impl +ij_java_ternary_operation_signs_on_next_line = true +ij_java_ternary_operation_wrap = normal +ij_java_test_name_suffix = Test +ij_java_throws_keyword_wrap = normal +ij_java_throws_list_wrap = normal +ij_java_use_external_annotations = false +ij_java_use_fq_class_names = false +ij_java_use_relative_indents = false +ij_java_use_single_class_imports = true +ij_java_variable_annotation_wrap = normal +ij_java_visibility = public +ij_java_while_brace_force = always +ij_java_while_on_new_line = false +ij_java_wrap_comments = false +ij_java_wrap_first_method_in_call_chain = false +ij_java_wrap_long_lines = true + +[*.properties] +ij_properties_align_group_field_declarations = false +ij_properties_keep_blank_lines = false +ij_properties_key_value_delimiter = equals +ij_properties_spaces_around_key_value_delimiter = false + +[.editorconfig] +ij_editorconfig_align_group_field_declarations = false +ij_editorconfig_space_after_colon = false +ij_editorconfig_space_after_comma = true +ij_editorconfig_space_before_colon = false +ij_editorconfig_space_before_comma = false +ij_editorconfig_spaces_around_assignment_operators = true + +[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.jspx, *.pom, *.rng, *.tagx, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}] +ij_xml_align_attributes = true +ij_xml_align_text = false +ij_xml_attribute_wrap = normal +ij_xml_block_comment_at_first_column = true +ij_xml_keep_blank_lines = 2 +ij_xml_keep_indents_on_empty_lines = false +ij_xml_keep_line_breaks = true +ij_xml_keep_line_breaks_in_text = true +ij_xml_keep_whitespaces = false +ij_xml_keep_whitespaces_around_cdata = preserve +ij_xml_keep_whitespaces_inside_cdata = false +ij_xml_line_comment_at_first_column = true +ij_xml_space_after_tag_name = false +ij_xml_space_around_equals_in_attribute = false +ij_xml_space_inside_empty_tag = false +ij_xml_text_wrap = normal + +[{*.bash, *.sh, *.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = false + +[{*.gant, *.gradle, *.groovy, *.gy}] +ij_groovy_align_group_field_declarations = false +ij_groovy_align_multiline_array_initializer_expression = false +ij_groovy_align_multiline_assignment = false +ij_groovy_align_multiline_binary_operation = false +ij_groovy_align_multiline_chained_methods = false +ij_groovy_align_multiline_extends_list = false +ij_groovy_align_multiline_for = true +ij_groovy_align_multiline_list_or_map = true +ij_groovy_align_multiline_method_parentheses = false +ij_groovy_align_multiline_parameters = true +ij_groovy_align_multiline_parameters_in_calls = false +ij_groovy_align_multiline_resources = true +ij_groovy_align_multiline_ternary_operation = false +ij_groovy_align_multiline_throws_list = false +ij_groovy_align_named_args_in_map = true +ij_groovy_align_throws_keyword = false +ij_groovy_array_initializer_new_line_after_left_brace = false +ij_groovy_array_initializer_right_brace_on_new_line = false +ij_groovy_array_initializer_wrap = off +ij_groovy_assert_statement_wrap = off +ij_groovy_assignment_wrap = off +ij_groovy_binary_operation_wrap = off +ij_groovy_blank_lines_after_class_header = 0 +ij_groovy_blank_lines_after_imports = 1 +ij_groovy_blank_lines_after_package = 1 +ij_groovy_blank_lines_around_class = 1 +ij_groovy_blank_lines_around_field = 0 +ij_groovy_blank_lines_around_field_in_interface = 0 +ij_groovy_blank_lines_around_method = 1 +ij_groovy_blank_lines_around_method_in_interface = 1 +ij_groovy_blank_lines_before_imports = 1 +ij_groovy_blank_lines_before_method_body = 0 +ij_groovy_blank_lines_before_package = 0 +ij_groovy_block_brace_style = end_of_line +ij_groovy_block_comment_at_first_column = true +ij_groovy_call_parameters_new_line_after_left_paren = false +ij_groovy_call_parameters_right_paren_on_new_line = false +ij_groovy_call_parameters_wrap = off +ij_groovy_catch_on_new_line = false +ij_groovy_class_annotation_wrap = split_into_lines +ij_groovy_class_brace_style = end_of_line +ij_groovy_class_count_to_use_import_on_demand = 5 +ij_groovy_do_while_brace_force = never +ij_groovy_else_on_new_line = false +ij_groovy_enum_constants_wrap = off +ij_groovy_extends_keyword_wrap = off +ij_groovy_extends_list_wrap = off +ij_groovy_field_annotation_wrap = split_into_lines +ij_groovy_finally_on_new_line = false +ij_groovy_for_brace_force = never +ij_groovy_for_statement_new_line_after_left_paren = false +ij_groovy_for_statement_right_paren_on_new_line = false +ij_groovy_for_statement_wrap = off +ij_groovy_if_brace_force = never +ij_groovy_import_annotation_wrap = 2 +ij_groovy_indent_case_from_switch = true +ij_groovy_indent_label_blocks = true +ij_groovy_insert_inner_class_imports = false +ij_groovy_keep_blank_lines_before_right_brace = 2 +ij_groovy_keep_blank_lines_in_code = 2 +ij_groovy_keep_blank_lines_in_declarations = 2 +ij_groovy_keep_control_statement_in_one_line = true +ij_groovy_keep_first_column_comment = true +ij_groovy_keep_indents_on_empty_lines = false +ij_groovy_keep_line_breaks = true +ij_groovy_keep_multiple_expressions_in_one_line = false +ij_groovy_keep_simple_blocks_in_one_line = false +ij_groovy_keep_simple_classes_in_one_line = true +ij_groovy_keep_simple_lambdas_in_one_line = true +ij_groovy_keep_simple_methods_in_one_line = true +ij_groovy_label_indent_absolute = false +ij_groovy_label_indent_size = 0 +ij_groovy_lambda_brace_style = end_of_line +ij_groovy_layout_static_imports_separately = true +ij_groovy_line_comment_add_space = false +ij_groovy_line_comment_at_first_column = true +ij_groovy_method_annotation_wrap = split_into_lines +ij_groovy_method_brace_style = end_of_line +ij_groovy_method_call_chain_wrap = off +ij_groovy_method_parameters_new_line_after_left_paren = false +ij_groovy_method_parameters_right_paren_on_new_line = false +ij_groovy_method_parameters_wrap = off +ij_groovy_modifier_list_wrap = false +ij_groovy_names_count_to_use_import_on_demand = 3 +ij_groovy_parameter_annotation_wrap = off +ij_groovy_parentheses_expression_new_line_after_left_paren = false +ij_groovy_parentheses_expression_right_paren_on_new_line = false +ij_groovy_prefer_parameters_wrap = false +ij_groovy_resource_list_new_line_after_left_paren = false +ij_groovy_resource_list_right_paren_on_new_line = false +ij_groovy_resource_list_wrap = off +ij_groovy_space_after_assert_separator = true +ij_groovy_space_after_colon = true +ij_groovy_space_after_comma = true +ij_groovy_space_after_comma_in_type_arguments = true +ij_groovy_space_after_for_semicolon = true +ij_groovy_space_after_quest = true +ij_groovy_space_after_type_cast = true +ij_groovy_space_before_annotation_parameter_list = false +ij_groovy_space_before_array_initializer_left_brace = false +ij_groovy_space_before_assert_separator = false +ij_groovy_space_before_catch_keyword = true +ij_groovy_space_before_catch_left_brace = true +ij_groovy_space_before_catch_parentheses = true +ij_groovy_space_before_class_left_brace = true +ij_groovy_space_before_closure_left_brace = true +ij_groovy_space_before_colon = true +ij_groovy_space_before_comma = false +ij_groovy_space_before_do_left_brace = true +ij_groovy_space_before_else_keyword = true +ij_groovy_space_before_else_left_brace = true +ij_groovy_space_before_finally_keyword = true +ij_groovy_space_before_finally_left_brace = true +ij_groovy_space_before_for_left_brace = true +ij_groovy_space_before_for_parentheses = true +ij_groovy_space_before_for_semicolon = false +ij_groovy_space_before_if_left_brace = true +ij_groovy_space_before_if_parentheses = true +ij_groovy_space_before_method_call_parentheses = false +ij_groovy_space_before_method_left_brace = true +ij_groovy_space_before_method_parentheses = false +ij_groovy_space_before_quest = true +ij_groovy_space_before_switch_left_brace = true +ij_groovy_space_before_switch_parentheses = true +ij_groovy_space_before_synchronized_left_brace = true +ij_groovy_space_before_synchronized_parentheses = true +ij_groovy_space_before_try_left_brace = true +ij_groovy_space_before_try_parentheses = true +ij_groovy_space_before_while_keyword = true +ij_groovy_space_before_while_left_brace = true +ij_groovy_space_before_while_parentheses = true +ij_groovy_space_in_named_argument = true +ij_groovy_space_in_named_argument_before_colon = false +ij_groovy_space_within_empty_array_initializer_braces = false +ij_groovy_space_within_empty_method_call_parentheses = false +ij_groovy_spaces_around_additive_operators = true +ij_groovy_spaces_around_assignment_operators = true +ij_groovy_spaces_around_bitwise_operators = true +ij_groovy_spaces_around_equality_operators = true +ij_groovy_spaces_around_lambda_arrow = true +ij_groovy_spaces_around_logical_operators = true +ij_groovy_spaces_around_multiplicative_operators = true +ij_groovy_spaces_around_regex_operators = true +ij_groovy_spaces_around_relational_operators = true +ij_groovy_spaces_around_shift_operators = true +ij_groovy_spaces_within_annotation_parentheses = false +ij_groovy_spaces_within_array_initializer_braces = false +ij_groovy_spaces_within_braces = true +ij_groovy_spaces_within_brackets = false +ij_groovy_spaces_within_cast_parentheses = false +ij_groovy_spaces_within_catch_parentheses = false +ij_groovy_spaces_within_for_parentheses = false +ij_groovy_spaces_within_gstring_injection_braces = false +ij_groovy_spaces_within_if_parentheses = false +ij_groovy_spaces_within_list_or_map = false +ij_groovy_spaces_within_method_call_parentheses = false +ij_groovy_spaces_within_method_parentheses = false +ij_groovy_spaces_within_parentheses = false +ij_groovy_spaces_within_switch_parentheses = false +ij_groovy_spaces_within_synchronized_parentheses = false +ij_groovy_spaces_within_try_parentheses = false +ij_groovy_spaces_within_tuple_expression = false +ij_groovy_spaces_within_while_parentheses = false +ij_groovy_special_else_if_treatment = true +ij_groovy_ternary_operation_wrap = off +ij_groovy_throws_keyword_wrap = off +ij_groovy_throws_list_wrap = off +ij_groovy_use_flying_geese_braces = false +ij_groovy_use_fq_class_names = false +ij_groovy_use_fq_class_names_in_javadoc = true +ij_groovy_use_relative_indents = false +ij_groovy_use_single_class_imports = true +ij_groovy_variable_annotation_wrap = off +ij_groovy_while_brace_force = never +ij_groovy_while_on_new_line = false +ij_groovy_wrap_long_lines = false + +[{*.har, *.json}] +indent_size = 2 +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = true +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + +[{*.htm, *.html, *.sht, *.shtm, *.shtml}] +ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3 +ij_html_align_attributes = true +ij_html_align_text = false +ij_html_attribute_wrap = normal +ij_html_block_comment_at_first_column = true +ij_html_do_not_align_children_of_min_lines = 0 +ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p +ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot +ij_html_enforce_quotes = false +ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var +ij_html_keep_blank_lines = 2 +ij_html_keep_indents_on_empty_lines = false +ij_html_keep_line_breaks = true +ij_html_keep_line_breaks_in_text = true +ij_html_keep_whitespaces = false +ij_html_keep_whitespaces_inside = span, pre, textarea +ij_html_line_comment_at_first_column = true +ij_html_new_line_after_last_attribute = never +ij_html_new_line_before_first_attribute = never +ij_html_quote_style = double +ij_html_remove_new_line_before_tags = br +ij_html_space_after_tag_name = false +ij_html_space_around_equality_in_attribute = false +ij_html_space_inside_empty_tag = false +ij_html_text_wrap = normal + +[{*.yaml, *.yml}] +indent_size = 2 +ij_yaml_keep_indents_on_empty_lines = false +ij_yaml_keep_line_breaks = true + +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +end_of_line = lf +max_line_length = 100 diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..8605c15 --- /dev/null +++ b/.gitignore @@ -0,0 +1,81 @@ +### Maven +target/ +logs/ +!.mvn/wrapper/maven-wrapper.jar + +### Gradle +.gradle +/build/ +/out/ +!gradle/wrapper/gradle-wrapper.jar +bin/ + +### Node +node_modules/ + +### STS +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA +.idea +*.iws +*.iml +*.ipr +log/ + +### NetBeans +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +### Mac +.DS_Store +*/.DS_Store + +### VSCode +*.project +*.factorypath +.vscode +!.vscode/extensions.json + +### Compiled class file +*.class + +### Log file +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +### BlueJ files +*.ctxt + +### Package Files +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +### Local file +application-local.yml +application-local.yaml +application-local.properties + +/console/build/ +/workplace/ +/src/main/resources/console/ +/src/main/resources/templates/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..20d40b6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..a707d8b --- /dev/null +++ b/OWNERS @@ -0,0 +1,11 @@ +reviewers: +- ruibaby +- guqing +- JohnNiang +- wan92hen +- LIlGG + +approvers: +- ruibaby +- guqing +- JohnNiang diff --git a/README.md b/README.md new file mode 100644 index 0000000..97869d3 --- /dev/null +++ b/README.md @@ -0,0 +1,336 @@ +# plugin-moments + +Halo 2.0 的瞬间管理插件,提供一个轻量级的内容发布功能,支持发布图文、视频、音频等内容。 + +![Preview](./images/plugin-moments-preview.png) + +## 使用方式 + +1. 下载,目前提供以下两个下载方式: + - Halo 应用市场: + - GitHub Releases:访问 [Releases](https://github.com/halo-sigs/plugin-moments/releases) 下载 Assets 中的 JAR 文件。 +2. 安装,插件安装和更新方式可参考: +3. 安装完成之后,访问 Console 左侧的**瞬间**菜单项,即可进行管理。 +4. 前台访问地址为 `/moments`,需要注意的是,此插件需要主题提供模板(moments.html)才能访问 `/moments`。 +5. 此插件也提供了 RSS 订阅的路由,可以访问 `/moments/rss.xml`。 +6. 此插件将数据同步至 Halo 搜索,type 为 `moment.moment.halo.run`。 + +## 开发环境 + +插件开发的详细文档请查阅: + +所需环境: + +1. Java 17 +2. Node 18 +3. pnpm 8 +4. Docker (可选) + +克隆项目: + +```bash +git clone git@github.com:halo-sigs/plugin-moments.git + +# 或者当你 fork 之后 + +git clone git@github.com:{your_github_id}/plugin-moments.git +``` + +```bash +cd path/to/plugin-moments +``` + +### 运行方式 1(推荐) + +> 此方式需要本地安装 Docker + +```bash +# macOS / Linux +./gradlew pnpmInstall + +# Windows +./gradlew.bat pnpmInstall +``` + +```bash +# macOS / Linux +./gradlew haloServer + +# Windows +./gradlew.bat haloServer +``` + +执行此命令后,会自动创建一个 Halo 的 Docker 容器并加载当前的插件,更多文档可查阅: + +### 运行方式 2 + +> 此方式需要使用源码运行 Halo + +编译插件: + +```bash +# macOS / Linux +./gradlew build + +# Windows +./gradlew.bat build +``` + +修改 Halo 配置文件: + +```yaml +halo: + plugin: + runtime-mode: development + fixedPluginPath: + - "/path/to/plugin-moments" +``` + +最后重启 Halo 项目即可。 + +## 主题适配 + +目前此插件为主题端提供了 `/moments` 路由,模板为 `moments.html`,也提供了 [Finder API](https://docs.halo.run/developer-guide/theme/finder-apis),可以将瞬间列表渲染到任何地方。 + +### 模板变量 + +#### 列表页面 /moments + +- 模板路径:/templates/moments.html +- 访问路径:/moments?tag={tag} | moments/page/{page}?tag={tag} + +**参数**: + +- tag:标签名称,用于筛选。 + +**变量**: + +- moments:[#UrlContextListResult\](#urlcontextlistresult-momentvo) +- tags:[#List\](#momenttagvo) + +**示例**: + +```html + + + +
+ +
    +
  • +
    + + + + + +
  • +
+ +
+``` + +#### 详情页面 /moments/{name} + +- 模板路径:/templates/moment.html +- 访问路径:/moments/{name} + +**变量**: + +- moment:[#MomentVo](#momentvo) + +**示例**: + +```html +
+
+
+ + + + + +
+
+``` + +#### 搜索路由 + +**变量**: + +- type: moment.moment.halo.run + +### Finder API + +#### listAll() + +获取全部瞬间内容。 + +**返回值类型**:List<[#MomentVo](#momentvo)> + +**示例**: + +```html +
    +
  • +
    + + + + + +
  • +
+``` + +#### list(page, size) + +根据分页参数获取瞬间列表。 + +**参数**: + +1. `page: int` - 分页页码,从 1 开始 +2. `size: int` - 分页条数 + +**返回值类型**:[ListResult\](#listresult-momentvo) + +**示例**: + +```html + +
    +
  • +
    + + + + + +
  • +
+
+ +
+
+``` + +### 类型定义 + +#### MomentVo + +```json +{ + "metadata": { + "name": "string", // 唯一标识 + "labels": { + "additionalProp1": "string" + }, + "annotations": { + "additionalProp1": "string" + }, + "creationTimestamp": "2022-11-20T13:06:38.512Z" // 创建时间 + }, + "spec": { + "content": { + "raw": "string", // 原始内容,一般用于编辑器使用 + "html": "string", // HTML 内容,用于主题端进行最终渲染的内容 + "medium": [ + // 媒体内容 + { + "type": "#MomentMediaType", // 类型 + "url": "string", // 链接 + "originType": "string" // 原始类型,例如:image/jpeg + } + ] + }, + "releaseTime": "string", // 发布时间 + "visible": "PUBLIC", // 可见性 + "owner": "string", // 所属用户 + "tags": ["string"] // 所拥有的标签 + }, + "owner": { + "name": "string", // 用户名 + "avatar": "string", // 头像 + "bio": "string", // 描述 + "displayName": "string" // 显示名称 + }, + "stats": { + "upvote": 0, // 点赞数 + "totalComment": 0, // 评论数 + "approvedComment": 0 // 审核通过的评论数 + } +} +``` + +#### MomentMediaType + +```java +enum Target { + PHOTO, // 图片 + VIDEO, // 视频 + POST, // 文章 + AUDIO; // 音频 +} +``` + +#### ListResult + +```json +{ + "page": 0, // 当前页码 + "size": 0, // 每页条数 + "total": 0, // 总条数 + "items": "List<#MomentVo>", // 瞬间列表数据 + "first": true, // 是否为第一页 + "last": true, // 是否为最后一页 + "hasNext": true, // 是否有下一页 + "hasPrevious": true, // 是否有上一页 + "totalPages": 0 // 总页数 +} +``` + +#### UrlContextListResult + +```json +{ + "page": 0, // 当前页码 + "size": 0, // 每页条数 + "total": 0, // 总条数 + "items": "List<#MomentVo>", // 瞬间列表数据 + "first": true, // 是否为第一页 + "last": true, // 是否为最后一页 + "hasNext": true, // 是否有下一页 + "hasPrevious": true, // 是否有上一页 + "totalPages": 0, // 总页数 + "prevUrl": "string", // 上一页链接 + "nextUrl": "string" // 下一页链接 +} +``` + +#### MomentTagVo + +```json +{ + "name": "string", // 标签名称 + "permalink": "string", // 标签链接 + "momentCount": 0 // 标签所属的 moment 数量 +} +``` diff --git a/api-docs/openapi/v3_0/momentsApi.json b/api-docs/openapi/v3_0/momentsApi.json new file mode 100644 index 0000000..953ef6e --- /dev/null +++ b/api-docs/openapi/v3_0/momentsApi.json @@ -0,0 +1,1155 @@ +{ + "openapi" : "3.0.1", + "info" : { + "title" : "Halo", + "version" : "2.17.0" + }, + "servers" : [ { + "url" : "http://localhost:65084", + "description" : "Generated server url" + } ], + "security" : [ { + "basicAuth" : [ ], + "bearerAuth" : [ ] + } ], + "paths" : { + "/apis/console.api.moment.halo.run/v1alpha1/moments" : { + "get" : { + "description" : "List moments.", + "operationId" : "ListMoments", + "parameters" : [ { + "description" : "Page number. Default is 0.", + "in" : "query", + "name" : "page", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "description" : "Size number. Default is 0.", + "in" : "query", + "name" : "size", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "description" : "Label selector. e.g.: hidden!=true", + "in" : "query", + "name" : "labelSelector", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Field selector. e.g.: metadata.name==halo", + "in" : "query", + "name" : "fieldSelector", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.", + "in" : "query", + "name" : "sort", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Moments filtered by keyword.", + "in" : "query", + "name" : "keyword", + "schema" : { + "type" : "string" + } + }, { + "description" : "Owner name.", + "in" : "query", + "name" : "ownerName", + "schema" : { + "type" : "string" + } + }, { + "description" : "Moment tag.", + "in" : "query", + "name" : "tag", + "schema" : { + "type" : "string" + } + }, { + "description" : "Moment visible.", + "in" : "query", + "name" : "visible", + "schema" : { + "type" : "string", + "enum" : [ "PUBLIC", "PRIVATE" ] + } + }, { + "description" : "Moment start date.", + "in" : "query", + "name" : "startDate", + "schema" : { + "type" : "string", + "format" : "date-time" + } + }, { + "description" : "Moment end date.", + "in" : "query", + "name" : "endDate", + "schema" : { + "type" : "string", + "format" : "date-time" + } + }, { + "description" : "Moment approved.", + "in" : "query", + "name" : "approved", + "schema" : { + "type" : "boolean" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/ListedMomentList" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "console.api.moment.halo.run/v1alpha1/Moment" ] + }, + "post" : { + "description" : "Create a Moment.", + "operationId" : "CreateMoment", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "required" : true + }, + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "console.api.moment.halo.run/v1alpha1/Moment" ] + } + }, + "/apis/console.api.moment.halo.run/v1alpha1/moments/{name}" : { + "get" : { + "description" : "Get a moment by name.", + "operationId" : "GetMoment", + "parameters" : [ { + "description" : "Moment name", + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/ListedMoment" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "console.api.moment.halo.run/v1alpha1/Moment" ] + } + }, + "/apis/console.api.moment.halo.run/v1alpha1/tags" : { + "get" : { + "description" : "List all moment tags.", + "operationId" : "ListTags", + "parameters" : [ { + "description" : "Tag name to query", + "in" : "query", + "name" : "name", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "console.api.moment.halo.run/v1alpha1/Moment" ] + } + }, + "/apis/moment.halo.run/v1alpha1/moments" : { + "get" : { + "description" : "List Moment", + "operationId" : "listMoment", + "parameters" : [ { + "description" : "Page number. Default is 0.", + "in" : "query", + "name" : "page", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "description" : "Size number. Default is 0.", + "in" : "query", + "name" : "size", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "description" : "Label selector. e.g.: hidden!=true", + "in" : "query", + "name" : "labelSelector", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Field selector. e.g.: metadata.name==halo", + "in" : "query", + "name" : "fieldSelector", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.", + "in" : "query", + "name" : "sort", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } ], + "responses" : { + "200" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/MomentList" + } + } + }, + "description" : "Response moments" + } + }, + "tags" : [ "MomentV1alpha1" ] + }, + "post" : { + "description" : "Create Moment", + "operationId" : "createMoment", + "requestBody" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "Fresh moment" + }, + "responses" : { + "200" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "Response moments created just now" + } + }, + "tags" : [ "MomentV1alpha1" ] + } + }, + "/apis/moment.halo.run/v1alpha1/moments/{name}" : { + "delete" : { + "description" : "Delete Moment", + "operationId" : "deleteMoment", + "parameters" : [ { + "description" : "Name of moment", + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "description" : "Response moment deleted just now" + } + }, + "tags" : [ "MomentV1alpha1" ] + }, + "get" : { + "description" : "Get Moment", + "operationId" : "getMoment", + "parameters" : [ { + "description" : "Name of moment", + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "200" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "Response single moment" + } + }, + "tags" : [ "MomentV1alpha1" ] + }, + "patch" : { + "description" : "Patch Moment", + "operationId" : "patchMoment", + "parameters" : [ { + "description" : "Name of moment", + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json-patch+json" : { + "schema" : { + "$ref" : "#/components/schemas/JsonPatch" + } + } + } + }, + "responses" : { + "200" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "Response moment patched just now" + } + }, + "tags" : [ "MomentV1alpha1" ] + }, + "put" : { + "description" : "Update Moment", + "operationId" : "updateMoment", + "parameters" : [ { + "description" : "Name of moment", + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "Updated moment" + }, + "responses" : { + "200" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "Response moments updated just now" + } + }, + "tags" : [ "MomentV1alpha1" ] + } + }, + "/apis/uc.api.moment.halo.run/v1alpha1/moments" : { + "get" : { + "description" : "List My moments.", + "operationId" : "ListMyMoments", + "parameters" : [ { + "description" : "Page number. Default is 0.", + "in" : "query", + "name" : "page", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "description" : "Size number. Default is 0.", + "in" : "query", + "name" : "size", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "description" : "Label selector. e.g.: hidden!=true", + "in" : "query", + "name" : "labelSelector", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Field selector. e.g.: metadata.name==halo", + "in" : "query", + "name" : "fieldSelector", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.", + "in" : "query", + "name" : "sort", + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + }, { + "description" : "Moments filtered by keyword.", + "in" : "query", + "name" : "keyword", + "schema" : { + "type" : "string" + } + }, { + "description" : "Owner name.", + "in" : "query", + "name" : "ownerName", + "schema" : { + "type" : "string" + } + }, { + "description" : "Moment tag.", + "in" : "query", + "name" : "tag", + "schema" : { + "type" : "string" + } + }, { + "description" : "Moment visible.", + "in" : "query", + "name" : "visible", + "schema" : { + "type" : "string", + "enum" : [ "PUBLIC", "PRIVATE" ] + } + }, { + "description" : "Moment start date.", + "in" : "query", + "name" : "startDate", + "schema" : { + "type" : "string", + "format" : "date-time" + } + }, { + "description" : "Moment end date.", + "in" : "query", + "name" : "endDate", + "schema" : { + "type" : "string", + "format" : "date-time" + } + }, { + "description" : "Moment approved.", + "in" : "query", + "name" : "approved", + "schema" : { + "type" : "boolean" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/ListedMomentList" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "uc.api.moment.halo.run/v1alpha1/moment" ] + }, + "post" : { + "description" : "Create a My Moment.", + "operationId" : "CreateMyMoment", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "required" : true + }, + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "uc.api.moment.halo.run/v1alpha1/moment" ] + } + }, + "/apis/uc.api.moment.halo.run/v1alpha1/moments/{name}" : { + "delete" : { + "description" : "Delete a My Moment.", + "operationId" : "DeleteMyMoment", + "parameters" : [ { + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "uc.api.moment.halo.run/v1alpha1/moment" ] + }, + "get" : { + "description" : "Get a My Moment.", + "operationId" : "GetMyMoment", + "parameters" : [ { + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "uc.api.moment.halo.run/v1alpha1/moment" ] + }, + "put" : { + "description" : "Update a My Moment.", + "operationId" : "UpdateMyMoment", + "parameters" : [ { + "in" : "path", + "name" : "name", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "required" : true + }, + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "$ref" : "#/components/schemas/Moment" + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "uc.api.moment.halo.run/v1alpha1/moment" ] + } + }, + "/apis/uc.api.moment.halo.run/v1alpha1/tags" : { + "get" : { + "description" : "List all moment tags.", + "operationId" : "ListTags_1", + "parameters" : [ { + "description" : "Tag name to query", + "in" : "query", + "name" : "name", + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "content" : { + "*/*" : { + "schema" : { + "type" : "array", + "items" : { + "type" : "string" + } + } + } + }, + "description" : "default response" + } + }, + "tags" : [ "uc.api.moment.halo.run/v1alpha1/moment" ] + } + } + }, + "components" : { + "schemas" : { + "AddOperation" : { + "required" : [ "op", "path", "value" ], + "type" : "object", + "properties" : { + "op" : { + "type" : "string", + "enum" : [ "add" ] + }, + "path" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + }, + "value" : { + "description" : "Value can be any JSON value" + } + } + }, + "Contributor" : { + "type" : "object", + "properties" : { + "avatar" : { + "type" : "string" + }, + "displayName" : { + "type" : "string" + }, + "name" : { + "type" : "string" + } + } + }, + "CopyOperation" : { + "required" : [ "op", "from", "path" ], + "type" : "object", + "properties" : { + "from" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + }, + "op" : { + "type" : "string", + "enum" : [ "copy" ] + }, + "path" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + } + } + }, + "JsonPatch" : { + "minItems" : 1, + "uniqueItems" : true, + "type" : "array", + "description" : "JSON schema for JSONPatch operations", + "items" : { + "oneOf" : [ { + "$ref" : "#/components/schemas/AddOperation" + }, { + "$ref" : "#/components/schemas/ReplaceOperation" + }, { + "$ref" : "#/components/schemas/TestOperation" + }, { + "$ref" : "#/components/schemas/RemoveOperation" + }, { + "$ref" : "#/components/schemas/MoveOperation" + }, { + "$ref" : "#/components/schemas/CopyOperation" + } ] + } + }, + "ListedMoment" : { + "required" : [ "moment", "owner", "stats" ], + "type" : "object", + "properties" : { + "moment" : { + "$ref" : "#/components/schemas/Moment" + }, + "owner" : { + "$ref" : "#/components/schemas/Contributor" + }, + "stats" : { + "$ref" : "#/components/schemas/Stats" + } + }, + "description" : "A chunk of items." + }, + "ListedMomentList" : { + "required" : [ "first", "hasNext", "hasPrevious", "items", "last", "page", "size", "total", "totalPages" ], + "type" : "object", + "properties" : { + "first" : { + "type" : "boolean", + "description" : "Indicates whether current page is the first page." + }, + "hasNext" : { + "type" : "boolean", + "description" : "Indicates whether current page has previous page." + }, + "hasPrevious" : { + "type" : "boolean", + "description" : "Indicates whether current page has previous page." + }, + "items" : { + "type" : "array", + "description" : "A chunk of items.", + "items" : { + "$ref" : "#/components/schemas/ListedMoment" + } + }, + "last" : { + "type" : "boolean", + "description" : "Indicates whether current page is the last page." + }, + "page" : { + "type" : "integer", + "description" : "Page number, starts from 1. If not set or equal to 0, it means no pagination.", + "format" : "int32" + }, + "size" : { + "type" : "integer", + "description" : "Size of each page. If not set or equal to 0, it means no pagination.", + "format" : "int32" + }, + "total" : { + "type" : "integer", + "description" : "Total elements.", + "format" : "int64" + }, + "totalPages" : { + "type" : "integer", + "description" : "Indicates total pages.", + "format" : "int64" + } + } + }, + "Metadata" : { + "required" : [ "name" ], + "type" : "object", + "properties" : { + "annotations" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "creationTimestamp" : { + "type" : "string", + "format" : "date-time", + "nullable" : true + }, + "deletionTimestamp" : { + "type" : "string", + "format" : "date-time", + "nullable" : true + }, + "finalizers" : { + "uniqueItems" : true, + "type" : "array", + "nullable" : true, + "items" : { + "type" : "string", + "nullable" : true + } + }, + "generateName" : { + "type" : "string", + "description" : "The name field will be generated automatically according to the given generateName field" + }, + "labels" : { + "type" : "object", + "additionalProperties" : { + "type" : "string" + } + }, + "name" : { + "type" : "string", + "description" : "Metadata name" + }, + "version" : { + "type" : "integer", + "format" : "int64", + "nullable" : true + } + } + }, + "Moment" : { + "required" : [ "apiVersion", "kind", "metadata", "spec" ], + "type" : "object", + "properties" : { + "apiVersion" : { + "type" : "string" + }, + "kind" : { + "type" : "string" + }, + "metadata" : { + "$ref" : "#/components/schemas/Metadata" + }, + "spec" : { + "$ref" : "#/components/schemas/MomentSpec" + }, + "status" : { + "$ref" : "#/components/schemas/MomentStatus" + } + } + }, + "MomentContent" : { + "type" : "object", + "properties" : { + "html" : { + "type" : "string", + "description" : "Rendered result with HTML format" + }, + "medium" : { + "uniqueItems" : true, + "type" : "array", + "description" : "Medium of moment", + "items" : { + "$ref" : "#/components/schemas/MomentMedia" + } + }, + "raw" : { + "type" : "string", + "description" : "Raw of content" + } + } + }, + "MomentList" : { + "required" : [ "first", "hasNext", "hasPrevious", "items", "last", "page", "size", "total", "totalPages" ], + "type" : "object", + "properties" : { + "first" : { + "type" : "boolean", + "description" : "Indicates whether current page is the first page." + }, + "hasNext" : { + "type" : "boolean", + "description" : "Indicates whether current page has previous page." + }, + "hasPrevious" : { + "type" : "boolean", + "description" : "Indicates whether current page has previous page." + }, + "items" : { + "type" : "array", + "description" : "A chunk of items.", + "items" : { + "$ref" : "#/components/schemas/Moment" + } + }, + "last" : { + "type" : "boolean", + "description" : "Indicates whether current page is the last page." + }, + "page" : { + "type" : "integer", + "description" : "Page number, starts from 1. If not set or equal to 0, it means no pagination.", + "format" : "int32" + }, + "size" : { + "type" : "integer", + "description" : "Size of each page. If not set or equal to 0, it means no pagination.", + "format" : "int32" + }, + "total" : { + "type" : "integer", + "description" : "Total elements.", + "format" : "int64" + }, + "totalPages" : { + "type" : "integer", + "description" : "Indicates total pages.", + "format" : "int64" + } + } + }, + "MomentMedia" : { + "type" : "object", + "properties" : { + "originType" : { + "type" : "string", + "description" : "Origin type of media." + }, + "type" : { + "type" : "string", + "description" : "Type of media", + "enum" : [ "PHOTO", "VIDEO", "POST", "AUDIO" ] + }, + "url" : { + "type" : "string", + "description" : "External URL of media" + } + }, + "description" : "Media item of moment" + }, + "MomentSpec" : { + "required" : [ "content", "owner" ], + "type" : "object", + "properties" : { + "approved" : { + "type" : "boolean", + "default" : false + }, + "approvedTime" : { + "type" : "string", + "format" : "date-time" + }, + "content" : { + "$ref" : "#/components/schemas/MomentContent" + }, + "owner" : { + "type" : "string", + "description" : "Owner of the moment" + }, + "releaseTime" : { + "type" : "string", + "description" : "Release timestamp. This field can be customized by owner", + "format" : "date-time" + }, + "tags" : { + "uniqueItems" : true, + "type" : "array", + "description" : "Tags of the moment", + "items" : { + "type" : "string", + "description" : "Tags of the moment" + } + }, + "visible" : { + "type" : "string", + "description" : "Visible indicates when to show publicly. Default is public", + "default" : "PUBLIC", + "enum" : [ "PUBLIC", "PRIVATE" ] + } + } + }, + "MomentStatus" : { + "type" : "object", + "properties" : { + "observedVersion" : { + "type" : "integer", + "format" : "int64" + }, + "permalink" : { + "type" : "string" + } + } + }, + "MoveOperation" : { + "required" : [ "op", "from", "path" ], + "type" : "object", + "properties" : { + "from" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + }, + "op" : { + "type" : "string", + "enum" : [ "move" ] + }, + "path" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + } + } + }, + "RemoveOperation" : { + "required" : [ "op", "path" ], + "type" : "object", + "properties" : { + "op" : { + "type" : "string", + "enum" : [ "remove" ] + }, + "path" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + } + } + }, + "ReplaceOperation" : { + "required" : [ "op", "path", "value" ], + "type" : "object", + "properties" : { + "op" : { + "type" : "string", + "enum" : [ "replace" ] + }, + "path" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + }, + "value" : { + "description" : "Value can be any JSON value" + } + } + }, + "Stats" : { + "type" : "object", + "properties" : { + "approvedComment" : { + "type" : "integer", + "format" : "int32" + }, + "totalComment" : { + "type" : "integer", + "format" : "int32" + }, + "upvote" : { + "type" : "integer", + "format" : "int32" + } + } + }, + "TestOperation" : { + "required" : [ "op", "path", "value" ], + "type" : "object", + "properties" : { + "op" : { + "type" : "string", + "enum" : [ "test" ] + }, + "path" : { + "pattern" : "^(/[^/~]*(~[01][^/~]*)*)*$", + "type" : "string", + "description" : "A JSON Pointer path pointing to the location to move/copy from.", + "example" : "/a/b/c" + }, + "value" : { + "description" : "Value can be any JSON value" + } + } + } + }, + "securitySchemes" : { + "basicAuth" : { + "scheme" : "basic", + "type" : "http" + }, + "bearerAuth" : { + "bearerFormat" : "JWT", + "scheme" : "bearer", + "type" : "http" + } + } + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..f656ede --- /dev/null +++ b/build.gradle @@ -0,0 +1,74 @@ +plugins { + id "com.github.node-gradle.node" version "5.0.0" + id "io.freefair.lombok" version "8.0.0-rc2" + id "run.halo.plugin.devtools" version "0.4.1" + id 'java' +} + +group 'run.halo.moments' +sourceCompatibility = JavaVersion.VERSION_17 + +repositories { + mavenCentral() + maven { url 'https://repo.spring.io/milestone' } + maven { url 'https://s01.oss.sonatype.org/content/repositories/releases' } +} + +dependencies { + implementation platform('run.halo.tools.platform:plugin:2.20.11') + compileOnly 'run.halo.app:api' + compileOnly "run.halo.feed:api:1.4.0" + + testImplementation 'run.halo.app:api' + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} + +test { + useJUnitPlatform() +} + +node { + nodeProjectDir = file("${project.projectDir}/console") +} + +tasks.register('installDepsForUI', PnpmTask) { + args = ['install'] +} + +tasks.register('buildFrontend', PnpmTask) { + args = ['build'] + dependsOn('installDepsForUI') +} + +build { + tasks.named('compileJava').configure { + dependsOn('buildFrontend') + } +} + +halo { + version = '2.21.0-beta.2' + debug = true; +} + +haloPlugin { + openApi { + outputDir = file("$rootDir/api-docs/openapi/v3_0") + groupingRules { + momentsApi { + displayName = 'Extension API for Moments Plugin' + pathsToMatch = [ + '/apis/moment.halo.run/v1alpha1/**', + '/apis/console.api.moment.halo.run/v1alpha1/**', + '/apis/uc.api.moment.halo.run/v1alpha1/**' + ] + } + } + groupedApiMappings = [ + '/v3/api-docs/momentsApi': 'momentsApi.json' + ] + generator { + outputDir = file("${projectDir}/console/src/api/generated") + } + } +} \ No newline at end of file diff --git a/console/.eslintrc.cjs b/console/.eslintrc.cjs new file mode 100644 index 0000000..770187a --- /dev/null +++ b/console/.eslintrc.cjs @@ -0,0 +1,20 @@ +/* eslint-env node */ +require("@rushstack/eslint-patch/modern-module-resolution"); + +module.exports = { + root: true, + extends: [ + "plugin:vue/vue3-recommended", + "eslint:recommended", + "@vue/eslint-config-typescript/recommended", + "@vue/eslint-config-prettier", + "@unocss", + ], + env: { + "vue/setup-compiler-macros": true, + }, + rules: { + "vue/no-v-html": "off", + "@unocss/enforce-class-compile": 1, + }, +}; diff --git a/console/env.d.ts b/console/env.d.ts new file mode 100644 index 0000000..9195d76 --- /dev/null +++ b/console/env.d.ts @@ -0,0 +1,18 @@ +/// +/// + +export {}; + +declare module "*.vue" { + import Vue from "vue"; + export default Vue; +} + +declare global { + interface Window { + enabledPlugins: { + name: string; + version: string; + }[]; + } +} diff --git a/console/package.json b/console/package.json new file mode 100644 index 0000000..038d629 --- /dev/null +++ b/console/package.json @@ -0,0 +1,51 @@ +{ + "type": "module", + "scripts": { + "build": "rsbuild build", + "dev": "rsbuild build --env-mode development --watch", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path ../.gitignore", + "prettier": "prettier --write src/" + }, + "dependencies": { + "@halo-dev/api-client": "^2.18.0", + "@halo-dev/components": "https://pkg.pr.new/@halo-dev/components@7383", + "@halo-dev/console-shared": "^2.18.0", + "@halo-dev/richtext-editor": "^2.18.0", + "@tanstack/vue-query": "^4.37.1", + "@tiptap/suggestion": "2.11.2", + "@vueuse/core": "^9.13.0", + "@vueuse/router": "^10.11.1", + "axios": "^1.7.3", + "dayjs": "^1.11.12", + "es-toolkit": "^1.39.7", + "floating-vue": "2.0.0-beta.20", + "tippy.js": "^6.3.7", + "vue": "^3.4.37", + "vue-datepicker-next": "^1.0.3", + "vue-router": "^4.4.3" + }, + "devDependencies": { + "@halo-dev/ui-plugin-bundler-kit": "2.21.2", + "@iconify/json": "^2.2.235", + "@rsbuild/core": "^1.4.6", + "@rsbuild/plugin-sass": "^1.3.3", + "@rushstack/eslint-patch": "^1.10.4", + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.14.9", + "@unocss/eslint-config": "^66.2.0", + "@unocss/webpack": "^66.2.0", + "@vue/eslint-config-prettier": "^7.1.0", + "@vue/eslint-config-typescript": "^10.0.0", + "@vue/tsconfig": "^0.5.1", + "eslint": "^8.57.0", + "eslint-plugin-vue": "^8.7.1", + "prettier": "^2.8.8", + "sass-embedded": "^1.89.2", + "typescript": "~5.5.4", + "unocss": "^66.2.0", + "unplugin-icons": "^22.1.0", + "vue-tsc": "^2.0.24" + }, + "packageManager": "pnpm@10.12.1+sha512.f0dda8580f0ee9481c5c79a1d927b9164f2c478e90992ad268bbb2465a736984391d6333d2c327913578b2804af33474ca554ba29c04a8b13060a717675ae3ac" +} diff --git a/console/patches/@tiptap__suggestion@2.11.2.patch b/console/patches/@tiptap__suggestion@2.11.2.patch new file mode 100644 index 0000000..f8eae45 --- /dev/null +++ b/console/patches/@tiptap__suggestion@2.11.2.patch @@ -0,0 +1,14 @@ +diff --git a/dist/index.js b/dist/index.js +index 1f04899a2a7f76f7c53f7f1fe82ae43262e2a8b7..7a14eb120ce1d3d2146c1c208c5f909a2d529638 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -1,6 +1,6 @@ +-import { PluginKey, Plugin } from '@tiptap/pm/state'; +-import { DecorationSet, Decoration } from '@tiptap/pm/view'; +-import { escapeForRegEx } from '@tiptap/core'; ++import { PluginKey, Plugin } from '@halo-dev/richtext-editor'; ++import { DecorationSet, Decoration } from '@halo-dev/richtext-editor'; ++import { escapeForRegEx } from '@halo-dev/richtext-editor'; + + function findSuggestionMatch(config) { + var _a; diff --git a/console/pnpm-lock.yaml b/console/pnpm-lock.yaml new file mode 100644 index 0000000..f7464a0 --- /dev/null +++ b/console/pnpm-lock.yaml @@ -0,0 +1,5609 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +patchedDependencies: + '@tiptap/suggestion@2.11.2': + hash: 93a4c9b57ce80e49a411cc52e124b5e16118c33cfc70fabc08e0be77f6686a6f + path: patches/@tiptap__suggestion@2.11.2.patch + +importers: + + .: + dependencies: + '@halo-dev/api-client': + specifier: ^2.18.0 + version: 2.18.0(axios@1.7.3) + '@halo-dev/components': + specifier: https://pkg.pr.new/@halo-dev/components@7383 + version: https://pkg.pr.new/@halo-dev/components@7383(vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4)) + '@halo-dev/console-shared': + specifier: ^2.18.0 + version: 2.18.0(axios@1.7.3)(vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4)) + '@halo-dev/richtext-editor': + specifier: ^2.18.0 + version: 2.18.0(vue@3.4.37(typescript@5.5.4)) + '@tanstack/vue-query': + specifier: ^4.37.1 + version: 4.37.1(vue@3.4.37(typescript@5.5.4)) + '@tiptap/suggestion': + specifier: 2.11.2 + version: 2.11.2(patch_hash=93a4c9b57ce80e49a411cc52e124b5e16118c33cfc70fabc08e0be77f6686a6f)(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@vueuse/core': + specifier: ^9.13.0 + version: 9.13.0(vue@3.4.37(typescript@5.5.4)) + '@vueuse/router': + specifier: ^10.11.1 + version: 10.11.1(vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4)) + axios: + specifier: ^1.7.3 + version: 1.7.3 + dayjs: + specifier: ^1.11.12 + version: 1.11.12 + es-toolkit: + specifier: ^1.39.7 + version: 1.39.7 + floating-vue: + specifier: 2.0.0-beta.20 + version: 2.0.0-beta.20(vue@3.4.37(typescript@5.5.4)) + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 + vue: + specifier: ^3.4.37 + version: 3.4.37(typescript@5.5.4) + vue-datepicker-next: + specifier: ^1.0.3 + version: 1.0.3(vue@3.4.37(typescript@5.5.4)) + vue-router: + specifier: ^4.4.3 + version: 4.4.3(vue@3.4.37(typescript@5.5.4)) + devDependencies: + '@halo-dev/ui-plugin-bundler-kit': + specifier: 2.21.2 + version: 2.21.2(@rsbuild/core@1.4.6)(@rsbuild/plugin-vue@1.1.0(@rsbuild/core@1.4.6)(@vue/compiler-sfc@3.4.37)(vue@3.4.37(typescript@5.5.4)))(@vitejs/plugin-vue@6.0.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)))(axios@1.7.3)(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0)) + '@iconify/json': + specifier: ^2.2.235 + version: 2.2.235 + '@rsbuild/core': + specifier: ^1.4.6 + version: 1.4.6 + '@rsbuild/plugin-sass': + specifier: ^1.3.3 + version: 1.3.3(@rsbuild/core@1.4.6) + '@rushstack/eslint-patch': + specifier: ^1.10.4 + version: 1.10.4 + '@tsconfig/node20': + specifier: ^20.1.4 + version: 20.1.4 + '@types/node': + specifier: ^20.14.9 + version: 20.14.15 + '@unocss/eslint-config': + specifier: ^66.2.0 + version: 66.2.0(eslint@8.57.0)(typescript@5.5.4) + '@unocss/webpack': + specifier: ^66.2.0 + version: 66.2.0(webpack@5.99.9) + '@vue/eslint-config-prettier': + specifier: ^7.1.0 + version: 7.1.0(eslint@8.57.0)(prettier@2.8.8) + '@vue/eslint-config-typescript': + specifier: ^10.0.0 + version: 10.0.0(eslint-plugin-vue@8.7.1(eslint@8.57.0))(eslint@8.57.0)(typescript@5.5.4) + '@vue/tsconfig': + specifier: ^0.5.1 + version: 0.5.1 + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-plugin-vue: + specifier: ^8.7.1 + version: 8.7.1(eslint@8.57.0) + prettier: + specifier: ^2.8.8 + version: 2.8.8 + sass-embedded: + specifier: ^1.89.2 + version: 1.89.2 + typescript: + specifier: ~5.5.4 + version: 5.5.4 + unocss: + specifier: ^66.2.0 + version: 66.2.0(@unocss/webpack@66.2.0(webpack@5.99.9))(postcss@8.5.6)(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)) + unplugin-icons: + specifier: ^22.1.0 + version: 22.1.0(@vue/compiler-sfc@3.4.37) + vue-tsc: + specifier: ^2.0.24 + version: 2.0.29(typescript@5.5.4) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + + '@babel/helper-string-parser@7.24.8': + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.8': + resolution: {integrity: sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.24.9': + resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==} + engines: {node: '>=6.9.0'} + + '@bufbuild/protobuf@2.5.2': + resolution: {integrity: sha512-foZ7qr0IsUBjzWIq+SuBLfdQCpJ1j8cTuNNT4owngTHoN5KsJb8L9t65fzz7SCeSWzescoOil/0ldqiL041ABg==} + + '@ckpack/vue-color@1.5.0': + resolution: {integrity: sha512-dj1zXVyay2m4LdlLJCQSdIS2FYwUl77BZqyKmUXiehyqjCP0bGYnPcL38lrShzYUc2FdkYQX8ANZZjRahd4PQw==} + engines: {node: '>=12'} + peerDependencies: + vue: ^3.2.0 + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@emnapi/core@1.4.4': + resolution: {integrity: sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==} + + '@emnapi/runtime@1.4.4': + resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==} + + '@emnapi/wasi-threads@1.0.3': + resolution: {integrity: sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/eslint-utils@4.7.0': + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@floating-ui/core@0.3.1': + resolution: {integrity: sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g==} + + '@floating-ui/core@1.5.1': + resolution: {integrity: sha512-QgcKYwzcc8vvZ4n/5uklchy8KVdjJwcOeI+HnnTNclJjs2nYsy23DOCf+sSV1kBwD9yDAoVKCkv/gEPzgQU3Pw==} + + '@floating-ui/dom@0.1.10': + resolution: {integrity: sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==} + + '@floating-ui/dom@1.1.1': + resolution: {integrity: sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==} + + '@floating-ui/utils@0.1.6': + resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + + '@halo-dev/api-client@2.18.0': + resolution: {integrity: sha512-A7dyC4CstFU8B1XkgnrCaWu15XyICYMnynUPyGzfr1ljwdIxfGwN7xtNt4CSxJ7Ky2b20dZrN8QR7RB5j1qmHg==} + peerDependencies: + axios: ^1.7.x + + '@halo-dev/api-client@2.21.1': + resolution: {integrity: sha512-4sfpSui4YO2u7W73r3ECoegK+/kVzLHv/a16pT23gZUqazK+5ZAqpDqVYHhbpyBVbs/fmsUuMgI8TXVLo6kZjg==} + peerDependencies: + axios: ^1.7.x + + '@halo-dev/components@https://pkg.pr.new/@halo-dev/components@7383': + resolution: {tarball: https://pkg.pr.new/@halo-dev/components@7383} + version: 2.21.0 + peerDependencies: + vue: ^3.5.13 + vue-router: ^4.3.2 + + '@halo-dev/console-shared@2.18.0': + resolution: {integrity: sha512-PjqXCpEeJD5rAdycQYCCTRzeDhE67v6xjgPMDovy5duZrHt7V7mvEPP0XVRMPsHAAU4C1lGAfqKHdl8RsdwJow==} + peerDependencies: + vue: ^3.4.27 + vue-router: ^4.3.2 + + '@halo-dev/richtext-editor@2.18.0': + resolution: {integrity: sha512-kCLzSwYmosQ73KWR/hAIePgAEZgLv0YTVCiuhTM8RIDA+wRxZuglbB+7ZHI9ccDzyjsdC0TxtnDKoTRn5RDS1A==} + peerDependencies: + vue: ^3.4.27 + + '@halo-dev/ui-plugin-bundler-kit@2.21.2': + resolution: {integrity: sha512-CjKAxs02VlrMGyPxV7fEDEfNOPoQDT22i4RkK/sts1JvysYEHNXhe9mZ9qa9CwVX4dorLGgd++l0nWODuAsvRQ==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + '@rsbuild/core': ^1.0.0 + '@rsbuild/plugin-vue': ^1.0.0 + '@vitejs/plugin-vue': ^5.0.0 || ^6.0.0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@iconify/json@2.2.235': + resolution: {integrity: sha512-8a5r/uIZY3DvJPCkRCMly0BgmsxItMTR6RjGnifQ0kGrLSE7TpdYIfQya9Ckd2qfWjD20WZmWblpFm1FcF6ybQ==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@module-federation/error-codes@0.15.0': + resolution: {integrity: sha512-CFJSF+XKwTcy0PFZ2l/fSUpR4z247+Uwzp1sXVkdIfJ/ATsnqf0Q01f51qqSEA6MYdQi6FKos9FIcu3dCpQNdg==} + + '@module-federation/runtime-core@0.15.0': + resolution: {integrity: sha512-RYzI61fRDrhyhaEOXH3AgIGlHiot0wPFXu7F43cr+ZnTi+VlSYWLdlZ4NBuT9uV6JSmH54/c+tEZm5SXgKR2sQ==} + + '@module-federation/runtime-tools@0.15.0': + resolution: {integrity: sha512-kzFn3ObUeBp5vaEtN1WMxhTYBuYEErxugu1RzFUERD21X3BZ+b4cWwdFJuBDlsmVjctIg/QSOoZoPXRKAO0foA==} + + '@module-federation/runtime@0.15.0': + resolution: {integrity: sha512-dTPsCNum9Bhu3yPOcrPYq0YnM9eCMMMNB1wuiqf1+sFbQlNApF0vfZxooqz3ln0/MpgE0jerVvFsLVGfqvC9Ug==} + + '@module-federation/sdk@0.15.0': + resolution: {integrity: sha512-PWiYbGcJrKUD6JZiEPihrXhV3bgXdll4bV7rU+opV7tHaun+Z0CdcawjZ82Xnpb8MCPGmqHwa1MPFeUs66zksw==} + + '@module-federation/webpack-bundler-runtime@0.15.0': + resolution: {integrity: sha512-i+3wu2Ljh2TmuUpsnjwZVupOVqV50jP0ndA8PSP4gwMKlgdGeaZ4VH5KkHAXGr2eiYUxYLMrJXz1+eILJqeGDg==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@polka/url@1.0.0-next.25': + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + + '@popperjs/core@2.11.6': + resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} + + '@quansync/fs@0.1.3': + resolution: {integrity: sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==} + engines: {node: '>=20.0.0'} + + '@remirror/core-constants@2.0.2': + resolution: {integrity: sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==} + + '@rolldown/pluginutils@1.0.0-beta.19': + resolution: {integrity: sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==} + + '@rollup/rollup-android-arm-eabi@4.20.0': + resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.20.0': + resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.20.0': + resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.20.0': + resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.20.0': + resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.20.0': + resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.20.0': + resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.20.0': + resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': + resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.20.0': + resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.20.0': + resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.20.0': + resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.20.0': + resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.20.0': + resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.20.0': + resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.20.0': + resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==} + cpu: [x64] + os: [win32] + + '@rsbuild/core@1.4.6': + resolution: {integrity: sha512-Z5e7ExKGmLv/wvBQEgSE2bPpR9movvq0jnfXjtYzrLzJFGsKFwL/5KShgdr6hUtVGGLoCCCHHHaTBL6BPcNvZA==} + engines: {node: '>=16.10.0'} + hasBin: true + + '@rsbuild/plugin-sass@1.3.3': + resolution: {integrity: sha512-TcfhLm/SWTTlCFIED/usH/aiHUB5qqTZ1YwFK0gAtaDNuQFSLiRq2OGZ3c934hYyKB95ckgj1o+gDcQvZbaumg==} + peerDependencies: + '@rsbuild/core': 1.x + + '@rsbuild/plugin-vue@1.1.0': + resolution: {integrity: sha512-SQ8CoS7qUTQUYcMxWgMLQcukE/fQ5pIzMDkvpqqoV4zQyWcw0kJ5z34ctCIaIA4vvOhXwuEi2XLwQalvGQI8Tg==} + peerDependencies: + '@rsbuild/core': 1.x + + '@rspack/binding-darwin-arm64@1.4.6': + resolution: {integrity: sha512-K37H8e58eY7zBHGeMVtT7m0Z5XvlNQX7YDuaxlbiA4hZxqeRoS5BMX/YOcDiGdNbSuqv+iG5GSckJ99YUI67Cw==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.4.6': + resolution: {integrity: sha512-3p5u9q/Q9MMVe+5XFJ/WiFrzNrrxUjJFR19kB1k/KMcf8ox982xWjnfJuBkET/k7Hn0EZL7L06ym447uIfAVAg==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.4.6': + resolution: {integrity: sha512-ZrrCn5b037ImZfZ3MShJrRw4d5M3Tq2rFJupr+SGMg7GTl2T6xEmo3ER/evHlT6e0ETi6tRWPxC9A1125jbSQA==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.4.6': + resolution: {integrity: sha512-0a30oR6ZmZrqmsOHQYrbZPCxAgnqAiqlbFozdhHs+Yu2bS7SDiLpdjMg0PHwLZT2+siiMWsLodFZlXRJE54oAQ==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.4.6': + resolution: {integrity: sha512-u6pq1aq7bX+NABVDDTOzH64KMj1KJn8fUWO+FaX7Kr7PBjhmxNRs4OaWZjbXEY6COhMYEJZ04h4DhY+lRzcKjA==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.4.6': + resolution: {integrity: sha512-rjP/1dWKB828kzd4/QpDYNVasUAKDj0OeRJGh5L/RluSH3pEqhxm5FwvndpmFDv6m3iPekZ4IO26UrpGJmE9fw==} + cpu: [x64] + os: [linux] + + '@rspack/binding-wasm32-wasi@1.4.6': + resolution: {integrity: sha512-5M0g7TaWgCFQJr4NKYW2bTLbQJuAQIgZL7WmiDwotgscBJDQWJVBayFEsnM6PYX1Inmu6RNhQ44BKIYwwoSyYw==} + cpu: [wasm32] + + '@rspack/binding-win32-arm64-msvc@1.4.6': + resolution: {integrity: sha512-thPCdbh4O+uEAJ8AvXBWZIOW0ZopJAN3CX2zlprso8Cnhi4wDseTtrIxFQh7cTo6pR3xSZAIv/zHd+MMF8TImA==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.4.6': + resolution: {integrity: sha512-KQmm6c/ZfJKQ/TpzbY6J0pDvUB9kwTXzp+xl2FhGq2RXid8uyDS8ZqbeJA6LDxgttsmp4PRVJjMdLVYjZenfLw==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.4.6': + resolution: {integrity: sha512-WRRhCsJ+xcOmvzo/r/b2UTejPLnDEbaD/te1yQwHe97sUaFGr3u1Njk6lVYRTV6mEvUopEChb8yAq/S4dvaGLg==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.4.6': + resolution: {integrity: sha512-rRc6sbKWxhomxxJeqi4QS3S/2T6pKf4JwC/VHXs7KXw7lHXHa3yxPynmn3xHstL0H6VLaM5xQj87Wh7lQYRAPg==} + + '@rspack/core@1.4.6': + resolution: {integrity: sha512-/OpJLv7dPEE7x/qCXGecRm9suNxz5w0Dheq2sh0TjTCUHodtMET3T+FlRWznBAlZeNuHLECDp0DWhchgS8BWuA==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@rspack/lite-tapable@1.0.1': + resolution: {integrity: sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==} + engines: {node: '>=16.0.0'} + + '@rushstack/eslint-patch@1.10.4': + resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + + '@tanstack/match-sorter-utils@8.7.6': + resolution: {integrity: sha512-2AMpRiA6QivHOUiBpQAVxjiHAA68Ei23ZUMNaRJrN6omWiSFLoYrxGcT6BXtuzp0Jw4h6HZCmGGIM/gbwebO2A==} + engines: {node: '>=12'} + + '@tanstack/query-core@4.36.1': + resolution: {integrity: sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==} + + '@tanstack/vue-query@4.37.1': + resolution: {integrity: sha512-QzCQ94g2oZQcEfI4nfqa6Qr3aFXtXiEH17Jho+QFl73c7epqsWNcyP3ovF1fgJz5jEOE5OYtwgkoaRKIRaSigg==} + peerDependencies: + '@vue/composition-api': ^1.1.2 + vue: ^2.5.0 || ^3.0.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + '@tiptap/core@2.5.9': + resolution: {integrity: sha512-PPUR+0tbr+wX2G8RG4FEps4qhbnAPEeXK1FUtirLXSRh8vm+TDgafu3sms7wBc4fAyw9zTO/KNNZ90GBe04guA==} + peerDependencies: + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-blockquote@2.5.9': + resolution: {integrity: sha512-LhGyigmd/v1OjYPeoVK8UvFHbH6ffh175ZuNvseZY4PsBd7kZhrSUiuMG8xYdNX8FxamsxAzr2YpsYnOzu3W7A==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-bold@2.5.9': + resolution: {integrity: sha512-XUJdzFb31t0+bwiRquJf0btBpqOB3axQNHTKM9XADuL4S+Z6OBPj0I5rYINeElw/Q7muvdWrHWHh/ovNJA1/5A==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-bubble-menu@2.5.9': + resolution: {integrity: sha512-NddZ8Qn5dgPPa1W4yk0jdhF4tDBh0FwzBpbnDu2Xz/0TUHrA36ugB2CvR5xS1we4zUKckgpVqOqgdelrmqqFVg==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-bullet-list@2.5.9': + resolution: {integrity: sha512-hJTv1x4omFgaID4LMRT5tOZb/VKmi8Kc6jsf4JNq4Grxd2sANmr9qpmKtBZvviK+XD5PpTXHvL+1c8C1SQtuHQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-code-block-lowlight@2.5.9': + resolution: {integrity: sha512-taIXxXQ/Lka9CegHFHQS+nx6cX9i9Ws63ZFMPbrXLMSJRhXk8+m4UAoGZQJH9CGGb5/Rv0p3Z8I59AGiyUHLEw==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/extension-code-block': ^2.5.9 + '@tiptap/pm': ^2.5.9 + highlight.js: ^11 + lowlight: ^2 || ^3 + + '@tiptap/extension-code-block@2.5.9': + resolution: {integrity: sha512-+MUwp0VFFv2aFiZ/qN6q10vfIc6VhLoFFpfuETX10eIRks0Xuj2nGiqCDj7ca0/M44bRg2VvW8+tg/ZEHFNl9g==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-code@2.5.9': + resolution: {integrity: sha512-Q1PL3DUXiEe5eYUwOug1haRjSaB0doAKwx7KFVI+kSGbDwCV6BdkKAeYf3us/O2pMP9D0im8RWX4dbSnatgwBA==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-color@2.5.9': + resolution: {integrity: sha512-VUGCT9iqD/Ni9arLIxkCbykAElRMFyew7uk2kbbNvttzdwzmZkbslEgCiaEZQTqKr8w4wjuQL14YOtXc6iwEww==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/extension-text-style': ^2.5.9 + + '@tiptap/extension-document@2.5.9': + resolution: {integrity: sha512-VdNZYDyCzC3W430UdeRXR9IZzPeODSbi5Xz/JEdV93THVp8AC9CrZR7/qjqdBTgbTB54VP8Yr6bKfCoIAF0BeQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-dropcursor@2.5.9': + resolution: {integrity: sha512-nEOb37UryG6bsU9JAs/HojE6Jg43LupNTAMISbnuB1CPAeAqNsFMwORd9eEPkyEwnQT7MkhsMOSJM44GoPGIFA==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-floating-menu@2.5.9': + resolution: {integrity: sha512-MWJIQQT6e5MgqHny8neeH2Dx926nVPF7sv4p84nX4E0dnkRbEYUP8mCsWYhSUvxxIif6e+yY+4654f2Q9qTx1w==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-hard-break@2.5.9': + resolution: {integrity: sha512-8hQ63SgZRG4BqHOeSfeaowG2eMr2beced018pOGbpHbE3XSYoISkMVuFz4Z8UEVR3W9dTbKo4wxNufSTducocQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-heading@2.5.9': + resolution: {integrity: sha512-HHowAlGUbFn1qvmY02ydM7qiPPMTGhAJn2A46enDRjNHW5UoqeMfkMpTEYaioOexyguRFSfDT3gpK68IHkQORQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-highlight@2.5.9': + resolution: {integrity: sha512-tRaSIIbCI7aBlvlmgUgBI5lVBqnMy49lc++UVAx1Pjey1j2KW031vUyvZfEwf6wk8Y7W3kVSkN0mW9IYCcOAOQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-history@2.5.9': + resolution: {integrity: sha512-hGPtJgoZSwnVVqi/xipC2ET/9X2G2UI/Y+M3IYV1ZlM0tCYsv4spNi3uXlZqnXRwYcBXLk5u6e/dmsy5QFbL8g==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-horizontal-rule@2.5.9': + resolution: {integrity: sha512-/ES5NdxCndBmZAgIXSpCJH8YzENcpxR0S8w34coSWyv+iW0Sq7rW/mksQw8ZIVsj8a7ntpoY5OoRFpSlqcvyGw==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-image@2.5.9': + resolution: {integrity: sha512-v4WZISCvbriac6HE6v7kYYY7KX+v9rJaIZC3gbYGtqnBWfaAwZiVVu8Z03xSrqYhoc+KHuI+oQ4VubcvZ/i7OQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-italic@2.5.9': + resolution: {integrity: sha512-Bw+P139L4cy+B56zpUiRjP8BZSaAUl3JFMnr/FO+FG55QhCxFMXIc6XrC3vslNy5ef3B3zv4gCttS3ee8ByMiw==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-link@2.5.9': + resolution: {integrity: sha512-7v9yRsX7NuiY8DPslIsPIlFqcD8aGBMLqfEGXltJDvuG6kykdr+khEZeWcJ8ihHIL4yWR3/MAgeT2W72Z/nxiQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-list-item@2.5.9': + resolution: {integrity: sha512-d9Eo+vBz74SMxP0r25aqiErV256C+lGz+VWMjOoqJa6xWLM1keYy12JtGQWJi8UDVZrDskJKCHq81A0uLt27WA==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-list-keymap@2.5.9': + resolution: {integrity: sha512-byZupOf1uMwiBXwh7fG4viS7sZvTqr4GmROKQnLDfnxKYF7+lOKKxQZCDBo4AXWfm4OOB29yqTtzuo6Xb+aMuQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-ordered-list@2.5.9': + resolution: {integrity: sha512-9MsWpvVvzILuEOd/GdroF7RI7uDuE1M6at9rzsaVGvCPVHZBvu1XR3MSVK5OdiJbbJuPGttlzEFLaN/rQdCGFg==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-paragraph@2.5.9': + resolution: {integrity: sha512-HDXGiHTJ/V85dbDMjcFj4XfqyTQZqry6V21ucMzgBZYX60X3gIn7VpQTQnnRjvULSgtfOASSJP6BELc5TyiK0w==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-placeholder@2.5.9': + resolution: {integrity: sha512-ytKmlSiebtCBXoMPE2cup48DR0rQiekXhLKLkNyt7m8tSXkaRO4eDaFqCqPEXLeQXWdhwWEoPM6Cejaaa3ztkA==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-strike@2.5.9': + resolution: {integrity: sha512-QezkOZpczpl09S8lp5JL7sRkwREoPY16Y/lTvBcFKm3TZbVzYZZ/KwS0zpwK9HXTfXr8os4L9AGjQf0tHonX+w==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-subscript@2.5.9': + resolution: {integrity: sha512-SY1VCf/zlsBLowZaayXGl7dkIGPMNieCO0P1luFBjsiEXCRff0WYVpxi24wzgMeWE6q28SXmd3eD5BsGBudx9g==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-superscript@2.5.9': + resolution: {integrity: sha512-ggpVx/oJk6tBDq7mNxrJNXhitHVqkJVbeOKaac5FACCoA3ZzHgZ75JooxZqn5wRoCaqShmbljLb8ZqefdX/PRg==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-table-row@2.5.9': + resolution: {integrity: sha512-VPmkzraT9m7g2/88qsTF9EQdFvkcwhvOD+WWZTflN92LMsRHddJt3peJ/fpuf0QKnwwn5qIB3fXWja4VcZe3wQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-table@2.5.9': + resolution: {integrity: sha512-kLZdYBO0Ug4sNjzyDfa3W29qL4HdRK/IaMxcmcEbyKSt42qiMJlIelbGzVENzxe9AbcNTeiWje70Nhk4dbb8Ag==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-task-item@2.5.9': + resolution: {integrity: sha512-g4HK3r3yNE0RcXQOkJHs94Ws/fhhTqa1L5iAy4gwYKNNFFnIQl8BpE6nn9d5h33kWDN9jjY+PZmq+0PvxCLODQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + + '@tiptap/extension-task-list@2.5.9': + resolution: {integrity: sha512-OylVo5cAh0117PzhyM8MGaUIrCskGiF7v7x6/zAHMFIqVdcbKsq+hMueVPnABfOyLcIH5Zojo3NzNOJeKeblCg==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-text-align@2.5.9': + resolution: {integrity: sha512-WYp9v7NEWddTt2Avbk3k/3g/fkL0hh4HEG97ubCPAj2aZzlZ85AEcRN8o4wLXJvZNj43nKQtZeel84INS5uzOg==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-text-style@2.5.9': + resolution: {integrity: sha512-1pNnl/a5EdY7g3IeFomm0B6eiTvAFOBeJGswoYxogzHmkWbLFhXFdgZ6qz7+k985w4qscsG1GpvtOW3IrJ9J6g==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-text@2.5.9': + resolution: {integrity: sha512-W0pfiQUPsMkwaV5Y/wKW4cFsyXAIkyOFt7uN5u6LrZ/iW9KZ/IsDODPJDikWp0aeQnXzT9NNQULTpCjbHzzS6g==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/extension-underline@2.5.9': + resolution: {integrity: sha512-1gFBLzzphwJHsPLwUl9xosErEmtG2c2Sa2ajyS4uRjfl9X7+Li2O2WelZLHZGgTHWliE6ptA3m1MyXppHoitbg==} + peerDependencies: + '@tiptap/core': ^2.5.9 + + '@tiptap/pm@2.5.9': + resolution: {integrity: sha512-YSUaEQVtvZnGzGjif2Tl2o9utE+6tR2Djhz0EqFUcAUEVhOMk7UYUO+r/aPfcCRraIoKKuDQzyCpjKmJicjCUA==} + + '@tiptap/suggestion@2.11.2': + resolution: {integrity: sha512-jA06veq7Ko7+yeyy4pymTGdqHfWNydDIioPCR0yddbon+3+aLP2hE31J+/1/8FmhSoE0qJsEki3/RU7pKTLgrg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/vue-3@2.5.9': + resolution: {integrity: sha512-Iz7HMW9A0jinYnMs2wZxjI+e5fc5MQmjgmfE0kQmimpgISBregW8vJyDKDPIZVJz5LQPLL045G3mL+7V8fExrQ==} + peerDependencies: + '@tiptap/core': ^2.5.9 + '@tiptap/pm': ^2.5.9 + vue: ^3.0.0 + + '@tsconfig/node20@20.1.4': + resolution: {integrity: sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==} + + '@tybys/wasm-util@0.10.0': + resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.3': + resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==} + + '@types/json-schema@7.0.11': + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@20.14.15': + resolution: {integrity: sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==} + + '@types/semver@7.3.13': + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + + '@types/unist@2.0.6': + resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + + '@types/web-bluetooth@0.0.16': + resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + + '@typescript-eslint/eslint-plugin@5.54.0': + resolution: {integrity: sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@5.54.0': + resolution: {integrity: sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/project-service@8.34.0': + resolution: {integrity: sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/scope-manager@5.54.0': + resolution: {integrity: sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/scope-manager@8.34.0': + resolution: {integrity: sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.34.0': + resolution: {integrity: sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/type-utils@5.54.0': + resolution: {integrity: sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@5.54.0': + resolution: {integrity: sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/types@8.34.0': + resolution: {integrity: sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@5.54.0': + resolution: {integrity: sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@8.34.0': + resolution: {integrity: sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/utils@5.54.0': + resolution: {integrity: sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/utils@8.34.0': + resolution: {integrity: sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/visitor-keys@5.54.0': + resolution: {integrity: sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/visitor-keys@8.34.0': + resolution: {integrity: sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + '@unocss/astro@66.2.0': + resolution: {integrity: sha512-UL95urnTaAtdu4WfRRuD52vziULkatco+Mdmza6FWhMnMaCvj5ErY1VDJQRCyO5foEYT4ky8pbzs5gv6ZGU40A==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 + peerDependenciesMeta: + vite: + optional: true + + '@unocss/cli@66.2.0': + resolution: {integrity: sha512-8yV4YuDFuuw9uizj9ic62f8AVqINz5zAaNFMi9SbfkAhDwHCIuozTQEgaQ80sH3M8wPc+lsZHi+HTbsvRXdFaA==} + engines: {node: '>=14'} + hasBin: true + + '@unocss/config@66.2.0': + resolution: {integrity: sha512-vJM00OU1FG/sZ4+uTO20e3ASRuUzlKkihwfd8BPTFDamkdbYehl7wZO1DI1TxtQv+bIc4Ociox6EKKCeQVJ/mA==} + engines: {node: '>=14'} + + '@unocss/core@66.2.0': + resolution: {integrity: sha512-jq+UPvmf271MjY/RoREBmjSCzTYdjzdlgBcjmtymYjBRg7a6a0GiSuhdL0D20cwQ4MoBvlO1tIzgCqnqImACBg==} + + '@unocss/eslint-config@66.2.0': + resolution: {integrity: sha512-X3kVIxoPRoTEEdSaIkx8N9yO3QDFHoT+HLyAMCFOiFQxzZ0Khih71yqrPqSOFIhxIUHMGgSAUjw3pOfgY068XA==} + engines: {node: '>=14'} + + '@unocss/eslint-plugin@66.2.0': + resolution: {integrity: sha512-ejOrpVUx2/ObGS2qOZ7rZJFd8mPgzJpxKoLDiBzuPuLZ5oznADXIZfz83lXMUK1BK0XlOl91Gijt5SN8IHI/Nw==} + engines: {node: '>=14'} + + '@unocss/extractor-arbitrary-variants@66.2.0': + resolution: {integrity: sha512-tRvWLbLLZweCv+eujbkvjflNclbkrJHhW2asuBUcaHXCzXIHCYgbBdF3lV5ww1lBBfEUWekgyFC/9fbB4rh1fg==} + + '@unocss/inspector@66.2.0': + resolution: {integrity: sha512-pks1xo8A33IUun9imnZasjsqyocKEYsy+KJHXZjvx+ikD1Lnwfnym7plHdn6wvKry7bjF1H+Pm8mBtawDLaOTA==} + + '@unocss/postcss@66.2.0': + resolution: {integrity: sha512-GBBP/gcDVpu+kjh3PvurhWwB670ei69bxWU40/cxAcgmLbl4EdG5g1FmlI2FaK/e1DhDf/+3v4dFmzy/Tz6pow==} + engines: {node: '>=14'} + peerDependencies: + postcss: ^8.4.21 + + '@unocss/preset-attributify@66.2.0': + resolution: {integrity: sha512-O1ZK5spw/tgcwACEcurw/BR6C594vh1hnAuEWnIoSH+3b2WBCpSORC7uF+UyW4Z5zvGz4asU3G27CGzuzIM31A==} + + '@unocss/preset-icons@66.2.0': + resolution: {integrity: sha512-MpANsJ4hpEfII180i23Tl+Sf0yNVa6lusfQglhjNYFMJwUIobiwMD2zehDLHwcBW31IwbjAXSYW0xs2xzemUkA==} + + '@unocss/preset-mini@66.2.0': + resolution: {integrity: sha512-ESOinBvDeCVKFvS1goI1+sp9tgasO0WSQmwaB+G+GK9uA8LMMMuslOjha3gUUVCskY9V+e5pVmZEJ6YmA72bJQ==} + + '@unocss/preset-tagify@66.2.0': + resolution: {integrity: sha512-x1kqtcbMsLCvM9MpjXt8nsEA17Y3HIXbGpe88iXTPDu1b+cxgprSKbMTQRWvzZgBansCN6XpB+9/QJK1UtvLiA==} + + '@unocss/preset-typography@66.2.0': + resolution: {integrity: sha512-27vlixFSjdF6SHodFhqIiXXmMxk11UXAFML+yHc/6jW01hpUnaFlwns+Jg47bLlVVvjLuVlTkgGr6oRftDA29g==} + + '@unocss/preset-uno@66.2.0': + resolution: {integrity: sha512-8tkDSrjZm4FIm7SxtmD9BEvQ0QxDO4jerV32LfvlhZCHeSypZGNGWWQROJdEpgOOz9axOuWibn/r4klidEAATw==} + + '@unocss/preset-web-fonts@66.2.0': + resolution: {integrity: sha512-6uJRmbooDmZOBw/vKj4vghqguTXGBmJYtHbJjmTZ1dW3322l38w1RVU1hWrFJf/xSFyMv5ir38dSwSS7gygrwQ==} + + '@unocss/preset-wind3@66.2.0': + resolution: {integrity: sha512-87o52P0y3g7Xq9iya/QO7lij6CI6FfM/wu6ivTwLEdio+SSC8m8QcDYFakGprUvFY4GdYk+Hv4WXYu6f3EV+zw==} + + '@unocss/preset-wind4@66.2.0': + resolution: {integrity: sha512-+qllvO142kajxD9EFag1WmiCJOjIxoMTVh1sW30SFXftB6rvVCaA8GbDo/Jnk9gXtmRQ2L9ZnuxPIx8W65pBjA==} + + '@unocss/preset-wind@66.2.0': + resolution: {integrity: sha512-04h1WPRoAli+XQX9g+k4ryFTTcWiFuF0LQX83Py7DNbTYRKFtTaNqLWQrZcORsEV8azo/VztMxygloqxJhUmfg==} + + '@unocss/reset@66.2.0': + resolution: {integrity: sha512-lANXvmU81Cmx5wo4Bwuw9VhOdOFzo/I2L0RCHSmH22m6+VQwG+ho9YONygf6AcN/ookyXX2F7si3CPM6Hkf4Cw==} + + '@unocss/rule-utils@66.2.0': + resolution: {integrity: sha512-T2Gg8WwLeCi7QaOss6EKC5Ypmbls+dqet5sMRsiIE5Mi04j3ndS0+lTwV/x7X6NnN6kCoh0IlwCdBUU4tkJbkQ==} + engines: {node: '>=14'} + + '@unocss/transformer-attributify-jsx@66.2.0': + resolution: {integrity: sha512-qtJJ8KCPRRdsjvTvfz71MMjAD3WAZVPBDjewOtw2OSJDSkrjHf9SiBXlxpo11nNTADscJw6RsVfVaU1drgnQbg==} + + '@unocss/transformer-compile-class@66.2.0': + resolution: {integrity: sha512-fQ4ma/JKgzmQp20IksCCirNNMcwgSE6JS54glwactEdgTTCsedfigAbjaqnX0wGYkqI8Q8mRb06sT8+dCwbjfA==} + + '@unocss/transformer-directives@66.2.0': + resolution: {integrity: sha512-FHhcXJFyzlzIGE9gDo3jSQZ1E25xhWGjwWmOtX7bt2s8QBNg3HjKlYHUrj9TRR0ksV3YENLk0WP3VzOnLBUFdg==} + + '@unocss/transformer-variant-group@66.2.0': + resolution: {integrity: sha512-mgmvDlBpeZ/hblbwE3jGRK8RpoDgrllFARR2+g3tvGw9ZM2BA+RAgMz307s9th1F+PCrDHCG1R+dCLN1b1qyww==} + + '@unocss/vite@66.2.0': + resolution: {integrity: sha512-nWEH0Ym/161nu66T1ANIjmsh5quGOINaunTqUnb41j1U5Y6StW35JmiH3d4Gpk5IsNJ8plBIEaUADxoBIPZZMw==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 + + '@unocss/webpack@66.2.0': + resolution: {integrity: sha512-37OOnU/9YsTI8MLB/z+1+0LJy1KA8d1wYwDePi9DH9RnUGMIE/XbZDPOLPm/ZMxYMOkPcHHEL8kCIuLipxrDkA==} + peerDependencies: + webpack: ^4 || ^5 + + '@vitejs/plugin-vue@6.0.0': + resolution: {integrity: sha512-iAliE72WsdhjzTOp2DtvKThq1VBC4REhwRcaA+zPAAph6I+OQhUXv+Xu2KS7ElxYtb7Zc/3R30Hwv1DxEo7NXQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.0-alpha.18': + resolution: {integrity: sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==} + + '@volar/source-map@2.4.0-alpha.18': + resolution: {integrity: sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==} + + '@volar/typescript@2.4.0-alpha.18': + resolution: {integrity: sha512-sXh5Y8sqGUkgxpMWUGvRXggxYHAVxg0Pa1C42lQZuPDrW6vHJPR0VCK8Sr7WJsAW530HuNQT/ZIskmXtxjybMQ==} + + '@vue/compiler-core@3.4.37': + resolution: {integrity: sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==} + + '@vue/compiler-dom@3.4.37': + resolution: {integrity: sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==} + + '@vue/compiler-sfc@3.4.37': + resolution: {integrity: sha512-vCfetdas40Wk9aK/WWf8XcVESffsbNkBQwS5t13Y/PcfqKfIwJX2gF+82th6dOpnpbptNMlMjAny80li7TaCIg==} + + '@vue/compiler-ssr@3.4.37': + resolution: {integrity: sha512-TyAgYBWrHlFrt4qpdACh8e9Ms6C/AZQ6A6xLJaWrCL8GCX5DxMzxyeFAEMfU/VFr4tylHm+a2NpfJpcd7+20XA==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/devtools-api@6.5.0': + resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} + + '@vue/devtools-api@6.6.3': + resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==} + + '@vue/eslint-config-prettier@7.1.0': + resolution: {integrity: sha512-Pv/lVr0bAzSIHLd9iz0KnvAr4GKyCEl+h52bc4e5yWuDVtLgFwycF7nrbWTAQAS+FU6q1geVd07lc6EWfJiWKQ==} + peerDependencies: + eslint: '>= 7.28.0' + prettier: '>= 2.0.0' + + '@vue/eslint-config-typescript@10.0.0': + resolution: {integrity: sha512-F94cL8ug3FaYXlCfU5/wiGjk1qeadmoBpRGAOBq+qre3Smdupa59dd6ZJrsfRODpsMPyTG7330juMDsUvpZ3Rw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + eslint-plugin-vue: ^8.0.1 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/language-core@2.0.29': + resolution: {integrity: sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/reactivity@3.4.37': + resolution: {integrity: sha512-UmdKXGx0BZ5kkxPqQr3PK3tElz6adTey4307NzZ3whZu19i5VavYal7u2FfOmAzlcDVgE8+X0HZ2LxLb/jgbYw==} + + '@vue/runtime-core@3.4.37': + resolution: {integrity: sha512-MNjrVoLV/sirHZoD7QAilU1Ifs7m/KJv4/84QVbE6nyAZGQNVOa1HGxaOzp9YqCG+GpLt1hNDC4RbH+KtanV7w==} + + '@vue/runtime-dom@3.4.37': + resolution: {integrity: sha512-Mg2EwgGZqtwKrqdL/FKMF2NEaOHuH+Ks9TQn3DHKyX//hQTYOun+7Tqp1eo0P4Ds+SjltZshOSRq6VsU0baaNg==} + + '@vue/server-renderer@3.4.37': + resolution: {integrity: sha512-jZ5FAHDR2KBq2FsRUJW6GKDOAG9lUTX8aBEGq4Vf6B/35I9fPce66BornuwmqmKgfiSlecwuOb6oeoamYMohkg==} + peerDependencies: + vue: 3.4.37 + + '@vue/shared@3.4.37': + resolution: {integrity: sha512-nIh8P2fc3DflG8+5Uw8PT/1i17ccFn0xxN/5oE9RfV5SVnd7G0XEFRwakrnNFE/jlS95fpGXDVG5zDETS26nmg==} + + '@vue/tsconfig@0.5.1': + resolution: {integrity: sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==} + + '@vueuse/core@9.13.0': + resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} + + '@vueuse/metadata@9.13.0': + resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} + + '@vueuse/router@10.11.1': + resolution: {integrity: sha512-tXtDofDwgmADrnLY2mK2LtHKV9CBehaNfT2ar00HZTJ00QxmCOjYp626WdGtQsUi4E64vTScV/s+yKTXhZfl1w==} + peerDependencies: + vue-router: '>=4.0.0-rc.1' + + '@vueuse/shared@10.11.1': + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + + '@vueuse/shared@9.13.0': + resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.7.3: + resolution: {integrity: sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + big.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + + binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + browserslist@4.25.0: + resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001722: + resolution: {integrity: sha512-DCQHBBZtiK6JVkAGw7drvAMK0Q0POD/xZvEmDp6baiMMP6QXXk9HpD6mNYBZWhOPG6LvIDb82ITqtWjhDckHCA==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + compute-scroll-into-view@3.1.0: + resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} + + computeds@0.0.1: + resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + core-js@3.44.0: + resolution: {integrity: sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw==} + + crelt@1.0.5: + resolution: {integrity: sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + date-format-parse@0.2.7: + resolution: {integrity: sha512-/+lyMUKoRogMuTeOVii6lUwjbVlesN9YRYLzZT/g3TEZ3uD9QnpjResujeEqUW+OSNbT7T1+SYdyEkTcRv+KDQ==} + + dayjs@1.11.12: + resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + electron-to-chromium@1.5.166: + resolution: {integrity: sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==} + + emojis-list@3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@5.0.0: + resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-toolkit@1.39.7: + resolution: {integrity: sha512-ek/wWryKouBrZIjkwW2BFf91CWOIMvoy2AE5YYgUrfWsJQM2Su1LoLtrw8uusEpN9RfqLlV/0FVNjT0WMv8Bxw==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@8.6.0: + resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-prettier@4.2.1: + resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + + eslint-plugin-vue@8.7.1: + resolution: {integrity: sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + exsolve@1.0.5: + resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + + fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + + floating-vue@2.0.0-beta.20: + resolution: {integrity: sha512-N68otcpp6WwcYC7zP8GeJqNZVdfvS7tEY88lwmuAHeqRgnfWx1Un8enzLxROyVnBDZ3TwUoUdj5IFg+bUT7JeA==} + peerDependencies: + vue: ^3.2.0 + + floating-vue@5.2.2: + resolution: {integrity: sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg==} + peerDependencies: + '@nuxt/kit': ^3.2.0 + vue: ^3.2.0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + github-markdown-css@5.4.0: + resolution: {integrity: sha512-eJhoFp9fiZ290h0vWrU5MmW0A2eeB81Lv/3ZkdtKrylJvtWi71ezGrxCcw1P2fVr82s3NvBX66SoDCN1pWLadw==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hash-sum@2.0.0: + resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + highlight.js@11.8.0: + resolution: {integrity: sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==} + engines: {node: '>=12.0.0'} + + highlight.js@11.9.0: + resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} + engines: {node: '>=12.0.0'} + + ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + + immutable@4.3.4: + resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==} + + immutable@5.1.2: + resolution: {integrity: sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + linkifyjs@4.1.3: + resolution: {integrity: sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==} + + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + loader-utils@2.0.4: + resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} + engines: {node: '>=8.9.0'} + + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lowlight@3.1.0: + resolution: {integrity: sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + material-colors@1.2.6: + resolution: {integrity: sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + ofetch@1.4.1: + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + orderedmap@2.1.0: + resolution: {integrity: sha512-/pIFexOm6S70EPdznemIz3BQZoJ4VTFrhqzu0ACBqBgeLsLxq8e6Jim63ImIfwW/zAD1AlXpRMlOv3aghmo4dA==} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + + postcss-selector-parser@6.0.11: + resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} + engines: {node: '>=4'} + + postcss@8.4.41: + resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + prosemirror-changeset@2.2.1: + resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.5.2: + resolution: {integrity: sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==} + + prosemirror-dropcursor@1.8.1: + resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} + + prosemirror-gapcursor@1.3.2: + resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + + prosemirror-history@1.4.1: + resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} + + prosemirror-inputrules@1.4.0: + resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} + + prosemirror-keymap@1.2.2: + resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} + + prosemirror-markdown@1.13.0: + resolution: {integrity: sha512-UziddX3ZYSYibgx8042hfGKmukq5Aljp2qoBiJRejD/8MH70siQNz5RB1TrdTPheqLMy4aCe4GYNF10/3lQS5g==} + + prosemirror-menu@1.2.4: + resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} + + prosemirror-model@1.22.3: + resolution: {integrity: sha512-V4XCysitErI+i0rKFILGt/xClnFJaohe/wrrlT2NSZ+zk8ggQfDH4x2wNK7Gm0Hp4CIoWizvXFP7L9KMaCuI0Q==} + + prosemirror-schema-basic@1.2.3: + resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==} + + prosemirror-schema-list@1.4.1: + resolution: {integrity: sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==} + + prosemirror-state@1.4.3: + resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} + + prosemirror-tables@1.4.0: + resolution: {integrity: sha512-fxryZZkQG12fSCNuZDrYx6Xvo2rLYZTbKLRd8rglOPgNJGMKIS8uvTt6gGC38m7UCu/ENnXIP9pEz5uDaPc+cA==} + + prosemirror-trailing-node@2.0.9: + resolution: {integrity: sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.9.0: + resolution: {integrity: sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==} + + prosemirror-view@1.33.9: + resolution: {integrity: sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + reduce-configs@1.1.0: + resolution: {integrity: sha512-DQxy6liNadHfrLahZR7lMdc227NYVaQZhY5FMsxLEjX8X0SCuH+ESHSLCoz2yDZFq1/CLMDOAHdsEHwOEXKtvg==} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + remove-accents@0.4.2: + resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rollup@4.20.0: + resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.3: + resolution: {integrity: sha512-85aZYCxweiD5J8yTEbw+E6A27zSnLPNDL0WfPdw3YYodq7WjnTKo0q4dtyQ2gz23iPT8Q9CUyJtAaUNcTxRf5Q==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + sass-embedded-android-arm64@1.89.2: + resolution: {integrity: sha512-+pq7a7AUpItNyPu61sRlP6G2A8pSPpyazASb+8AK2pVlFayCSPAEgpwpCE9A2/Xj86xJZeMizzKUHxM2CBCUxA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.89.2: + resolution: {integrity: sha512-oHAPTboBHRZlDBhyRB6dvDKh4KvFs+DZibDHXbkSI6dBZxMTT+Yb2ivocHnctVGucKTLQeT7+OM5DjWHyynL/A==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-riscv64@1.89.2: + resolution: {integrity: sha512-HfJJWp/S6XSYvlGAqNdakeEMPOdhBkj2s2lN6SHnON54rahKem+z9pUbCriUJfM65Z90lakdGuOfidY61R9TYg==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.89.2: + resolution: {integrity: sha512-BGPzq53VH5z5HN8de6jfMqJjnRe1E6sfnCWFd4pK+CAiuM7iw5Fx6BQZu3ikfI1l2GY0y6pRXzsVLdp/j4EKEA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.89.2: + resolution: {integrity: sha512-UCm3RL/tzMpG7DsubARsvGUNXC5pgfQvP+RRFJo9XPIi6elopY5B6H4m9dRYDpHA+scjVthdiDwkPYr9+S/KGw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.89.2: + resolution: {integrity: sha512-D9WxtDY5VYtMApXRuhQK9VkPHB8R79NIIR6xxVlN2MIdEid/TZWi1MHNweieETXhWGrKhRKglwnHxxyKdJYMnA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.89.2: + resolution: {integrity: sha512-2N4WW5LLsbtrWUJ7iTpjvhajGIbmDR18ZzYRywHdMLpfdPApuHPMDF5CYzHbS+LLx2UAx7CFKBnj5LLjY6eFgQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-arm@1.89.2: + resolution: {integrity: sha512-leP0t5U4r95dc90o8TCWfxNXwMAsQhpWxTkdtySDpngoqtTy3miMd7EYNYd1znI0FN1CBaUvbdCMbnbPwygDlA==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-arm64@1.89.2: + resolution: {integrity: sha512-nTyuaBX6U1A/cG7WJh0pKD1gY8hbg1m2SnzsyoFG+exQ0lBX/lwTLHq3nyhF+0atv7YYhYKbmfz+sjPP8CZ9lw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.89.2: + resolution: {integrity: sha512-Z6gG2FiVEEdxYHRi2sS5VIYBmp17351bWtOCUZ/thBM66+e70yiN6Eyqjz80DjL8haRUegNQgy9ZJqsLAAmr9g==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-riscv64@1.89.2: + resolution: {integrity: sha512-N6oul+qALO0SwGY8JW7H/Vs0oZIMrRMBM4GqX3AjM/6y8JsJRxkAwnfd0fDyK+aICMFarDqQonQNIx99gdTZqw==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-musl-x64@1.89.2: + resolution: {integrity: sha512-K+FmWcdj/uyP8GiG9foxOCPfb5OAZG0uSVq80DKgVSC0U44AdGjvAvVZkrgFEcZ6cCqlNC2JfYmslB5iqdL7tg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-riscv64@1.89.2: + resolution: {integrity: sha512-g9nTbnD/3yhOaskeqeBQETbtfDQWRgsjHok6bn7DdAuwBsyrR3JlSFyqKc46pn9Xxd9SQQZU8AzM4IR+sY0A0w==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-x64@1.89.2: + resolution: {integrity: sha512-Ax7dKvzncyQzIl4r7012KCMBvJzOz4uwSNoyoM5IV6y5I1f5hEwI25+U4WfuTqdkv42taCMgpjZbh9ERr6JVMQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-win32-arm64@1.89.2: + resolution: {integrity: sha512-j96iJni50ZUsfD6tRxDQE2QSYQ2WrfHxeiyAXf41Kw0V4w5KYR/Sf6rCZQLMTUOHnD16qTMVpQi20LQSqf4WGg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-x64@1.89.2: + resolution: {integrity: sha512-cS2j5ljdkQsb4PaORiClaVYynE9OAPZG/XjbOMxpQmjRIf7UroY4PEIH+Waf+y47PfXFX9SyxhYuw2NIKGbEng==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.89.2: + resolution: {integrity: sha512-Ack2K8rc57kCFcYlf3HXpZEJFNUX8xd8DILldksREmYXQkRHI879yy8q4mRDJgrojkySMZqmmmW1NxrFxMsYaA==} + engines: {node: '>=16.0.0'} + hasBin: true + + sass@1.77.8: + resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + schema-utils@4.3.2: + resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + engines: {node: '>= 10.13.0'} + + scroll-into-view-if-needed@3.1.0: + resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} + + semver@7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sirv@3.0.1: + resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} + engines: {node: '>=18'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + + synckit@0.9.3: + resolution: {integrity: sha512-JJoOEKTfL1urb1mDoEblhD9NhEbWmq9jHEMEnxoC4ujUaZ4itA8vKgwkFAyNClgxplLi9tsUKX+EduK0p/l7sg==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@2.2.2: + resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + engines: {node: '>=6'} + + terser-webpack-plugin@5.3.14: + resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.42.0: + resolution: {integrity: sha512-UYCvU9YQW2f/Vwl+P0GfhxJxbUGLwd+5QrrGgLajzWAtC/23AX0vcise32kkP7Eu0Wu9VlzzHAXkLObgjQfFlQ==} + engines: {node: '>=10'} + hasBin: true + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + + tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + + unconfig@7.3.2: + resolution: {integrity: sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + unocss@66.2.0: + resolution: {integrity: sha512-cAOwKnjcXZPXthg97oiQN0V7G0E44bbSqLoCvO3ukeHdu2/xKnAZgDJudAnKe/LT7HOYYbBHxUUPEtAjy4Ob6Q==} + engines: {node: '>=14'} + peerDependencies: + '@unocss/webpack': 66.2.0 + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 + peerDependenciesMeta: + '@unocss/webpack': + optional: true + vite: + optional: true + + unplugin-icons@22.1.0: + resolution: {integrity: sha512-ect2ZNtk1Zgwb0NVHd0C1IDW/MV+Jk/xaq4t8o6rYdVS3+L660ZdD5kTSQZvsgdwCvquRw+/wYn75hsweRjoIA==} + peerDependencies: + '@svgr/core': '>=7.0.0' + '@svgx/core': ^1.0.1 + '@vue/compiler-sfc': ^3.0.2 || ^2.7.0 + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 + vue-template-compiler: ^2.6.12 + vue-template-es2015-compiler: ^1.9.0 + peerDependenciesMeta: + '@svgr/core': + optional: true + '@svgx/core': + optional: true + '@vue/compiler-sfc': + optional: true + svelte: + optional: true + vue-template-compiler: + optional: true + vue-template-es2015-compiler: + optional: true + + unplugin-utils@0.2.4: + resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} + engines: {node: '>=18.12.0'} + + unplugin@2.3.5: + resolution: {integrity: sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==} + engines: {node: '>=18.12.0'} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + + vite@5.4.0: + resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + + vue-datepicker-next@1.0.3: + resolution: {integrity: sha512-Brqjh896BJGVxP7d6tGDsPMu0SDAB8hAdtG7zWF8VIHJB21dk1VB9KgdajD9Y9uXbg+wHN0vmL7sbMPIyehQVQ==} + peerDependencies: + vue: ^3.0.0 + + vue-demi@0.13.11: + resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-demi@0.14.0: + resolution: {integrity: sha512-gt58r2ogsNQeVoQ3EhoUAvUsH9xviydl0dWJj7dabBC/2L4uBId7ujtCwDRD0JhkGsV1i0CtfLAeyYKBht9oWg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-eslint-parser@8.3.0: + resolution: {integrity: sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + + vue-flow-layout@0.1.1: + resolution: {integrity: sha512-JdgRRUVrN0Y2GosA0M68DEbKlXMqJ7FQgsK8CjQD2vxvNSqAU6PZEpi4cfcTVtfM2GVOMjHo7GKKLbXxOBqDqA==} + peerDependencies: + vue: ^3.4.37 + + vue-loader@17.4.2: + resolution: {integrity: sha512-yTKOA4R/VN4jqjw4y5HrynFL8AK0Z3/Jt7eOJXEitsm0GMRHDBjCfCiuTiLP7OESvsZYo2pATCWhDqxC5ZrM6w==} + peerDependencies: + '@vue/compiler-sfc': '*' + vue: '*' + webpack: ^4.1.0 || ^5.0.0-0 + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + vue: + optional: true + + vue-resize@2.0.0-alpha.1: + resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} + peerDependencies: + vue: ^3.0.0 + + vue-router@4.4.3: + resolution: {integrity: sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==} + peerDependencies: + vue: ^3.2.0 + + vue-tsc@2.0.29: + resolution: {integrity: sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue@3.4.37: + resolution: {integrity: sha512-3vXvNfkKTBsSJ7JP+LyR7GBuwQuckbWvuwAid3xbqK9ppsKt/DUvfqgZ48fgOLEfpy1IacL5f8QhUVl77RaI7A==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + w3c-keyname@2.2.6: + resolution: {integrity: sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==} + + watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + engines: {node: '>=10.13.0'} + + webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + webpack@5.99.9: + resolution: {integrity: sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.3.0 + tinyexec: 1.0.1 + + '@antfu/utils@8.1.1': {} + + '@babel/helper-string-parser@7.24.8': {} + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/parser@7.24.8': + dependencies: + '@babel/types': 7.24.9 + + '@babel/types@7.24.9': + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + + '@bufbuild/protobuf@2.5.2': {} + + '@ckpack/vue-color@1.5.0(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@ctrl/tinycolor': 3.6.1 + material-colors: 1.2.6 + vue: 3.4.37(typescript@5.5.4) + + '@ctrl/tinycolor@3.6.1': {} + + '@emnapi/core@1.4.4': + dependencies: + '@emnapi/wasi-threads': 1.0.3 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.4.4': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.0.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.3.0 + + '@eslint-community/eslint-utils@4.7.0(eslint@8.57.0)': + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.0': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.6.1 + globals: 13.20.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.0': {} + + '@floating-ui/core@0.3.1': {} + + '@floating-ui/core@1.5.1': + dependencies: + '@floating-ui/utils': 0.1.6 + + '@floating-ui/dom@0.1.10': + dependencies: + '@floating-ui/core': 0.3.1 + + '@floating-ui/dom@1.1.1': + dependencies: + '@floating-ui/core': 1.5.1 + + '@floating-ui/utils@0.1.6': {} + + '@halo-dev/api-client@2.18.0(axios@1.7.3)': + dependencies: + axios: 1.7.3 + + '@halo-dev/api-client@2.21.1(axios@1.7.3)': + dependencies: + axios: 1.7.3 + qs: 6.13.0 + + '@halo-dev/components@https://pkg.pr.new/@halo-dev/components@7383(vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4))': + dependencies: + floating-vue: 5.2.2(vue@3.4.37(typescript@5.5.4)) + vue: 3.4.37(typescript@5.5.4) + vue-router: 4.4.3(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - '@nuxt/kit' + + '@halo-dev/console-shared@2.18.0(axios@1.7.3)(vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@halo-dev/api-client': 2.18.0(axios@1.7.3) + vue: 3.4.37(typescript@5.5.4) + vue-router: 4.4.3(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - axios + + '@halo-dev/richtext-editor@2.18.0(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@ckpack/vue-color': 1.5.0(vue@3.4.37(typescript@5.5.4)) + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/extension-blockquote': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-bold': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-bullet-list': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-code': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-code-block': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-code-block-lowlight': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/extension-code-block@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)(highlight.js@11.8.0)(lowlight@3.1.0) + '@tiptap/extension-color': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/extension-text-style@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))) + '@tiptap/extension-document': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-dropcursor': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-hard-break': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-heading': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-highlight': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-history': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-horizontal-rule': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-image': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-italic': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-link': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-list-item': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-list-keymap': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-ordered-list': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-paragraph': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-placeholder': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-strike': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-subscript': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-superscript': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-table': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-table-row': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-task-item': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-task-list': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-text': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-text-align': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-text-style': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/extension-underline': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + '@tiptap/pm': 2.5.9 + '@tiptap/suggestion': 2.11.2(patch_hash=93a4c9b57ce80e49a411cc52e124b5e16118c33cfc70fabc08e0be77f6686a6f)(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/vue-3': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)(vue@3.4.37(typescript@5.5.4)) + floating-vue: 5.2.2(vue@3.4.37(typescript@5.5.4)) + github-markdown-css: 5.4.0 + highlight.js: 11.8.0 + linkifyjs: 4.1.3 + lowlight: 3.1.0 + scroll-into-view-if-needed: 3.1.0 + tippy.js: 6.3.7 + vue: 3.4.37(typescript@5.5.4) + transitivePeerDependencies: + - '@nuxt/kit' + + '@halo-dev/ui-plugin-bundler-kit@2.21.2(@rsbuild/core@1.4.6)(@rsbuild/plugin-vue@1.1.0(@rsbuild/core@1.4.6)(@vue/compiler-sfc@3.4.37)(vue@3.4.37(typescript@5.5.4)))(@vitejs/plugin-vue@6.0.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)))(axios@1.7.3)(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))': + dependencies: + '@halo-dev/api-client': 2.21.1(axios@1.7.3) + '@rsbuild/core': 1.4.6 + '@rsbuild/plugin-vue': 1.1.0(@rsbuild/core@1.4.6)(@vue/compiler-sfc@3.4.37)(vue@3.4.37(typescript@5.5.4)) + '@vitejs/plugin-vue': 6.0.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)) + js-yaml: 4.1.0 + vite: 5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0) + transitivePeerDependencies: + - axios + + '@humanwhocodes/config-array@0.11.14': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@iconify/json@2.2.235': + dependencies: + '@iconify/types': 2.0.0 + pathe: 1.1.2 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.1 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@module-federation/error-codes@0.15.0': {} + + '@module-federation/runtime-core@0.15.0': + dependencies: + '@module-federation/error-codes': 0.15.0 + '@module-federation/sdk': 0.15.0 + + '@module-federation/runtime-tools@0.15.0': + dependencies: + '@module-federation/runtime': 0.15.0 + '@module-federation/webpack-bundler-runtime': 0.15.0 + + '@module-federation/runtime@0.15.0': + dependencies: + '@module-federation/error-codes': 0.15.0 + '@module-federation/runtime-core': 0.15.0 + '@module-federation/sdk': 0.15.0 + + '@module-federation/sdk@0.15.0': {} + + '@module-federation/webpack-bundler-runtime@0.15.0': + dependencies: + '@module-federation/runtime': 0.15.0 + '@module-federation/sdk': 0.15.0 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.4.4 + '@emnapi/runtime': 1.4.4 + '@tybys/wasm-util': 0.10.0 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + + '@pkgr/core@0.1.1': {} + + '@polka/url@1.0.0-next.25': {} + + '@popperjs/core@2.11.6': {} + + '@quansync/fs@0.1.3': + dependencies: + quansync: 0.2.10 + + '@remirror/core-constants@2.0.2': {} + + '@rolldown/pluginutils@1.0.0-beta.19': {} + + '@rollup/rollup-android-arm-eabi@4.20.0': + optional: true + + '@rollup/rollup-android-arm64@4.20.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.20.0': + optional: true + + '@rollup/rollup-darwin-x64@4.20.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.20.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.20.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.20.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.20.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.20.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.20.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.20.0': + optional: true + + '@rsbuild/core@1.4.6': + dependencies: + '@rspack/core': 1.4.6(@swc/helpers@0.5.17) + '@rspack/lite-tapable': 1.0.1 + '@swc/helpers': 0.5.17 + core-js: 3.44.0 + jiti: 2.4.2 + + '@rsbuild/plugin-sass@1.3.3(@rsbuild/core@1.4.6)': + dependencies: + '@rsbuild/core': 1.4.6 + deepmerge: 4.3.1 + loader-utils: 2.0.4 + postcss: 8.5.6 + reduce-configs: 1.1.0 + sass-embedded: 1.89.2 + + '@rsbuild/plugin-vue@1.1.0(@rsbuild/core@1.4.6)(@vue/compiler-sfc@3.4.37)(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@rsbuild/core': 1.4.6 + vue-loader: 17.4.2(@vue/compiler-sfc@3.4.37)(vue@3.4.37(typescript@5.5.4))(webpack@5.99.9) + webpack: 5.99.9 + transitivePeerDependencies: + - '@swc/core' + - '@vue/compiler-sfc' + - esbuild + - uglify-js + - vue + - webpack-cli + + '@rspack/binding-darwin-arm64@1.4.6': + optional: true + + '@rspack/binding-darwin-x64@1.4.6': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.4.6': + optional: true + + '@rspack/binding-linux-arm64-musl@1.4.6': + optional: true + + '@rspack/binding-linux-x64-gnu@1.4.6': + optional: true + + '@rspack/binding-linux-x64-musl@1.4.6': + optional: true + + '@rspack/binding-wasm32-wasi@1.4.6': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@rspack/binding-win32-arm64-msvc@1.4.6': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.4.6': + optional: true + + '@rspack/binding-win32-x64-msvc@1.4.6': + optional: true + + '@rspack/binding@1.4.6': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.4.6 + '@rspack/binding-darwin-x64': 1.4.6 + '@rspack/binding-linux-arm64-gnu': 1.4.6 + '@rspack/binding-linux-arm64-musl': 1.4.6 + '@rspack/binding-linux-x64-gnu': 1.4.6 + '@rspack/binding-linux-x64-musl': 1.4.6 + '@rspack/binding-wasm32-wasi': 1.4.6 + '@rspack/binding-win32-arm64-msvc': 1.4.6 + '@rspack/binding-win32-ia32-msvc': 1.4.6 + '@rspack/binding-win32-x64-msvc': 1.4.6 + + '@rspack/core@1.4.6(@swc/helpers@0.5.17)': + dependencies: + '@module-federation/runtime-tools': 0.15.0 + '@rspack/binding': 1.4.6 + '@rspack/lite-tapable': 1.0.1 + optionalDependencies: + '@swc/helpers': 0.5.17 + + '@rspack/lite-tapable@1.0.1': {} + + '@rushstack/eslint-patch@1.10.4': {} + + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + + '@tanstack/match-sorter-utils@8.7.6': + dependencies: + remove-accents: 0.4.2 + + '@tanstack/query-core@4.36.1': {} + + '@tanstack/vue-query@4.37.1(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@tanstack/match-sorter-utils': 8.7.6 + '@tanstack/query-core': 4.36.1 + '@vue/devtools-api': 6.5.0 + vue: 3.4.37(typescript@5.5.4) + vue-demi: 0.13.11(vue@3.4.37(typescript@5.5.4)) + + '@tiptap/core@2.5.9(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-blockquote@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-bold@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-bubble-menu@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + tippy.js: 6.3.7 + + '@tiptap/extension-bullet-list@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-code-block-lowlight@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/extension-code-block@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)(highlight.js@11.8.0)(lowlight@3.1.0)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/extension-code-block': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + highlight.js: 11.8.0 + lowlight: 3.1.0 + + '@tiptap/extension-code-block@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-code@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-color@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/extension-text-style@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/extension-text-style': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9)) + + '@tiptap/extension-document@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-dropcursor@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-floating-menu@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + tippy.js: 6.3.7 + + '@tiptap/extension-hard-break@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-heading@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-highlight@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-history@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-horizontal-rule@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-image@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-italic@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-link@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + linkifyjs: 4.1.3 + + '@tiptap/extension-list-item@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-list-keymap@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-ordered-list@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-paragraph@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-placeholder@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-strike@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-subscript@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-superscript@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-table-row@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-table@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-task-item@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/extension-task-list@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-text-align@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-text-style@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-text@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/extension-underline@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + + '@tiptap/pm@2.5.9': + dependencies: + prosemirror-changeset: 2.2.1 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.5.2 + prosemirror-dropcursor: 1.8.1 + prosemirror-gapcursor: 1.3.2 + prosemirror-history: 1.4.1 + prosemirror-inputrules: 1.4.0 + prosemirror-keymap: 1.2.2 + prosemirror-markdown: 1.13.0 + prosemirror-menu: 1.2.4 + prosemirror-model: 1.22.3 + prosemirror-schema-basic: 1.2.3 + prosemirror-schema-list: 1.4.1 + prosemirror-state: 1.4.3 + prosemirror-tables: 1.4.0 + prosemirror-trailing-node: 2.0.9(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9) + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.9 + + '@tiptap/suggestion@2.11.2(patch_hash=93a4c9b57ce80e49a411cc52e124b5e16118c33cfc70fabc08e0be77f6686a6f)(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + + '@tiptap/vue-3@2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9)(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@tiptap/core': 2.5.9(@tiptap/pm@2.5.9) + '@tiptap/extension-bubble-menu': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/extension-floating-menu': 2.5.9(@tiptap/core@2.5.9(@tiptap/pm@2.5.9))(@tiptap/pm@2.5.9) + '@tiptap/pm': 2.5.9 + vue: 3.4.37(typescript@5.5.4) + + '@tsconfig/node20@20.1.4': {} + + '@tybys/wasm-util@0.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.5': {} + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.3': + dependencies: + '@types/unist': 2.0.6 + + '@types/json-schema@7.0.11': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@20.14.15': + dependencies: + undici-types: 5.26.5 + + '@types/semver@7.3.13': {} + + '@types/unist@2.0.6': {} + + '@types/web-bluetooth@0.0.16': {} + + '@typescript-eslint/eslint-plugin@5.54.0(@typescript-eslint/parser@5.54.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/parser': 5.54.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/type-utils': 5.54.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 5.54.0(eslint@8.57.0)(typescript@5.5.4) + debug: 4.3.4 + eslint: 8.57.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + regexpp: 3.2.0 + semver: 7.3.8 + tsutils: 3.21.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@5.54.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/typescript-estree': 5.54.0(typescript@5.5.4) + debug: 4.3.4 + eslint: 8.57.0 + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.34.0(typescript@5.5.4)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.34.0(typescript@5.5.4) + '@typescript-eslint/types': 8.34.0 + debug: 4.3.6 + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@5.54.0': + dependencies: + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/visitor-keys': 5.54.0 + + '@typescript-eslint/scope-manager@8.34.0': + dependencies: + '@typescript-eslint/types': 8.34.0 + '@typescript-eslint/visitor-keys': 8.34.0 + + '@typescript-eslint/tsconfig-utils@8.34.0(typescript@5.5.4)': + dependencies: + typescript: 5.5.4 + + '@typescript-eslint/type-utils@5.54.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/typescript-estree': 5.54.0(typescript@5.5.4) + '@typescript-eslint/utils': 5.54.0(eslint@8.57.0)(typescript@5.5.4) + debug: 4.3.4 + eslint: 8.57.0 + tsutils: 3.21.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@5.54.0': {} + + '@typescript-eslint/types@8.34.0': {} + + '@typescript-eslint/typescript-estree@5.54.0(typescript@5.5.4)': + dependencies: + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/visitor-keys': 5.54.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.34.0(typescript@5.5.4)': + dependencies: + '@typescript-eslint/project-service': 8.34.0(typescript@5.5.4) + '@typescript-eslint/tsconfig-utils': 8.34.0(typescript@5.5.4) + '@typescript-eslint/types': 8.34.0 + '@typescript-eslint/visitor-keys': 8.34.0 + debug: 4.3.6 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 2.1.0(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@5.54.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/typescript-estree': 5.54.0(typescript@5.5.4) + eslint: 8.57.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@8.57.0) + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@8.34.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.34.0 + '@typescript-eslint/types': 8.34.0 + '@typescript-eslint/typescript-estree': 8.34.0(typescript@5.5.4) + eslint: 8.57.0 + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@5.54.0': + dependencies: + '@typescript-eslint/types': 5.54.0 + eslint-visitor-keys: 3.3.0 + + '@typescript-eslint/visitor-keys@8.34.0': + dependencies: + '@typescript-eslint/types': 8.34.0 + eslint-visitor-keys: 4.2.1 + + '@ungap/structured-clone@1.2.0': {} + + '@unocss/astro@66.2.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/reset': 66.2.0 + '@unocss/vite': 66.2.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)) + optionalDependencies: + vite: 5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0) + transitivePeerDependencies: + - vue + + '@unocss/cli@66.2.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@unocss/config': 66.2.0 + '@unocss/core': 66.2.0 + '@unocss/preset-uno': 66.2.0 + cac: 6.7.14 + chokidar: 3.6.0 + colorette: 2.0.20 + consola: 3.4.2 + magic-string: 0.30.17 + pathe: 2.0.3 + perfect-debounce: 1.0.0 + tinyglobby: 0.2.14 + unplugin-utils: 0.2.4 + + '@unocss/config@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + unconfig: 7.3.2 + + '@unocss/core@66.2.0': {} + + '@unocss/eslint-config@66.2.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@unocss/eslint-plugin': 66.2.0(eslint@8.57.0)(typescript@5.5.4) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@unocss/eslint-plugin@66.2.0(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/utils': 8.34.0(eslint@8.57.0)(typescript@5.5.4) + '@unocss/config': 66.2.0 + '@unocss/core': 66.2.0 + '@unocss/rule-utils': 66.2.0 + magic-string: 0.30.17 + synckit: 0.9.3 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@unocss/extractor-arbitrary-variants@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + + '@unocss/inspector@66.2.0(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/rule-utils': 66.2.0 + colorette: 2.0.20 + gzip-size: 6.0.0 + sirv: 3.0.1 + vue-flow-layout: 0.1.1(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - vue + + '@unocss/postcss@66.2.0(postcss@8.5.6)': + dependencies: + '@unocss/config': 66.2.0 + '@unocss/core': 66.2.0 + '@unocss/rule-utils': 66.2.0 + css-tree: 3.1.0 + postcss: 8.5.6 + tinyglobby: 0.2.14 + + '@unocss/preset-attributify@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + + '@unocss/preset-icons@66.2.0': + dependencies: + '@iconify/utils': 2.3.0 + '@unocss/core': 66.2.0 + ofetch: 1.4.1 + transitivePeerDependencies: + - supports-color + + '@unocss/preset-mini@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/extractor-arbitrary-variants': 66.2.0 + '@unocss/rule-utils': 66.2.0 + + '@unocss/preset-tagify@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + + '@unocss/preset-typography@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/preset-mini': 66.2.0 + '@unocss/rule-utils': 66.2.0 + + '@unocss/preset-uno@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/preset-wind3': 66.2.0 + + '@unocss/preset-web-fonts@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + ofetch: 1.4.1 + + '@unocss/preset-wind3@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/preset-mini': 66.2.0 + '@unocss/rule-utils': 66.2.0 + + '@unocss/preset-wind4@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/extractor-arbitrary-variants': 66.2.0 + '@unocss/rule-utils': 66.2.0 + + '@unocss/preset-wind@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/preset-wind3': 66.2.0 + + '@unocss/reset@66.2.0': {} + + '@unocss/rule-utils@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + magic-string: 0.30.17 + + '@unocss/transformer-attributify-jsx@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + + '@unocss/transformer-compile-class@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + + '@unocss/transformer-directives@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + '@unocss/rule-utils': 66.2.0 + css-tree: 3.1.0 + + '@unocss/transformer-variant-group@66.2.0': + dependencies: + '@unocss/core': 66.2.0 + + '@unocss/vite@66.2.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@unocss/config': 66.2.0 + '@unocss/core': 66.2.0 + '@unocss/inspector': 66.2.0(vue@3.4.37(typescript@5.5.4)) + chokidar: 3.6.0 + magic-string: 0.30.17 + pathe: 2.0.3 + tinyglobby: 0.2.14 + unplugin-utils: 0.2.4 + vite: 5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0) + transitivePeerDependencies: + - vue + + '@unocss/webpack@66.2.0(webpack@5.99.9)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@unocss/config': 66.2.0 + '@unocss/core': 66.2.0 + chokidar: 3.6.0 + magic-string: 0.30.17 + pathe: 2.0.3 + tinyglobby: 0.2.14 + unplugin: 2.3.5 + unplugin-utils: 0.2.4 + webpack: 5.99.9 + webpack-sources: 3.2.3 + + '@vitejs/plugin-vue@6.0.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@rolldown/pluginutils': 1.0.0-beta.19 + vite: 5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0) + vue: 3.4.37(typescript@5.5.4) + + '@volar/language-core@2.4.0-alpha.18': + dependencies: + '@volar/source-map': 2.4.0-alpha.18 + + '@volar/source-map@2.4.0-alpha.18': {} + + '@volar/typescript@2.4.0-alpha.18': + dependencies: + '@volar/language-core': 2.4.0-alpha.18 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 + + '@vue/compiler-core@3.4.37': + dependencies: + '@babel/parser': 7.24.8 + '@vue/shared': 3.4.37 + entities: 5.0.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + + '@vue/compiler-dom@3.4.37': + dependencies: + '@vue/compiler-core': 3.4.37 + '@vue/shared': 3.4.37 + + '@vue/compiler-sfc@3.4.37': + dependencies: + '@babel/parser': 7.24.8 + '@vue/compiler-core': 3.4.37 + '@vue/compiler-dom': 3.4.37 + '@vue/compiler-ssr': 3.4.37 + '@vue/shared': 3.4.37 + estree-walker: 2.0.2 + magic-string: 0.30.10 + postcss: 8.4.41 + source-map-js: 1.2.0 + + '@vue/compiler-ssr@3.4.37': + dependencies: + '@vue/compiler-dom': 3.4.37 + '@vue/shared': 3.4.37 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/devtools-api@6.5.0': {} + + '@vue/devtools-api@6.6.3': {} + + '@vue/eslint-config-prettier@7.1.0(eslint@8.57.0)(prettier@2.8.8)': + dependencies: + eslint: 8.57.0 + eslint-config-prettier: 8.6.0(eslint@8.57.0) + eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.6.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8) + prettier: 2.8.8 + + '@vue/eslint-config-typescript@10.0.0(eslint-plugin-vue@8.7.1(eslint@8.57.0))(eslint@8.57.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/eslint-plugin': 5.54.0(@typescript-eslint/parser@5.54.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/parser': 5.54.0(eslint@8.57.0)(typescript@5.5.4) + eslint: 8.57.0 + eslint-plugin-vue: 8.7.1(eslint@8.57.0) + vue-eslint-parser: 8.3.0(eslint@8.57.0) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@vue/language-core@2.0.29(typescript@5.5.4)': + dependencies: + '@volar/language-core': 2.4.0-alpha.18 + '@vue/compiler-dom': 3.4.37 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.4.37 + computeds: 0.0.1 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.5.4 + + '@vue/reactivity@3.4.37': + dependencies: + '@vue/shared': 3.4.37 + + '@vue/runtime-core@3.4.37': + dependencies: + '@vue/reactivity': 3.4.37 + '@vue/shared': 3.4.37 + + '@vue/runtime-dom@3.4.37': + dependencies: + '@vue/reactivity': 3.4.37 + '@vue/runtime-core': 3.4.37 + '@vue/shared': 3.4.37 + csstype: 3.1.3 + + '@vue/server-renderer@3.4.37(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@vue/compiler-ssr': 3.4.37 + '@vue/shared': 3.4.37 + vue: 3.4.37(typescript@5.5.4) + + '@vue/shared@3.4.37': {} + + '@vue/tsconfig@0.5.1': {} + + '@vueuse/core@9.13.0(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.13.0 + '@vueuse/shared': 9.13.0(vue@3.4.37(typescript@5.5.4)) + vue-demi: 0.13.11(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@9.13.0': {} + + '@vueuse/router@10.11.1(vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)))(vue@3.4.37(typescript@5.5.4))': + dependencies: + '@vueuse/shared': 10.11.1(vue@3.4.37(typescript@5.5.4)) + vue-demi: 0.14.10(vue@3.4.37(typescript@5.5.4)) + vue-router: 4.4.3(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/shared@10.11.1(vue@3.4.37(typescript@5.5.4))': + dependencies: + vue-demi: 0.14.10(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/shared@9.13.0(vue@3.4.37(typescript@5.5.4))': + dependencies: + vue-demi: 0.14.0(vue@3.4.37(typescript@5.5.4)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + acorn-jsx@5.3.2(acorn@8.12.1): + dependencies: + acorn: 8.12.1 + + acorn@8.12.1: {} + + acorn@8.15.0: {} + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@5.1.0(ajv@8.17.1): + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + asynckit@0.4.0: {} + + axios@1.7.3: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + big.js@5.2.2: {} + + binary-extensions@2.2.0: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.2: + dependencies: + fill-range: 7.0.1 + + browserslist@4.25.0: + dependencies: + caniuse-lite: 1.0.30001722 + electron-to-chromium: 1.5.166 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.0) + + buffer-builder@0.2.0: {} + + buffer-from@1.1.2: {} + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001722: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chrome-trace-event@1.0.4: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + colorjs.io@0.5.2: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@2.20.3: {} + + compute-scroll-into-view@3.1.0: {} + + computeds@0.0.1: {} + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + confbox@0.2.2: {} + + consola@3.4.2: {} + + core-js@3.44.0: {} + + crelt@1.0.5: {} + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.0 + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + date-format-parse@0.2.7: {} + + dayjs@1.11.12: {} + + de-indent@1.0.2: {} + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + debug@4.3.6: + dependencies: + ms: 2.1.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + destr@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.2: {} + + electron-to-chromium@1.5.166: {} + + emojis-list@3.0.0: {} + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.2 + + entities@4.5.0: {} + + entities@5.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-toolkit@1.39.7: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@8.6.0(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + + eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.6.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.8.8): + dependencies: + eslint: 8.57.0 + prettier: 2.8.8 + prettier-linter-helpers: 1.0.0 + optionalDependencies: + eslint-config-prettier: 8.6.0(eslint@8.57.0) + + eslint-plugin-vue@8.7.1(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + eslint-utils: 3.0.0(eslint@8.57.0) + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.0.11 + semver: 7.3.8 + vue-eslint-parser: 8.3.0(eslint@8.57.0) + transitivePeerDependencies: + - supports-color + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-utils@3.0.0(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 2.1.0 + + eslint-visitor-keys@2.1.0: {} + + eslint-visitor-keys@3.3.0: {} + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@8.57.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.11.0 + '@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.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + 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.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.20.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + 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.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.4.1: + dependencies: + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 3.3.0 + + espree@9.6.1: + dependencies: + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 3.4.3 + + esquery@1.5.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + events@3.3.0: {} + + exsolve@1.0.5: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.2.0: {} + + fast-glob@3.2.12: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fastq@1.15.0: + dependencies: + reusify: 1.0.4 + + fdir@6.4.6(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.0.4 + + fill-range@7.0.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.0.4: + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + + flatted@3.2.7: {} + + floating-vue@2.0.0-beta.20(vue@3.4.37(typescript@5.5.4)): + dependencies: + '@floating-ui/dom': 0.1.10 + vue: 3.4.37(typescript@5.5.4) + vue-resize: 2.0.0-alpha.1(vue@3.4.37(typescript@5.5.4)) + + floating-vue@5.2.2(vue@3.4.37(typescript@5.5.4)): + dependencies: + '@floating-ui/dom': 1.1.1 + vue: 3.4.37(typescript@5.5.4) + vue-resize: 2.0.0-alpha.1(vue@3.4.37(typescript@5.5.4)) + + follow-redirects@1.15.6: {} + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + github-markdown-css@5.4.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@13.20.0: + dependencies: + type-fest: 0.20.2 + + globals@15.15.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + grapheme-splitter@1.0.4: {} + + graphemer@1.4.0: {} + + gzip-size@6.0.0: + dependencies: + duplexer: 0.1.2 + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + hash-sum@2.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + highlight.js@11.8.0: {} + + highlight.js@11.9.0: {} + + ignore@5.2.4: {} + + immutable@4.3.4: + optional: true + + immutable@5.1.2: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.2.0 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + isexe@2.0.0: {} + + jest-worker@27.5.1: + dependencies: + '@types/node': 20.14.15 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jiti@2.4.2: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + kolorist@1.8.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + linkifyjs@4.1.3: {} + + loader-runner@4.3.0: {} + + loader-utils@2.0.4: + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 2.2.3 + + local-pkg@1.1.1: + dependencies: + mlly: 1.7.4 + pkg-types: 2.1.0 + quansync: 0.2.10 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + lowlight@3.1.0: + dependencies: + '@types/hast': 3.0.3 + devlop: 1.1.0 + highlight.js: 11.9.0 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.30.10: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + material-colors@1.2.6: {} + + math-intrinsics@1.1.0: {} + + mdn-data@2.12.2: {} + + mdurl@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.5: + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + mlly@1.7.4: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.5.4 + + mrmime@2.0.0: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.11: {} + + nanoid@3.3.7: {} + + natural-compare-lite@1.4.0: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + node-fetch-native@1.6.4: {} + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-inspect@1.13.4: {} + + ofetch@1.4.1: + dependencies: + destr: 2.0.3 + node-fetch-native: 1.6.4 + ufo: 1.5.4 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + orderedmap@2.1.0: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-manager-detector@1.3.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-type@4.0.0: {} + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + perfect-debounce@1.0.0: {} + + picocolors@1.0.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + pkg-types@2.1.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.5 + pathe: 2.0.3 + + postcss-selector-parser@6.0.11: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.4.41: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.2.0 + + prettier@2.8.8: {} + + prosemirror-changeset@2.2.1: + dependencies: + prosemirror-transform: 1.9.0 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.3 + + prosemirror-commands@1.5.2: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + + prosemirror-dropcursor@1.8.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.9 + + prosemirror-gapcursor@1.3.2: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-view: 1.33.9 + + prosemirror-history@1.4.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.9 + rope-sequence: 1.3.3 + + prosemirror-inputrules@1.4.0: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + + prosemirror-keymap@1.2.2: + dependencies: + prosemirror-state: 1.4.3 + w3c-keyname: 2.2.6 + + prosemirror-markdown@1.13.0: + dependencies: + markdown-it: 14.1.0 + prosemirror-model: 1.22.3 + + prosemirror-menu@1.2.4: + dependencies: + crelt: 1.0.5 + prosemirror-commands: 1.5.2 + prosemirror-history: 1.4.1 + prosemirror-state: 1.4.3 + + prosemirror-model@1.22.3: + dependencies: + orderedmap: 2.1.0 + + prosemirror-schema-basic@1.2.3: + dependencies: + prosemirror-model: 1.22.3 + + prosemirror-schema-list@1.4.1: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + + prosemirror-state@1.4.3: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.9 + + prosemirror-tables@1.4.0: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.9 + + prosemirror-trailing-node@2.0.9(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)(prosemirror-view@1.33.9): + dependencies: + '@remirror/core-constants': 2.0.2 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-view: 1.33.9 + + prosemirror-transform@1.9.0: + dependencies: + prosemirror-model: 1.22.3 + + prosemirror-view@1.33.9: + dependencies: + prosemirror-model: 1.22.3 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + + proxy-from-env@1.1.0: {} + + punycode.js@2.3.1: {} + + punycode@2.3.0: {} + + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + + quansync@0.2.10: {} + + queue-microtask@1.2.3: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + reduce-configs@1.1.0: {} + + regexpp@3.2.0: {} + + remove-accents@0.4.2: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rollup@4.20.0: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.20.0 + '@rollup/rollup-android-arm64': 4.20.0 + '@rollup/rollup-darwin-arm64': 4.20.0 + '@rollup/rollup-darwin-x64': 4.20.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.20.0 + '@rollup/rollup-linux-arm-musleabihf': 4.20.0 + '@rollup/rollup-linux-arm64-gnu': 4.20.0 + '@rollup/rollup-linux-arm64-musl': 4.20.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0 + '@rollup/rollup-linux-riscv64-gnu': 4.20.0 + '@rollup/rollup-linux-s390x-gnu': 4.20.0 + '@rollup/rollup-linux-x64-gnu': 4.20.0 + '@rollup/rollup-linux-x64-musl': 4.20.0 + '@rollup/rollup-win32-arm64-msvc': 4.20.0 + '@rollup/rollup-win32-ia32-msvc': 4.20.0 + '@rollup/rollup-win32-x64-msvc': 4.20.0 + fsevents: 2.3.3 + + rope-sequence@1.3.3: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@7.8.2: + dependencies: + tslib: 2.6.3 + + safe-buffer@5.2.1: {} + + sass-embedded-android-arm64@1.89.2: + optional: true + + sass-embedded-android-arm@1.89.2: + optional: true + + sass-embedded-android-riscv64@1.89.2: + optional: true + + sass-embedded-android-x64@1.89.2: + optional: true + + sass-embedded-darwin-arm64@1.89.2: + optional: true + + sass-embedded-darwin-x64@1.89.2: + optional: true + + sass-embedded-linux-arm64@1.89.2: + optional: true + + sass-embedded-linux-arm@1.89.2: + optional: true + + sass-embedded-linux-musl-arm64@1.89.2: + optional: true + + sass-embedded-linux-musl-arm@1.89.2: + optional: true + + sass-embedded-linux-musl-riscv64@1.89.2: + optional: true + + sass-embedded-linux-musl-x64@1.89.2: + optional: true + + sass-embedded-linux-riscv64@1.89.2: + optional: true + + sass-embedded-linux-x64@1.89.2: + optional: true + + sass-embedded-win32-arm64@1.89.2: + optional: true + + sass-embedded-win32-x64@1.89.2: + optional: true + + sass-embedded@1.89.2: + dependencies: + '@bufbuild/protobuf': 2.5.2 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.1.2 + rxjs: 7.8.2 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.89.2 + sass-embedded-android-arm64: 1.89.2 + sass-embedded-android-riscv64: 1.89.2 + sass-embedded-android-x64: 1.89.2 + sass-embedded-darwin-arm64: 1.89.2 + sass-embedded-darwin-x64: 1.89.2 + sass-embedded-linux-arm: 1.89.2 + sass-embedded-linux-arm64: 1.89.2 + sass-embedded-linux-musl-arm: 1.89.2 + sass-embedded-linux-musl-arm64: 1.89.2 + sass-embedded-linux-musl-riscv64: 1.89.2 + sass-embedded-linux-musl-x64: 1.89.2 + sass-embedded-linux-riscv64: 1.89.2 + sass-embedded-linux-x64: 1.89.2 + sass-embedded-win32-arm64: 1.89.2 + sass-embedded-win32-x64: 1.89.2 + + sass@1.77.8: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.4 + source-map-js: 1.2.1 + optional: true + + schema-utils@4.3.2: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) + + scroll-into-view-if-needed@3.1.0: + dependencies: + compute-scroll-into-view: 3.1.0 + + semver@7.3.8: + dependencies: + lru-cache: 6.0.0 + + semver@7.6.3: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sirv@3.0.1: + dependencies: + '@polka/url': 1.0.0-next.25 + mrmime: 2.0.0 + totalist: 3.0.1 + + slash@3.0.0: {} + + source-map-js@1.2.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.1.3 + + sync-message-port@1.1.3: {} + + synckit@0.9.3: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.3 + + tapable@2.2.2: {} + + terser-webpack-plugin@5.3.14(webpack@5.99.9): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 4.3.2 + serialize-javascript: 6.0.2 + terser: 5.42.0 + webpack: 5.99.9 + + terser@5.42.0: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + text-table@0.2.0: {} + + tinyexec@1.0.1: {} + + tinyglobby@0.2.14: + dependencies: + fdir: 6.4.6(picomatch@4.0.2) + picomatch: 4.0.2 + + tippy.js@6.3.7: + dependencies: + '@popperjs/core': 2.11.6 + + to-fast-properties@2.0.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + totalist@3.0.1: {} + + ts-api-utils@2.1.0(typescript@5.5.4): + dependencies: + typescript: 5.5.4 + + tslib@1.14.1: {} + + tslib@2.6.3: {} + + tslib@2.8.1: {} + + tsutils@3.21.0(typescript@5.5.4): + dependencies: + tslib: 1.14.1 + typescript: 5.5.4 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + typescript@5.5.4: {} + + uc.micro@2.1.0: {} + + ufo@1.5.4: {} + + unconfig@7.3.2: + dependencies: + '@quansync/fs': 0.1.3 + defu: 6.1.4 + jiti: 2.4.2 + quansync: 0.2.10 + + undici-types@5.26.5: {} + + unocss@66.2.0(@unocss/webpack@66.2.0(webpack@5.99.9))(postcss@8.5.6)(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)): + dependencies: + '@unocss/astro': 66.2.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)) + '@unocss/cli': 66.2.0 + '@unocss/core': 66.2.0 + '@unocss/postcss': 66.2.0(postcss@8.5.6) + '@unocss/preset-attributify': 66.2.0 + '@unocss/preset-icons': 66.2.0 + '@unocss/preset-mini': 66.2.0 + '@unocss/preset-tagify': 66.2.0 + '@unocss/preset-typography': 66.2.0 + '@unocss/preset-uno': 66.2.0 + '@unocss/preset-web-fonts': 66.2.0 + '@unocss/preset-wind': 66.2.0 + '@unocss/preset-wind3': 66.2.0 + '@unocss/preset-wind4': 66.2.0 + '@unocss/transformer-attributify-jsx': 66.2.0 + '@unocss/transformer-compile-class': 66.2.0 + '@unocss/transformer-directives': 66.2.0 + '@unocss/transformer-variant-group': 66.2.0 + '@unocss/vite': 66.2.0(vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0))(vue@3.4.37(typescript@5.5.4)) + optionalDependencies: + '@unocss/webpack': 66.2.0(webpack@5.99.9) + vite: 5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0) + transitivePeerDependencies: + - postcss + - supports-color + - vue + + unplugin-icons@22.1.0(@vue/compiler-sfc@3.4.37): + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/utils': 2.3.0 + debug: 4.4.1 + local-pkg: 1.1.1 + unplugin: 2.3.5 + optionalDependencies: + '@vue/compiler-sfc': 3.4.37 + transitivePeerDependencies: + - supports-color + + unplugin-utils@0.2.4: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.2 + + unplugin@2.3.5: + dependencies: + acorn: 8.15.0 + picomatch: 4.0.2 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.1.3(browserslist@4.25.0): + dependencies: + browserslist: 4.25.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.0 + + util-deprecate@1.0.2: {} + + varint@6.0.0: {} + + vite@5.4.0(@types/node@20.14.15)(sass-embedded@1.89.2)(sass@1.77.8)(terser@5.42.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.20.0 + optionalDependencies: + '@types/node': 20.14.15 + fsevents: 2.3.3 + sass: 1.77.8 + sass-embedded: 1.89.2 + terser: 5.42.0 + + vscode-uri@3.0.8: {} + + vue-datepicker-next@1.0.3(vue@3.4.37(typescript@5.5.4)): + dependencies: + date-format-parse: 0.2.7 + vue: 3.4.37(typescript@5.5.4) + + vue-demi@0.13.11(vue@3.4.37(typescript@5.5.4)): + dependencies: + vue: 3.4.37(typescript@5.5.4) + + vue-demi@0.14.0(vue@3.4.37(typescript@5.5.4)): + dependencies: + vue: 3.4.37(typescript@5.5.4) + + vue-demi@0.14.10(vue@3.4.37(typescript@5.5.4)): + dependencies: + vue: 3.4.37(typescript@5.5.4) + + vue-eslint-parser@8.3.0(eslint@8.57.0): + dependencies: + debug: 4.3.4 + eslint: 8.57.0 + eslint-scope: 7.1.1 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + + vue-flow-layout@0.1.1(vue@3.4.37(typescript@5.5.4)): + dependencies: + vue: 3.4.37(typescript@5.5.4) + + vue-loader@17.4.2(@vue/compiler-sfc@3.4.37)(vue@3.4.37(typescript@5.5.4))(webpack@5.99.9): + dependencies: + chalk: 4.1.2 + hash-sum: 2.0.0 + watchpack: 2.4.4 + webpack: 5.99.9 + optionalDependencies: + '@vue/compiler-sfc': 3.4.37 + vue: 3.4.37(typescript@5.5.4) + + vue-resize@2.0.0-alpha.1(vue@3.4.37(typescript@5.5.4)): + dependencies: + vue: 3.4.37(typescript@5.5.4) + + vue-router@4.4.3(vue@3.4.37(typescript@5.5.4)): + dependencies: + '@vue/devtools-api': 6.6.3 + vue: 3.4.37(typescript@5.5.4) + + vue-tsc@2.0.29(typescript@5.5.4): + dependencies: + '@volar/typescript': 2.4.0-alpha.18 + '@vue/language-core': 2.0.29(typescript@5.5.4) + semver: 7.6.3 + typescript: 5.5.4 + + vue@3.4.37(typescript@5.5.4): + dependencies: + '@vue/compiler-dom': 3.4.37 + '@vue/compiler-sfc': 3.4.37 + '@vue/runtime-dom': 3.4.37 + '@vue/server-renderer': 3.4.37(vue@3.4.37(typescript@5.5.4)) + '@vue/shared': 3.4.37 + optionalDependencies: + typescript: 5.5.4 + + w3c-keyname@2.2.6: {} + + watchpack@2.4.4: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + webpack-sources@3.2.3: {} + + webpack-virtual-modules@0.6.2: {} + + webpack@5.99.9: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + browserslist: 4.25.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.1 + es-module-lexer: 1.7.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.2 + tapable: 2.2.2 + terser-webpack-plugin: 5.3.14(webpack@5.99.9) + watchpack: 2.4.4 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + yallist@4.0.0: {} + + yocto-queue@0.1.0: {} diff --git a/console/pnpm-workspace.yaml b/console/pnpm-workspace.yaml new file mode 100644 index 0000000..f9eaa63 --- /dev/null +++ b/console/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +onlyBuiltDependencies: + - core-js + - esbuild + - vue-demi + +patchedDependencies: + '@tiptap/suggestion@2.11.2': patches/@tiptap__suggestion@2.11.2.patch diff --git a/console/rsbuild.config.mjs b/console/rsbuild.config.mjs new file mode 100644 index 0000000..645bf06 --- /dev/null +++ b/console/rsbuild.config.mjs @@ -0,0 +1,39 @@ +import { rsbuildConfig } from "@halo-dev/ui-plugin-bundler-kit"; +import { pluginSass } from "@rsbuild/plugin-sass"; +import { UnoCSSRspackPlugin } from "@unocss/webpack/rspack"; +import Icons from "unplugin-icons/rspack"; + +const OUT_DIR_PROD = "../src/main/resources/console"; +const OUT_DIR_DEV = "../build/resources/main/console"; + +export default rsbuildConfig({ + rsbuild: ({ envMode }) => { + const isProduction = envMode === "production"; + const outDir = isProduction ? OUT_DIR_PROD : OUT_DIR_DEV; + + return { + plugins: [pluginSass()], + resolve: { + alias: { + "@": "./src", + }, + }, + output: { + distPath: { + root: outDir, + }, + }, + tools: { + rspack: { + cache: false, + plugins: [ + Icons({ + compiler: "vue3", + }), + UnoCSSRspackPlugin(), + ], + }, + }, + }; + }, +}); diff --git a/console/src/api/generated/.gitignore b/console/src/api/generated/.gitignore new file mode 100644 index 0000000..149b576 --- /dev/null +++ b/console/src/api/generated/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/console/src/api/generated/.npmignore b/console/src/api/generated/.npmignore new file mode 100644 index 0000000..999d88d --- /dev/null +++ b/console/src/api/generated/.npmignore @@ -0,0 +1 @@ +# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm \ No newline at end of file diff --git a/console/src/api/generated/.openapi-generator-ignore b/console/src/api/generated/.openapi-generator-ignore new file mode 100644 index 0000000..7484ee5 --- /dev/null +++ b/console/src/api/generated/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/console/src/api/generated/.openapi-generator/FILES b/console/src/api/generated/.openapi-generator/FILES new file mode 100644 index 0000000..4d9843f --- /dev/null +++ b/console/src/api/generated/.openapi-generator/FILES @@ -0,0 +1,31 @@ +.gitignore +.npmignore +.openapi-generator-ignore +api.ts +api/console-api-moment-halo-run-v1alpha1-moment-api.ts +api/moment-v1alpha1-api.ts +api/uc-api-moment-halo-run-v1alpha1-moment-api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts +models/add-operation.ts +models/contributor.ts +models/copy-operation.ts +models/index.ts +models/json-patch-inner.ts +models/listed-moment-list.ts +models/listed-moment.ts +models/metadata.ts +models/moment-content.ts +models/moment-list.ts +models/moment-media.ts +models/moment-spec.ts +models/moment-status.ts +models/moment.ts +models/move-operation.ts +models/remove-operation.ts +models/replace-operation.ts +models/stats.ts +models/test-operation.ts diff --git a/console/src/api/generated/.openapi-generator/VERSION b/console/src/api/generated/.openapi-generator/VERSION new file mode 100644 index 0000000..1985849 --- /dev/null +++ b/console/src/api/generated/.openapi-generator/VERSION @@ -0,0 +1 @@ +7.7.0 diff --git a/console/src/api/generated/api.ts b/console/src/api/generated/api.ts new file mode 100644 index 0000000..c2a17fa --- /dev/null +++ b/console/src/api/generated/api.ts @@ -0,0 +1,20 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +export * from './api/console-api-moment-halo-run-v1alpha1-moment-api'; +export * from './api/moment-v1alpha1-api'; +export * from './api/uc-api-moment-halo-run-v1alpha1-moment-api'; + diff --git a/console/src/api/generated/api/console-api-moment-halo-run-v1alpha1-moment-api.ts b/console/src/api/generated/api/console-api-moment-halo-run-v1alpha1-moment-api.ts new file mode 100644 index 0000000..642cfed --- /dev/null +++ b/console/src/api/generated/api/console-api-moment-halo-run-v1alpha1-moment-api.ts @@ -0,0 +1,573 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from '../configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; +// @ts-ignore +import type { ListedMoment } from '../models'; +// @ts-ignore +import type { ListedMomentList } from '../models'; +// @ts-ignore +import type { Moment } from '../models'; +/** + * ConsoleApiMomentHaloRunV1alpha1MomentApi - axios parameter creator + * @export + */ +export const ConsoleApiMomentHaloRunV1alpha1MomentApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * Create a Moment. + * @param {Moment} moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createMoment: async (moment: Moment, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'moment' is not null or undefined + assertParamExists('createMoment', 'moment', moment) + const localVarPath = `/apis/console.api.moment.halo.run/v1alpha1/moments`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(moment, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get a moment by name. + * @param {string} name Moment name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getMoment: async (name: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('getMoment', 'name', name) + const localVarPath = `/apis/console.api.moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * List moments. + * @param {number} [page] Page number. Default is 0. + * @param {number} [size] Size number. Default is 0. + * @param {Array} [labelSelector] Label selector. e.g.: hidden!=true + * @param {Array} [fieldSelector] Field selector. e.g.: metadata.name==halo + * @param {Array} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @param {string} [keyword] Moments filtered by keyword. + * @param {string} [ownerName] Owner name. + * @param {string} [tag] Moment tag. + * @param {ListMomentsVisibleEnum} [visible] Moment visible. + * @param {string} [startDate] Moment start date. + * @param {string} [endDate] Moment end date. + * @param {boolean} [approved] Moment approved. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listMoments: async (page?: number, size?: number, labelSelector?: Array, fieldSelector?: Array, sort?: Array, keyword?: string, ownerName?: string, tag?: string, visible?: ListMomentsVisibleEnum, startDate?: string, endDate?: string, approved?: boolean, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/apis/console.api.moment.halo.run/v1alpha1/moments`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (page !== undefined) { + localVarQueryParameter['page'] = page; + } + + if (size !== undefined) { + localVarQueryParameter['size'] = size; + } + + if (labelSelector) { + localVarQueryParameter['labelSelector'] = labelSelector; + } + + if (fieldSelector) { + localVarQueryParameter['fieldSelector'] = fieldSelector; + } + + if (sort) { + localVarQueryParameter['sort'] = sort; + } + + if (keyword !== undefined) { + localVarQueryParameter['keyword'] = keyword; + } + + if (ownerName !== undefined) { + localVarQueryParameter['ownerName'] = ownerName; + } + + if (tag !== undefined) { + localVarQueryParameter['tag'] = tag; + } + + if (visible !== undefined) { + localVarQueryParameter['visible'] = visible; + } + + if (startDate !== undefined) { + localVarQueryParameter['startDate'] = (startDate as any instanceof Date) ? + (startDate as any).toISOString() : + startDate; + } + + if (endDate !== undefined) { + localVarQueryParameter['endDate'] = (endDate as any instanceof Date) ? + (endDate as any).toISOString() : + endDate; + } + + if (approved !== undefined) { + localVarQueryParameter['approved'] = approved; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * List all moment tags. + * @param {string} [name] Tag name to query + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listTags: async (name?: string, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/apis/console.api.moment.halo.run/v1alpha1/tags`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (name !== undefined) { + localVarQueryParameter['name'] = name; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * ConsoleApiMomentHaloRunV1alpha1MomentApi - functional programming interface + * @export + */ +export const ConsoleApiMomentHaloRunV1alpha1MomentApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = ConsoleApiMomentHaloRunV1alpha1MomentApiAxiosParamCreator(configuration) + return { + /** + * Create a Moment. + * @param {Moment} moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createMoment(moment: Moment, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createMoment(moment, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ConsoleApiMomentHaloRunV1alpha1MomentApi.createMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get a moment by name. + * @param {string} name Moment name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getMoment(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getMoment(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ConsoleApiMomentHaloRunV1alpha1MomentApi.getMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * List moments. + * @param {number} [page] Page number. Default is 0. + * @param {number} [size] Size number. Default is 0. + * @param {Array} [labelSelector] Label selector. e.g.: hidden!=true + * @param {Array} [fieldSelector] Field selector. e.g.: metadata.name==halo + * @param {Array} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @param {string} [keyword] Moments filtered by keyword. + * @param {string} [ownerName] Owner name. + * @param {string} [tag] Moment tag. + * @param {ListMomentsVisibleEnum} [visible] Moment visible. + * @param {string} [startDate] Moment start date. + * @param {string} [endDate] Moment end date. + * @param {boolean} [approved] Moment approved. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listMoments(page?: number, size?: number, labelSelector?: Array, fieldSelector?: Array, sort?: Array, keyword?: string, ownerName?: string, tag?: string, visible?: ListMomentsVisibleEnum, startDate?: string, endDate?: string, approved?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listMoments(page, size, labelSelector, fieldSelector, sort, keyword, ownerName, tag, visible, startDate, endDate, approved, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ConsoleApiMomentHaloRunV1alpha1MomentApi.listMoments']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * List all moment tags. + * @param {string} [name] Tag name to query + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listTags(name?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listTags(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['ConsoleApiMomentHaloRunV1alpha1MomentApi.listTags']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * ConsoleApiMomentHaloRunV1alpha1MomentApi - factory interface + * @export + */ +export const ConsoleApiMomentHaloRunV1alpha1MomentApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = ConsoleApiMomentHaloRunV1alpha1MomentApiFp(configuration) + return { + /** + * Create a Moment. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createMoment(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createMoment(requestParameters.moment, options).then((request) => request(axios, basePath)); + }, + /** + * Get a moment by name. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiGetMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getMoment(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiGetMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getMoment(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + /** + * List moments. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiListMomentsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listMoments(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiListMomentsRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.listMoments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.keyword, requestParameters.ownerName, requestParameters.tag, requestParameters.visible, requestParameters.startDate, requestParameters.endDate, requestParameters.approved, options).then((request) => request(axios, basePath)); + }, + /** + * List all moment tags. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiListTagsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listTags(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiListTagsRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise> { + return localVarFp.listTags(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * Request parameters for createMoment operation in ConsoleApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMomentRequest + */ +export interface ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMomentRequest { + /** + * + * @type {Moment} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMoment + */ + readonly moment: Moment +} + +/** + * Request parameters for getMoment operation in ConsoleApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface ConsoleApiMomentHaloRunV1alpha1MomentApiGetMomentRequest + */ +export interface ConsoleApiMomentHaloRunV1alpha1MomentApiGetMomentRequest { + /** + * Moment name + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiGetMoment + */ + readonly name: string +} + +/** + * Request parameters for listMoments operation in ConsoleApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface ConsoleApiMomentHaloRunV1alpha1MomentApiListMomentsRequest + */ +export interface ConsoleApiMomentHaloRunV1alpha1MomentApiListMomentsRequest { + /** + * Page number. Default is 0. + * @type {number} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly page?: number + + /** + * Size number. Default is 0. + * @type {number} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly size?: number + + /** + * Label selector. e.g.: hidden!=true + * @type {Array} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly labelSelector?: Array + + /** + * Field selector. e.g.: metadata.name==halo + * @type {Array} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly fieldSelector?: Array + + /** + * Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @type {Array} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly sort?: Array + + /** + * Moments filtered by keyword. + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly keyword?: string + + /** + * Owner name. + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly ownerName?: string + + /** + * Moment tag. + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly tag?: string + + /** + * Moment visible. + * @type {'PUBLIC' | 'PRIVATE'} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly visible?: ListMomentsVisibleEnum + + /** + * Moment start date. + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly startDate?: string + + /** + * Moment end date. + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly endDate?: string + + /** + * Moment approved. + * @type {boolean} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListMoments + */ + readonly approved?: boolean +} + +/** + * Request parameters for listTags operation in ConsoleApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface ConsoleApiMomentHaloRunV1alpha1MomentApiListTagsRequest + */ +export interface ConsoleApiMomentHaloRunV1alpha1MomentApiListTagsRequest { + /** + * Tag name to query + * @type {string} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApiListTags + */ + readonly name?: string +} + +/** + * ConsoleApiMomentHaloRunV1alpha1MomentApi - object-oriented interface + * @export + * @class ConsoleApiMomentHaloRunV1alpha1MomentApi + * @extends {BaseAPI} + */ +export class ConsoleApiMomentHaloRunV1alpha1MomentApi extends BaseAPI { + /** + * Create a Moment. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApi + */ + public createMoment(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiCreateMomentRequest, options?: RawAxiosRequestConfig) { + return ConsoleApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).createMoment(requestParameters.moment, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get a moment by name. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiGetMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApi + */ + public getMoment(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiGetMomentRequest, options?: RawAxiosRequestConfig) { + return ConsoleApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).getMoment(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * List moments. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiListMomentsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApi + */ + public listMoments(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiListMomentsRequest = {}, options?: RawAxiosRequestConfig) { + return ConsoleApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).listMoments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.keyword, requestParameters.ownerName, requestParameters.tag, requestParameters.visible, requestParameters.startDate, requestParameters.endDate, requestParameters.approved, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * List all moment tags. + * @param {ConsoleApiMomentHaloRunV1alpha1MomentApiListTagsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ConsoleApiMomentHaloRunV1alpha1MomentApi + */ + public listTags(requestParameters: ConsoleApiMomentHaloRunV1alpha1MomentApiListTagsRequest = {}, options?: RawAxiosRequestConfig) { + return ConsoleApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).listTags(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } +} + +/** + * @export + */ +export const ListMomentsVisibleEnum = { + Public: 'PUBLIC', + Private: 'PRIVATE' +} as const; +export type ListMomentsVisibleEnum = typeof ListMomentsVisibleEnum[keyof typeof ListMomentsVisibleEnum]; diff --git a/console/src/api/generated/api/moment-v1alpha1-api.ts b/console/src/api/generated/api/moment-v1alpha1-api.ts new file mode 100644 index 0000000..29fe2c7 --- /dev/null +++ b/console/src/api/generated/api/moment-v1alpha1-api.ts @@ -0,0 +1,665 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from '../configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; +// @ts-ignore +import type { JsonPatchInner } from '../models'; +// @ts-ignore +import type { Moment } from '../models'; +// @ts-ignore +import type { MomentList } from '../models'; +/** + * MomentV1alpha1Api - axios parameter creator + * @export + */ +export const MomentV1alpha1ApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * Create Moment + * @param {Moment} [moment] Fresh moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createMoment: async (moment?: Moment, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/apis/moment.halo.run/v1alpha1/moments`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(moment, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Delete Moment + * @param {string} name Name of moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteMoment: async (name: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('deleteMoment', 'name', name) + const localVarPath = `/apis/moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get Moment + * @param {string} name Name of moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getMoment: async (name: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('getMoment', 'name', name) + const localVarPath = `/apis/moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * List Moment + * @param {number} [page] Page number. Default is 0. + * @param {number} [size] Size number. Default is 0. + * @param {Array} [labelSelector] Label selector. e.g.: hidden!=true + * @param {Array} [fieldSelector] Field selector. e.g.: metadata.name==halo + * @param {Array} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listMoment: async (page?: number, size?: number, labelSelector?: Array, fieldSelector?: Array, sort?: Array, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/apis/moment.halo.run/v1alpha1/moments`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (page !== undefined) { + localVarQueryParameter['page'] = page; + } + + if (size !== undefined) { + localVarQueryParameter['size'] = size; + } + + if (labelSelector) { + localVarQueryParameter['labelSelector'] = labelSelector; + } + + if (fieldSelector) { + localVarQueryParameter['fieldSelector'] = fieldSelector; + } + + if (sort) { + localVarQueryParameter['sort'] = sort; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Patch Moment + * @param {string} name Name of moment + * @param {Array} [jsonPatchInner] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + patchMoment: async (name: string, jsonPatchInner?: Array, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('patchMoment', 'name', name) + const localVarPath = `/apis/moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PATCH', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json-patch+json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(jsonPatchInner, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Update Moment + * @param {string} name Name of moment + * @param {Moment} [moment] Updated moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateMoment: async (name: string, moment?: Moment, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('updateMoment', 'name', name) + const localVarPath = `/apis/moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(moment, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * MomentV1alpha1Api - functional programming interface + * @export + */ +export const MomentV1alpha1ApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = MomentV1alpha1ApiAxiosParamCreator(configuration) + return { + /** + * Create Moment + * @param {Moment} [moment] Fresh moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createMoment(moment?: Moment, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createMoment(moment, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['MomentV1alpha1Api.createMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Delete Moment + * @param {string} name Name of moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteMoment(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteMoment(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['MomentV1alpha1Api.deleteMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get Moment + * @param {string} name Name of moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getMoment(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getMoment(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['MomentV1alpha1Api.getMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * List Moment + * @param {number} [page] Page number. Default is 0. + * @param {number} [size] Size number. Default is 0. + * @param {Array} [labelSelector] Label selector. e.g.: hidden!=true + * @param {Array} [fieldSelector] Field selector. e.g.: metadata.name==halo + * @param {Array} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listMoment(page?: number, size?: number, labelSelector?: Array, fieldSelector?: Array, sort?: Array, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listMoment(page, size, labelSelector, fieldSelector, sort, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['MomentV1alpha1Api.listMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Patch Moment + * @param {string} name Name of moment + * @param {Array} [jsonPatchInner] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async patchMoment(name: string, jsonPatchInner?: Array, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.patchMoment(name, jsonPatchInner, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['MomentV1alpha1Api.patchMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Update Moment + * @param {string} name Name of moment + * @param {Moment} [moment] Updated moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async updateMoment(name: string, moment?: Moment, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateMoment(name, moment, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['MomentV1alpha1Api.updateMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * MomentV1alpha1Api - factory interface + * @export + */ +export const MomentV1alpha1ApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = MomentV1alpha1ApiFp(configuration) + return { + /** + * Create Moment + * @param {MomentV1alpha1ApiCreateMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createMoment(requestParameters: MomentV1alpha1ApiCreateMomentRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createMoment(requestParameters.moment, options).then((request) => request(axios, basePath)); + }, + /** + * Delete Moment + * @param {MomentV1alpha1ApiDeleteMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteMoment(requestParameters: MomentV1alpha1ApiDeleteMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.deleteMoment(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + /** + * Get Moment + * @param {MomentV1alpha1ApiGetMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getMoment(requestParameters: MomentV1alpha1ApiGetMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getMoment(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + /** + * List Moment + * @param {MomentV1alpha1ApiListMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listMoment(requestParameters: MomentV1alpha1ApiListMomentRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.listMoment(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, options).then((request) => request(axios, basePath)); + }, + /** + * Patch Moment + * @param {MomentV1alpha1ApiPatchMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + patchMoment(requestParameters: MomentV1alpha1ApiPatchMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.patchMoment(requestParameters.name, requestParameters.jsonPatchInner, options).then((request) => request(axios, basePath)); + }, + /** + * Update Moment + * @param {MomentV1alpha1ApiUpdateMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateMoment(requestParameters: MomentV1alpha1ApiUpdateMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.updateMoment(requestParameters.name, requestParameters.moment, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * Request parameters for createMoment operation in MomentV1alpha1Api. + * @export + * @interface MomentV1alpha1ApiCreateMomentRequest + */ +export interface MomentV1alpha1ApiCreateMomentRequest { + /** + * Fresh moment + * @type {Moment} + * @memberof MomentV1alpha1ApiCreateMoment + */ + readonly moment?: Moment +} + +/** + * Request parameters for deleteMoment operation in MomentV1alpha1Api. + * @export + * @interface MomentV1alpha1ApiDeleteMomentRequest + */ +export interface MomentV1alpha1ApiDeleteMomentRequest { + /** + * Name of moment + * @type {string} + * @memberof MomentV1alpha1ApiDeleteMoment + */ + readonly name: string +} + +/** + * Request parameters for getMoment operation in MomentV1alpha1Api. + * @export + * @interface MomentV1alpha1ApiGetMomentRequest + */ +export interface MomentV1alpha1ApiGetMomentRequest { + /** + * Name of moment + * @type {string} + * @memberof MomentV1alpha1ApiGetMoment + */ + readonly name: string +} + +/** + * Request parameters for listMoment operation in MomentV1alpha1Api. + * @export + * @interface MomentV1alpha1ApiListMomentRequest + */ +export interface MomentV1alpha1ApiListMomentRequest { + /** + * Page number. Default is 0. + * @type {number} + * @memberof MomentV1alpha1ApiListMoment + */ + readonly page?: number + + /** + * Size number. Default is 0. + * @type {number} + * @memberof MomentV1alpha1ApiListMoment + */ + readonly size?: number + + /** + * Label selector. e.g.: hidden!=true + * @type {Array} + * @memberof MomentV1alpha1ApiListMoment + */ + readonly labelSelector?: Array + + /** + * Field selector. e.g.: metadata.name==halo + * @type {Array} + * @memberof MomentV1alpha1ApiListMoment + */ + readonly fieldSelector?: Array + + /** + * Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @type {Array} + * @memberof MomentV1alpha1ApiListMoment + */ + readonly sort?: Array +} + +/** + * Request parameters for patchMoment operation in MomentV1alpha1Api. + * @export + * @interface MomentV1alpha1ApiPatchMomentRequest + */ +export interface MomentV1alpha1ApiPatchMomentRequest { + /** + * Name of moment + * @type {string} + * @memberof MomentV1alpha1ApiPatchMoment + */ + readonly name: string + + /** + * + * @type {Array} + * @memberof MomentV1alpha1ApiPatchMoment + */ + readonly jsonPatchInner?: Array +} + +/** + * Request parameters for updateMoment operation in MomentV1alpha1Api. + * @export + * @interface MomentV1alpha1ApiUpdateMomentRequest + */ +export interface MomentV1alpha1ApiUpdateMomentRequest { + /** + * Name of moment + * @type {string} + * @memberof MomentV1alpha1ApiUpdateMoment + */ + readonly name: string + + /** + * Updated moment + * @type {Moment} + * @memberof MomentV1alpha1ApiUpdateMoment + */ + readonly moment?: Moment +} + +/** + * MomentV1alpha1Api - object-oriented interface + * @export + * @class MomentV1alpha1Api + * @extends {BaseAPI} + */ +export class MomentV1alpha1Api extends BaseAPI { + /** + * Create Moment + * @param {MomentV1alpha1ApiCreateMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MomentV1alpha1Api + */ + public createMoment(requestParameters: MomentV1alpha1ApiCreateMomentRequest = {}, options?: RawAxiosRequestConfig) { + return MomentV1alpha1ApiFp(this.configuration).createMoment(requestParameters.moment, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Delete Moment + * @param {MomentV1alpha1ApiDeleteMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MomentV1alpha1Api + */ + public deleteMoment(requestParameters: MomentV1alpha1ApiDeleteMomentRequest, options?: RawAxiosRequestConfig) { + return MomentV1alpha1ApiFp(this.configuration).deleteMoment(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get Moment + * @param {MomentV1alpha1ApiGetMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MomentV1alpha1Api + */ + public getMoment(requestParameters: MomentV1alpha1ApiGetMomentRequest, options?: RawAxiosRequestConfig) { + return MomentV1alpha1ApiFp(this.configuration).getMoment(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * List Moment + * @param {MomentV1alpha1ApiListMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MomentV1alpha1Api + */ + public listMoment(requestParameters: MomentV1alpha1ApiListMomentRequest = {}, options?: RawAxiosRequestConfig) { + return MomentV1alpha1ApiFp(this.configuration).listMoment(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Patch Moment + * @param {MomentV1alpha1ApiPatchMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MomentV1alpha1Api + */ + public patchMoment(requestParameters: MomentV1alpha1ApiPatchMomentRequest, options?: RawAxiosRequestConfig) { + return MomentV1alpha1ApiFp(this.configuration).patchMoment(requestParameters.name, requestParameters.jsonPatchInner, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Update Moment + * @param {MomentV1alpha1ApiUpdateMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof MomentV1alpha1Api + */ + public updateMoment(requestParameters: MomentV1alpha1ApiUpdateMomentRequest, options?: RawAxiosRequestConfig) { + return MomentV1alpha1ApiFp(this.configuration).updateMoment(requestParameters.name, requestParameters.moment, options).then((request) => request(this.axios, this.basePath)); + } +} + diff --git a/console/src/api/generated/api/uc-api-moment-halo-run-v1alpha1-moment-api.ts b/console/src/api/generated/api/uc-api-moment-halo-run-v1alpha1-moment-api.ts new file mode 100644 index 0000000..cda87cd --- /dev/null +++ b/console/src/api/generated/api/uc-api-moment-halo-run-v1alpha1-moment-api.ts @@ -0,0 +1,759 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from '../configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; +// @ts-ignore +import type { ListedMomentList } from '../models'; +// @ts-ignore +import type { Moment } from '../models'; +/** + * UcApiMomentHaloRunV1alpha1MomentApi - axios parameter creator + * @export + */ +export const UcApiMomentHaloRunV1alpha1MomentApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * Create a My Moment. + * @param {Moment} moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createMyMoment: async (moment: Moment, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'moment' is not null or undefined + assertParamExists('createMyMoment', 'moment', moment) + const localVarPath = `/apis/uc.api.moment.halo.run/v1alpha1/moments`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(moment, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Delete a My Moment. + * @param {string} name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteMyMoment: async (name: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('deleteMyMoment', 'name', name) + const localVarPath = `/apis/uc.api.moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Get a My Moment. + * @param {string} name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getMyMoment: async (name: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('getMyMoment', 'name', name) + const localVarPath = `/apis/uc.api.moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * List My moments. + * @param {number} [page] Page number. Default is 0. + * @param {number} [size] Size number. Default is 0. + * @param {Array} [labelSelector] Label selector. e.g.: hidden!=true + * @param {Array} [fieldSelector] Field selector. e.g.: metadata.name==halo + * @param {Array} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @param {string} [keyword] Moments filtered by keyword. + * @param {string} [ownerName] Owner name. + * @param {string} [tag] Moment tag. + * @param {ListMyMomentsVisibleEnum} [visible] Moment visible. + * @param {string} [startDate] Moment start date. + * @param {string} [endDate] Moment end date. + * @param {boolean} [approved] Moment approved. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listMyMoments: async (page?: number, size?: number, labelSelector?: Array, fieldSelector?: Array, sort?: Array, keyword?: string, ownerName?: string, tag?: string, visible?: ListMyMomentsVisibleEnum, startDate?: string, endDate?: string, approved?: boolean, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/apis/uc.api.moment.halo.run/v1alpha1/moments`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (page !== undefined) { + localVarQueryParameter['page'] = page; + } + + if (size !== undefined) { + localVarQueryParameter['size'] = size; + } + + if (labelSelector) { + localVarQueryParameter['labelSelector'] = labelSelector; + } + + if (fieldSelector) { + localVarQueryParameter['fieldSelector'] = fieldSelector; + } + + if (sort) { + localVarQueryParameter['sort'] = sort; + } + + if (keyword !== undefined) { + localVarQueryParameter['keyword'] = keyword; + } + + if (ownerName !== undefined) { + localVarQueryParameter['ownerName'] = ownerName; + } + + if (tag !== undefined) { + localVarQueryParameter['tag'] = tag; + } + + if (visible !== undefined) { + localVarQueryParameter['visible'] = visible; + } + + if (startDate !== undefined) { + localVarQueryParameter['startDate'] = (startDate as any instanceof Date) ? + (startDate as any).toISOString() : + startDate; + } + + if (endDate !== undefined) { + localVarQueryParameter['endDate'] = (endDate as any instanceof Date) ? + (endDate as any).toISOString() : + endDate; + } + + if (approved !== undefined) { + localVarQueryParameter['approved'] = approved; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * List all moment tags. + * @param {string} [name] Tag name to query + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listTags1: async (name?: string, options: RawAxiosRequestConfig = {}): Promise => { + const localVarPath = `/apis/uc.api.moment.halo.run/v1alpha1/tags`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + if (name !== undefined) { + localVarQueryParameter['name'] = name; + } + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * Update a My Moment. + * @param {string} name + * @param {Moment} moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateMyMoment: async (name: string, moment: Moment, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'name' is not null or undefined + assertParamExists('updateMyMoment', 'name', name) + // verify required parameter 'moment' is not null or undefined + assertParamExists('updateMyMoment', 'moment', moment) + const localVarPath = `/apis/uc.api.moment.halo.run/v1alpha1/moments/{name}` + .replace(`{${"name"}}`, encodeURIComponent(String(name))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication basicAuth required + // http basic authentication required + setBasicAuthToObject(localVarRequestOptions, configuration) + + // authentication bearerAuth required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(moment, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * UcApiMomentHaloRunV1alpha1MomentApi - functional programming interface + * @export + */ +export const UcApiMomentHaloRunV1alpha1MomentApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = UcApiMomentHaloRunV1alpha1MomentApiAxiosParamCreator(configuration) + return { + /** + * Create a My Moment. + * @param {Moment} moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async createMyMoment(moment: Moment, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.createMyMoment(moment, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['UcApiMomentHaloRunV1alpha1MomentApi.createMyMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Delete a My Moment. + * @param {string} name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async deleteMyMoment(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.deleteMyMoment(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['UcApiMomentHaloRunV1alpha1MomentApi.deleteMyMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Get a My Moment. + * @param {string} name + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getMyMoment(name: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getMyMoment(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['UcApiMomentHaloRunV1alpha1MomentApi.getMyMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * List My moments. + * @param {number} [page] Page number. Default is 0. + * @param {number} [size] Size number. Default is 0. + * @param {Array} [labelSelector] Label selector. e.g.: hidden!=true + * @param {Array} [fieldSelector] Field selector. e.g.: metadata.name==halo + * @param {Array} [sort] Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @param {string} [keyword] Moments filtered by keyword. + * @param {string} [ownerName] Owner name. + * @param {string} [tag] Moment tag. + * @param {ListMyMomentsVisibleEnum} [visible] Moment visible. + * @param {string} [startDate] Moment start date. + * @param {string} [endDate] Moment end date. + * @param {boolean} [approved] Moment approved. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listMyMoments(page?: number, size?: number, labelSelector?: Array, fieldSelector?: Array, sort?: Array, keyword?: string, ownerName?: string, tag?: string, visible?: ListMyMomentsVisibleEnum, startDate?: string, endDate?: string, approved?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listMyMoments(page, size, labelSelector, fieldSelector, sort, keyword, ownerName, tag, visible, startDate, endDate, approved, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['UcApiMomentHaloRunV1alpha1MomentApi.listMyMoments']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * List all moment tags. + * @param {string} [name] Tag name to query + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listTags1(name?: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listTags1(name, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['UcApiMomentHaloRunV1alpha1MomentApi.listTags1']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * Update a My Moment. + * @param {string} name + * @param {Moment} moment + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async updateMyMoment(name: string, moment: Moment, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.updateMyMoment(name, moment, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['UcApiMomentHaloRunV1alpha1MomentApi.updateMyMoment']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * UcApiMomentHaloRunV1alpha1MomentApi - factory interface + * @export + */ +export const UcApiMomentHaloRunV1alpha1MomentApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = UcApiMomentHaloRunV1alpha1MomentApiFp(configuration) + return { + /** + * Create a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiCreateMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + createMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiCreateMyMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.createMyMoment(requestParameters.moment, options).then((request) => request(axios, basePath)); + }, + /** + * Delete a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + deleteMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.deleteMyMoment(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + /** + * Get a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiGetMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiGetMyMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.getMyMoment(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + /** + * List My moments. + * @param {UcApiMomentHaloRunV1alpha1MomentApiListMyMomentsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listMyMoments(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiListMyMomentsRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.listMyMoments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.keyword, requestParameters.ownerName, requestParameters.tag, requestParameters.visible, requestParameters.startDate, requestParameters.endDate, requestParameters.approved, options).then((request) => request(axios, basePath)); + }, + /** + * List all moment tags. + * @param {UcApiMomentHaloRunV1alpha1MomentApiListTags1Request} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listTags1(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiListTags1Request = {}, options?: RawAxiosRequestConfig): AxiosPromise> { + return localVarFp.listTags1(requestParameters.name, options).then((request) => request(axios, basePath)); + }, + /** + * Update a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + updateMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMomentRequest, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.updateMyMoment(requestParameters.name, requestParameters.moment, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * Request parameters for createMyMoment operation in UcApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface UcApiMomentHaloRunV1alpha1MomentApiCreateMyMomentRequest + */ +export interface UcApiMomentHaloRunV1alpha1MomentApiCreateMyMomentRequest { + /** + * + * @type {Moment} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiCreateMyMoment + */ + readonly moment: Moment +} + +/** + * Request parameters for deleteMyMoment operation in UcApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMomentRequest + */ +export interface UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMomentRequest { + /** + * + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMoment + */ + readonly name: string +} + +/** + * Request parameters for getMyMoment operation in UcApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface UcApiMomentHaloRunV1alpha1MomentApiGetMyMomentRequest + */ +export interface UcApiMomentHaloRunV1alpha1MomentApiGetMyMomentRequest { + /** + * + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiGetMyMoment + */ + readonly name: string +} + +/** + * Request parameters for listMyMoments operation in UcApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface UcApiMomentHaloRunV1alpha1MomentApiListMyMomentsRequest + */ +export interface UcApiMomentHaloRunV1alpha1MomentApiListMyMomentsRequest { + /** + * Page number. Default is 0. + * @type {number} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly page?: number + + /** + * Size number. Default is 0. + * @type {number} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly size?: number + + /** + * Label selector. e.g.: hidden!=true + * @type {Array} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly labelSelector?: Array + + /** + * Field selector. e.g.: metadata.name==halo + * @type {Array} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly fieldSelector?: Array + + /** + * Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @type {Array} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly sort?: Array + + /** + * Moments filtered by keyword. + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly keyword?: string + + /** + * Owner name. + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly ownerName?: string + + /** + * Moment tag. + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly tag?: string + + /** + * Moment visible. + * @type {'PUBLIC' | 'PRIVATE'} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly visible?: ListMyMomentsVisibleEnum + + /** + * Moment start date. + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly startDate?: string + + /** + * Moment end date. + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly endDate?: string + + /** + * Moment approved. + * @type {boolean} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListMyMoments + */ + readonly approved?: boolean +} + +/** + * Request parameters for listTags1 operation in UcApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface UcApiMomentHaloRunV1alpha1MomentApiListTags1Request + */ +export interface UcApiMomentHaloRunV1alpha1MomentApiListTags1Request { + /** + * Tag name to query + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiListTags1 + */ + readonly name?: string +} + +/** + * Request parameters for updateMyMoment operation in UcApiMomentHaloRunV1alpha1MomentApi. + * @export + * @interface UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMomentRequest + */ +export interface UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMomentRequest { + /** + * + * @type {string} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMoment + */ + readonly name: string + + /** + * + * @type {Moment} + * @memberof UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMoment + */ + readonly moment: Moment +} + +/** + * UcApiMomentHaloRunV1alpha1MomentApi - object-oriented interface + * @export + * @class UcApiMomentHaloRunV1alpha1MomentApi + * @extends {BaseAPI} + */ +export class UcApiMomentHaloRunV1alpha1MomentApi extends BaseAPI { + /** + * Create a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiCreateMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UcApiMomentHaloRunV1alpha1MomentApi + */ + public createMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiCreateMyMomentRequest, options?: RawAxiosRequestConfig) { + return UcApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).createMyMoment(requestParameters.moment, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Delete a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UcApiMomentHaloRunV1alpha1MomentApi + */ + public deleteMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiDeleteMyMomentRequest, options?: RawAxiosRequestConfig) { + return UcApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).deleteMyMoment(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Get a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiGetMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UcApiMomentHaloRunV1alpha1MomentApi + */ + public getMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiGetMyMomentRequest, options?: RawAxiosRequestConfig) { + return UcApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).getMyMoment(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * List My moments. + * @param {UcApiMomentHaloRunV1alpha1MomentApiListMyMomentsRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UcApiMomentHaloRunV1alpha1MomentApi + */ + public listMyMoments(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiListMyMomentsRequest = {}, options?: RawAxiosRequestConfig) { + return UcApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).listMyMoments(requestParameters.page, requestParameters.size, requestParameters.labelSelector, requestParameters.fieldSelector, requestParameters.sort, requestParameters.keyword, requestParameters.ownerName, requestParameters.tag, requestParameters.visible, requestParameters.startDate, requestParameters.endDate, requestParameters.approved, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * List all moment tags. + * @param {UcApiMomentHaloRunV1alpha1MomentApiListTags1Request} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UcApiMomentHaloRunV1alpha1MomentApi + */ + public listTags1(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiListTags1Request = {}, options?: RawAxiosRequestConfig) { + return UcApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).listTags1(requestParameters.name, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * Update a My Moment. + * @param {UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMomentRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UcApiMomentHaloRunV1alpha1MomentApi + */ + public updateMyMoment(requestParameters: UcApiMomentHaloRunV1alpha1MomentApiUpdateMyMomentRequest, options?: RawAxiosRequestConfig) { + return UcApiMomentHaloRunV1alpha1MomentApiFp(this.configuration).updateMyMoment(requestParameters.name, requestParameters.moment, options).then((request) => request(this.axios, this.basePath)); + } +} + +/** + * @export + */ +export const ListMyMomentsVisibleEnum = { + Public: 'PUBLIC', + Private: 'PRIVATE' +} as const; +export type ListMyMomentsVisibleEnum = typeof ListMyMomentsVisibleEnum[keyof typeof ListMyMomentsVisibleEnum]; diff --git a/console/src/api/generated/base.ts b/console/src/api/generated/base.ts new file mode 100644 index 0000000..50a1e18 --- /dev/null +++ b/console/src/api/generated/base.ts @@ -0,0 +1,86 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from './configuration'; +// Some imports not used depending on template conditions +// @ts-ignore +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; + +export const BASE_PATH = "http://localhost:65084".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: RawAxiosRequestConfig; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath ?? basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + constructor(public field: string, msg?: string) { + super(msg); + this.name = "RequiredError" + } +} + +interface ServerMap { + [key: string]: { + url: string, + description: string, + }[]; +} + +/** + * + * @export + */ +export const operationServerMap: ServerMap = { +} diff --git a/console/src/api/generated/common.ts b/console/src/api/generated/common.ts new file mode 100644 index 0000000..b7f1bd1 --- /dev/null +++ b/console/src/api/generated/common.ts @@ -0,0 +1,150 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +import type { Configuration } from "./configuration"; +import type { RequestArgs } from "./base"; +import type { AxiosInstance, AxiosResponse } from 'axios'; +import { RequiredError } from "./base"; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com' + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); + } +} + +/** + * + * @export + */ +export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +} + +/** + * + * @export + */ +export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { + if (configuration && (configuration.username || configuration.password)) { + object["auth"] = { username: configuration.username, password: configuration.password }; + } +} + +/** + * + * @export + */ +export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object["Authorization"] = "Bearer " + accessToken; + } +} + +/** + * + * @export + */ +export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object["Authorization"] = "Bearer " + localVarAccessTokenValue; + } +} + +function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { + if (parameter == null) return; + if (typeof parameter === "object") { + if (Array.isArray(parameter)) { + (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); + } + else { + Object.keys(parameter).forEach(currentKey => + setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) + ); + } + } + else { + if (urlSearchParams.has(key)) { + urlSearchParams.append(key, parameter); + } + else { + urlSearchParams.set(key, parameter); + } + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + setFlattenedQueryParams(searchParams, objects); + url.search = searchParams.toString(); +} + +/** + * + * @export + */ +export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { + const nonString = typeof value !== 'string'; + const needsSerialization = nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : (value || ""); +} + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash +} + +/** + * + * @export + */ +export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { + return >(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...axiosArgs.options, url: (axios.defaults.baseURL ? '' : configuration?.basePath ?? basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/console/src/api/generated/configuration.ts b/console/src/api/generated/configuration.ts new file mode 100644 index 0000000..c5ef9d6 --- /dev/null +++ b/console/src/api/generated/configuration.ts @@ -0,0 +1,110 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export interface ConfigurationParameters { + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + serverIndex?: number; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * override server index + * + * @type {number} + * @memberof Configuration + */ + serverIndex?: number; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.serverIndex = param.serverIndex; + this.baseOptions = param.baseOptions; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } +} diff --git a/console/src/api/generated/git_push.sh b/console/src/api/generated/git_push.sh new file mode 100644 index 0000000..f53a75d --- /dev/null +++ b/console/src/api/generated/git_push.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 +git_host=$4 + +if [ "$git_host" = "" ]; then + git_host="github.com" + echo "[INFO] No command line input provided. Set \$git_host to $git_host" +fi + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=$(git remote) +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' diff --git a/console/src/api/generated/index.ts b/console/src/api/generated/index.ts new file mode 100644 index 0000000..a68ebf1 --- /dev/null +++ b/console/src/api/generated/index.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +export * from "./api"; +export * from "./configuration"; +export * from "./models"; diff --git a/console/src/api/generated/models/add-operation.ts b/console/src/api/generated/models/add-operation.ts new file mode 100644 index 0000000..5ce065b --- /dev/null +++ b/console/src/api/generated/models/add-operation.ts @@ -0,0 +1,49 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface AddOperation + */ +export interface AddOperation { + /** + * + * @type {string} + * @memberof AddOperation + */ + 'op': AddOperationOpEnum; + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof AddOperation + */ + 'path': string; + /** + * Value can be any JSON value + * @type {any} + * @memberof AddOperation + */ + 'value': any; +} + +export const AddOperationOpEnum = { + Add: 'add' +} as const; + +export type AddOperationOpEnum = typeof AddOperationOpEnum[keyof typeof AddOperationOpEnum]; + + diff --git a/console/src/api/generated/models/contributor.ts b/console/src/api/generated/models/contributor.ts new file mode 100644 index 0000000..d8a755b --- /dev/null +++ b/console/src/api/generated/models/contributor.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface Contributor + */ +export interface Contributor { + /** + * + * @type {string} + * @memberof Contributor + */ + 'avatar'?: string; + /** + * + * @type {string} + * @memberof Contributor + */ + 'displayName'?: string; + /** + * + * @type {string} + * @memberof Contributor + */ + 'name'?: string; +} + diff --git a/console/src/api/generated/models/copy-operation.ts b/console/src/api/generated/models/copy-operation.ts new file mode 100644 index 0000000..a7ed4c5 --- /dev/null +++ b/console/src/api/generated/models/copy-operation.ts @@ -0,0 +1,49 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface CopyOperation + */ +export interface CopyOperation { + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof CopyOperation + */ + 'from': string; + /** + * + * @type {string} + * @memberof CopyOperation + */ + 'op': CopyOperationOpEnum; + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof CopyOperation + */ + 'path': string; +} + +export const CopyOperationOpEnum = { + Copy: 'copy' +} as const; + +export type CopyOperationOpEnum = typeof CopyOperationOpEnum[keyof typeof CopyOperationOpEnum]; + + diff --git a/console/src/api/generated/models/index.ts b/console/src/api/generated/models/index.ts new file mode 100644 index 0000000..5f68038 --- /dev/null +++ b/console/src/api/generated/models/index.ts @@ -0,0 +1,18 @@ +export * from "./add-operation"; +export * from "./contributor"; +export * from "./copy-operation"; +export * from "./json-patch-inner"; +export * from "./listed-moment"; +export * from "./listed-moment-list"; +export * from "./metadata"; +export * from "./moment"; +export * from "./moment-content"; +export * from "./moment-list"; +export * from "./moment-media"; +export * from "./moment-spec"; +export * from "./moment-status"; +export * from "./move-operation"; +export * from "./remove-operation"; +export * from "./replace-operation"; +export * from "./stats"; +export * from "./test-operation"; diff --git a/console/src/api/generated/models/json-patch-inner.ts b/console/src/api/generated/models/json-patch-inner.ts new file mode 100644 index 0000000..48764b0 --- /dev/null +++ b/console/src/api/generated/models/json-patch-inner.ts @@ -0,0 +1,41 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { AddOperation } from './add-operation'; +// May contain unused imports in some cases +// @ts-ignore +import type { CopyOperation } from './copy-operation'; +// May contain unused imports in some cases +// @ts-ignore +import type { MoveOperation } from './move-operation'; +// May contain unused imports in some cases +// @ts-ignore +import type { RemoveOperation } from './remove-operation'; +// May contain unused imports in some cases +// @ts-ignore +import type { ReplaceOperation } from './replace-operation'; +// May contain unused imports in some cases +// @ts-ignore +import type { TestOperation } from './test-operation'; + +/** + * @type JsonPatchInner + * @export + */ +export type JsonPatchInner = AddOperation | CopyOperation | MoveOperation | RemoveOperation | ReplaceOperation | TestOperation; + + diff --git a/console/src/api/generated/models/listed-moment-list.ts b/console/src/api/generated/models/listed-moment-list.ts new file mode 100644 index 0000000..872ef94 --- /dev/null +++ b/console/src/api/generated/models/listed-moment-list.ts @@ -0,0 +1,81 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { ListedMoment } from './listed-moment'; + +/** + * + * @export + * @interface ListedMomentList + */ +export interface ListedMomentList { + /** + * Indicates whether current page is the first page. + * @type {boolean} + * @memberof ListedMomentList + */ + 'first': boolean; + /** + * Indicates whether current page has previous page. + * @type {boolean} + * @memberof ListedMomentList + */ + 'hasNext': boolean; + /** + * Indicates whether current page has previous page. + * @type {boolean} + * @memberof ListedMomentList + */ + 'hasPrevious': boolean; + /** + * A chunk of items. + * @type {Array} + * @memberof ListedMomentList + */ + 'items': Array; + /** + * Indicates whether current page is the last page. + * @type {boolean} + * @memberof ListedMomentList + */ + 'last': boolean; + /** + * Page number, starts from 1. If not set or equal to 0, it means no pagination. + * @type {number} + * @memberof ListedMomentList + */ + 'page': number; + /** + * Size of each page. If not set or equal to 0, it means no pagination. + * @type {number} + * @memberof ListedMomentList + */ + 'size': number; + /** + * Total elements. + * @type {number} + * @memberof ListedMomentList + */ + 'total': number; + /** + * Indicates total pages. + * @type {number} + * @memberof ListedMomentList + */ + 'totalPages': number; +} + diff --git a/console/src/api/generated/models/listed-moment.ts b/console/src/api/generated/models/listed-moment.ts new file mode 100644 index 0000000..2489ddb --- /dev/null +++ b/console/src/api/generated/models/listed-moment.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { Contributor } from './contributor'; +// May contain unused imports in some cases +// @ts-ignore +import type { Moment } from './moment'; +// May contain unused imports in some cases +// @ts-ignore +import type { Stats } from './stats'; + +/** + * A chunk of items. + * @export + * @interface ListedMoment + */ +export interface ListedMoment { + /** + * + * @type {Moment} + * @memberof ListedMoment + */ + 'moment': Moment; + /** + * + * @type {Contributor} + * @memberof ListedMoment + */ + 'owner': Contributor; + /** + * + * @type {Stats} + * @memberof ListedMoment + */ + 'stats': Stats; +} + diff --git a/console/src/api/generated/models/metadata.ts b/console/src/api/generated/models/metadata.ts new file mode 100644 index 0000000..8b06fe0 --- /dev/null +++ b/console/src/api/generated/models/metadata.ts @@ -0,0 +1,72 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface Metadata + */ +export interface Metadata { + /** + * + * @type {{ [key: string]: string; }} + * @memberof Metadata + */ + 'annotations'?: { [key: string]: string; }; + /** + * + * @type {string} + * @memberof Metadata + */ + 'creationTimestamp'?: string | null; + /** + * + * @type {string} + * @memberof Metadata + */ + 'deletionTimestamp'?: string | null; + /** + * + * @type {Array} + * @memberof Metadata + */ + 'finalizers'?: Array | null; + /** + * The name field will be generated automatically according to the given generateName field + * @type {string} + * @memberof Metadata + */ + 'generateName'?: string; + /** + * + * @type {{ [key: string]: string; }} + * @memberof Metadata + */ + 'labels'?: { [key: string]: string; }; + /** + * Metadata name + * @type {string} + * @memberof Metadata + */ + 'name': string; + /** + * + * @type {number} + * @memberof Metadata + */ + 'version'?: number | null; +} + diff --git a/console/src/api/generated/models/moment-content.ts b/console/src/api/generated/models/moment-content.ts new file mode 100644 index 0000000..eec54f9 --- /dev/null +++ b/console/src/api/generated/models/moment-content.ts @@ -0,0 +1,45 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { MomentMedia } from './moment-media'; + +/** + * + * @export + * @interface MomentContent + */ +export interface MomentContent { + /** + * Rendered result with HTML format + * @type {string} + * @memberof MomentContent + */ + 'html'?: string; + /** + * Medium of moment + * @type {Array} + * @memberof MomentContent + */ + 'medium'?: Array; + /** + * Raw of content + * @type {string} + * @memberof MomentContent + */ + 'raw'?: string; +} + diff --git a/console/src/api/generated/models/moment-list.ts b/console/src/api/generated/models/moment-list.ts new file mode 100644 index 0000000..d860808 --- /dev/null +++ b/console/src/api/generated/models/moment-list.ts @@ -0,0 +1,81 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { Moment } from './moment'; + +/** + * + * @export + * @interface MomentList + */ +export interface MomentList { + /** + * Indicates whether current page is the first page. + * @type {boolean} + * @memberof MomentList + */ + 'first': boolean; + /** + * Indicates whether current page has previous page. + * @type {boolean} + * @memberof MomentList + */ + 'hasNext': boolean; + /** + * Indicates whether current page has previous page. + * @type {boolean} + * @memberof MomentList + */ + 'hasPrevious': boolean; + /** + * A chunk of items. + * @type {Array} + * @memberof MomentList + */ + 'items': Array; + /** + * Indicates whether current page is the last page. + * @type {boolean} + * @memberof MomentList + */ + 'last': boolean; + /** + * Page number, starts from 1. If not set or equal to 0, it means no pagination. + * @type {number} + * @memberof MomentList + */ + 'page': number; + /** + * Size of each page. If not set or equal to 0, it means no pagination. + * @type {number} + * @memberof MomentList + */ + 'size': number; + /** + * Total elements. + * @type {number} + * @memberof MomentList + */ + 'total': number; + /** + * Indicates total pages. + * @type {number} + * @memberof MomentList + */ + 'totalPages': number; +} + diff --git a/console/src/api/generated/models/moment-media.ts b/console/src/api/generated/models/moment-media.ts new file mode 100644 index 0000000..c54303c --- /dev/null +++ b/console/src/api/generated/models/moment-media.ts @@ -0,0 +1,52 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * Media item of moment + * @export + * @interface MomentMedia + */ +export interface MomentMedia { + /** + * Origin type of media. + * @type {string} + * @memberof MomentMedia + */ + 'originType'?: string; + /** + * Type of media + * @type {string} + * @memberof MomentMedia + */ + 'type'?: MomentMediaTypeEnum; + /** + * External URL of media + * @type {string} + * @memberof MomentMedia + */ + 'url'?: string; +} + +export const MomentMediaTypeEnum = { + Photo: 'PHOTO', + Video: 'VIDEO', + Post: 'POST', + Audio: 'AUDIO' +} as const; + +export type MomentMediaTypeEnum = typeof MomentMediaTypeEnum[keyof typeof MomentMediaTypeEnum]; + + diff --git a/console/src/api/generated/models/moment-spec.ts b/console/src/api/generated/models/moment-spec.ts new file mode 100644 index 0000000..a5f7fe8 --- /dev/null +++ b/console/src/api/generated/models/moment-spec.ts @@ -0,0 +1,77 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { MomentContent } from './moment-content'; + +/** + * + * @export + * @interface MomentSpec + */ +export interface MomentSpec { + /** + * + * @type {boolean} + * @memberof MomentSpec + */ + 'approved'?: boolean; + /** + * + * @type {string} + * @memberof MomentSpec + */ + 'approvedTime'?: string; + /** + * + * @type {MomentContent} + * @memberof MomentSpec + */ + 'content': MomentContent; + /** + * Owner of the moment + * @type {string} + * @memberof MomentSpec + */ + 'owner': string; + /** + * Release timestamp. This field can be customized by owner + * @type {string} + * @memberof MomentSpec + */ + 'releaseTime'?: string; + /** + * Tags of the moment + * @type {Array} + * @memberof MomentSpec + */ + 'tags'?: Array; + /** + * Visible indicates when to show publicly. Default is public + * @type {string} + * @memberof MomentSpec + */ + 'visible'?: MomentSpecVisibleEnum; +} + +export const MomentSpecVisibleEnum = { + Public: 'PUBLIC', + Private: 'PRIVATE' +} as const; + +export type MomentSpecVisibleEnum = typeof MomentSpecVisibleEnum[keyof typeof MomentSpecVisibleEnum]; + + diff --git a/console/src/api/generated/models/moment-status.ts b/console/src/api/generated/models/moment-status.ts new file mode 100644 index 0000000..80c1634 --- /dev/null +++ b/console/src/api/generated/models/moment-status.ts @@ -0,0 +1,36 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface MomentStatus + */ +export interface MomentStatus { + /** + * + * @type {number} + * @memberof MomentStatus + */ + 'observedVersion'?: number; + /** + * + * @type {string} + * @memberof MomentStatus + */ + 'permalink'?: string; +} + diff --git a/console/src/api/generated/models/moment.ts b/console/src/api/generated/models/moment.ts new file mode 100644 index 0000000..8b03f1c --- /dev/null +++ b/console/src/api/generated/models/moment.ts @@ -0,0 +1,63 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { Metadata } from './metadata'; +// May contain unused imports in some cases +// @ts-ignore +import type { MomentSpec } from './moment-spec'; +// May contain unused imports in some cases +// @ts-ignore +import type { MomentStatus } from './moment-status'; + +/** + * + * @export + * @interface Moment + */ +export interface Moment { + /** + * + * @type {string} + * @memberof Moment + */ + 'apiVersion': string; + /** + * + * @type {string} + * @memberof Moment + */ + 'kind': string; + /** + * + * @type {Metadata} + * @memberof Moment + */ + 'metadata': Metadata; + /** + * + * @type {MomentSpec} + * @memberof Moment + */ + 'spec': MomentSpec; + /** + * + * @type {MomentStatus} + * @memberof Moment + */ + 'status'?: MomentStatus; +} + diff --git a/console/src/api/generated/models/move-operation.ts b/console/src/api/generated/models/move-operation.ts new file mode 100644 index 0000000..b0e9e08 --- /dev/null +++ b/console/src/api/generated/models/move-operation.ts @@ -0,0 +1,49 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface MoveOperation + */ +export interface MoveOperation { + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof MoveOperation + */ + 'from': string; + /** + * + * @type {string} + * @memberof MoveOperation + */ + 'op': MoveOperationOpEnum; + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof MoveOperation + */ + 'path': string; +} + +export const MoveOperationOpEnum = { + Move: 'move' +} as const; + +export type MoveOperationOpEnum = typeof MoveOperationOpEnum[keyof typeof MoveOperationOpEnum]; + + diff --git a/console/src/api/generated/models/remove-operation.ts b/console/src/api/generated/models/remove-operation.ts new file mode 100644 index 0000000..4c5ce2c --- /dev/null +++ b/console/src/api/generated/models/remove-operation.ts @@ -0,0 +1,43 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface RemoveOperation + */ +export interface RemoveOperation { + /** + * + * @type {string} + * @memberof RemoveOperation + */ + 'op': RemoveOperationOpEnum; + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof RemoveOperation + */ + 'path': string; +} + +export const RemoveOperationOpEnum = { + Remove: 'remove' +} as const; + +export type RemoveOperationOpEnum = typeof RemoveOperationOpEnum[keyof typeof RemoveOperationOpEnum]; + + diff --git a/console/src/api/generated/models/replace-operation.ts b/console/src/api/generated/models/replace-operation.ts new file mode 100644 index 0000000..84f6e73 --- /dev/null +++ b/console/src/api/generated/models/replace-operation.ts @@ -0,0 +1,49 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ReplaceOperation + */ +export interface ReplaceOperation { + /** + * + * @type {string} + * @memberof ReplaceOperation + */ + 'op': ReplaceOperationOpEnum; + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof ReplaceOperation + */ + 'path': string; + /** + * Value can be any JSON value + * @type {any} + * @memberof ReplaceOperation + */ + 'value': any; +} + +export const ReplaceOperationOpEnum = { + Replace: 'replace' +} as const; + +export type ReplaceOperationOpEnum = typeof ReplaceOperationOpEnum[keyof typeof ReplaceOperationOpEnum]; + + diff --git a/console/src/api/generated/models/stats.ts b/console/src/api/generated/models/stats.ts new file mode 100644 index 0000000..41ebcf0 --- /dev/null +++ b/console/src/api/generated/models/stats.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface Stats + */ +export interface Stats { + /** + * + * @type {number} + * @memberof Stats + */ + 'approvedComment'?: number; + /** + * + * @type {number} + * @memberof Stats + */ + 'totalComment'?: number; + /** + * + * @type {number} + * @memberof Stats + */ + 'upvote'?: number; +} + diff --git a/console/src/api/generated/models/test-operation.ts b/console/src/api/generated/models/test-operation.ts new file mode 100644 index 0000000..3cec441 --- /dev/null +++ b/console/src/api/generated/models/test-operation.ts @@ -0,0 +1,49 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Halo + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 2.17.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface TestOperation + */ +export interface TestOperation { + /** + * + * @type {string} + * @memberof TestOperation + */ + 'op': TestOperationOpEnum; + /** + * A JSON Pointer path pointing to the location to move/copy from. + * @type {string} + * @memberof TestOperation + */ + 'path': string; + /** + * Value can be any JSON value + * @type {any} + * @memberof TestOperation + */ + 'value': any; +} + +export const TestOperationOpEnum = { + Test: 'test' +} as const; + +export type TestOperationOpEnum = typeof TestOperationOpEnum[keyof typeof TestOperationOpEnum]; + + diff --git a/console/src/api/index.ts b/console/src/api/index.ts new file mode 100644 index 0000000..ecd94d3 --- /dev/null +++ b/console/src/api/index.ts @@ -0,0 +1,20 @@ +import { axiosInstance } from "@halo-dev/api-client"; +import { + ConsoleApiMomentHaloRunV1alpha1MomentApi, + MomentV1alpha1Api, + UcApiMomentHaloRunV1alpha1MomentApi, +} from "./generated"; + +const momentsCoreApiClient = { + moment: new MomentV1alpha1Api(undefined, "", axiosInstance), +}; + +const momentsConsoleApiClient = { + moment: new ConsoleApiMomentHaloRunV1alpha1MomentApi(undefined, "", axiosInstance), +}; + +const momentsUcApiClient = { + moment: new UcApiMomentHaloRunV1alpha1MomentApi(undefined, "", axiosInstance), +}; + +export { momentsConsoleApiClient, momentsCoreApiClient, momentsUcApiClient }; diff --git a/console/src/assets/logo.svg b/console/src/assets/logo.svg new file mode 100644 index 0000000..86fbed9 --- /dev/null +++ b/console/src/assets/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/console/src/components/EditorBubbleMenu.vue b/console/src/components/EditorBubbleMenu.vue new file mode 100644 index 0000000..04270ba --- /dev/null +++ b/console/src/components/EditorBubbleMenu.vue @@ -0,0 +1,48 @@ + + + diff --git a/console/src/components/EditorLinkBubbleMenuItems.vue b/console/src/components/EditorLinkBubbleMenuItems.vue new file mode 100644 index 0000000..23a50fc --- /dev/null +++ b/console/src/components/EditorLinkBubbleMenuItems.vue @@ -0,0 +1,97 @@ + + + + diff --git a/console/src/components/FilterDropdown.vue b/console/src/components/FilterDropdown.vue new file mode 100644 index 0000000..15feefe --- /dev/null +++ b/console/src/components/FilterDropdown.vue @@ -0,0 +1,73 @@ + + + diff --git a/console/src/components/MediaCard.vue b/console/src/components/MediaCard.vue new file mode 100644 index 0000000..f164d6b --- /dev/null +++ b/console/src/components/MediaCard.vue @@ -0,0 +1,103 @@ + + diff --git a/console/src/components/MomentEdit.vue b/console/src/components/MomentEdit.vue new file mode 100644 index 0000000..9aad371 --- /dev/null +++ b/console/src/components/MomentEdit.vue @@ -0,0 +1,400 @@ + + + diff --git a/console/src/components/MomentItem.vue b/console/src/components/MomentItem.vue new file mode 100644 index 0000000..9620365 --- /dev/null +++ b/console/src/components/MomentItem.vue @@ -0,0 +1,168 @@ + + diff --git a/console/src/components/MomentPreview.vue b/console/src/components/MomentPreview.vue new file mode 100644 index 0000000..0cf82bb --- /dev/null +++ b/console/src/components/MomentPreview.vue @@ -0,0 +1,227 @@ + + diff --git a/console/src/components/PreviewDetailModal.vue b/console/src/components/PreviewDetailModal.vue new file mode 100644 index 0000000..52dbbf8 --- /dev/null +++ b/console/src/components/PreviewDetailModal.vue @@ -0,0 +1,45 @@ + + diff --git a/console/src/components/TagFilterDropdown.vue b/console/src/components/TagFilterDropdown.vue new file mode 100644 index 0000000..51b2e95 --- /dev/null +++ b/console/src/components/TagFilterDropdown.vue @@ -0,0 +1,103 @@ + + + diff --git a/console/src/components/TextEditor.vue b/console/src/components/TextEditor.vue new file mode 100644 index 0000000..1284877 --- /dev/null +++ b/console/src/components/TextEditor.vue @@ -0,0 +1,200 @@ + + diff --git a/console/src/components/composables/use-extension.ts b/console/src/components/composables/use-extension.ts new file mode 100644 index 0000000..ccfcd12 --- /dev/null +++ b/console/src/components/composables/use-extension.ts @@ -0,0 +1,62 @@ +// FROM https://github.com/halo-dev/halo/blob/733679d5ac98b9e93c373244e2b05d7d79000409/ui/src/components/editor/composables/use-extension.ts +import { randomUUID } from "@/utils/id"; +import { + getExtensionField, + type AnyConfig, + type AnyExtension, + type Extensions, +} from "@halo-dev/richtext-editor"; + +export function useExtension() { + const filterDuplicateExtensions = (extensions: Extensions | undefined) => { + if (!extensions) { + return; + } + const resolvedExtensions = sort(extensions); + const map = new Map(); + resolvedExtensions.forEach((extension) => { + if (!extension.name) { + console.warn(`Extension name is missing for Extension, type: ${extension.type}.`); + const key = randomUUID().toString(); + map.set(key, extension); + return; + } + const key = `${extension.type}-${extension.name}`; + if (map.has(key)) { + console.warn( + `Duplicate found for Extension, type: ${extension.type}, name: ${extension.name}. Keeping the later one.` + ); + } + map.set(key, extension); + }); + return Array.from(map.values()); + }; + + /** + * Sort extensions by priority. + * @param extensions An array of Tiptap extensions + * @returns A sorted array of Tiptap extensions by priority + */ + const sort = (extensions: Extensions): Extensions => { + const defaultPriority = 100; + + return extensions.sort((a, b) => { + const priorityA = getExtensionField(a, "priority") || defaultPriority; + const priorityB = getExtensionField(b, "priority") || defaultPriority; + + if (priorityA > priorityB) { + return -1; + } + + if (priorityA < priorityB) { + return 1; + } + + return 0; + }); + }; + + return { + filterDuplicateExtensions, + }; +} diff --git a/console/src/composables/use-content-cache.ts b/console/src/composables/use-content-cache.ts new file mode 100644 index 0000000..bb7d9b1 --- /dev/null +++ b/console/src/composables/use-content-cache.ts @@ -0,0 +1,79 @@ +import { Toast } from "@halo-dev/components"; +import { useLocalStorage } from "@vueuse/core"; +import { debounce } from "es-toolkit"; +import type { Ref } from "vue"; + +interface ContentCache { + name: string; + content?: string; +} + +interface useContentCacheReturn { + handleResetCache: () => void; + handleSetContentCache: () => void; + handleClearCache: (name: string) => void; +} + +export function useContentCache( + key: string, + name: string, + raw: Ref +): useContentCacheReturn { + const content_caches = useLocalStorage(key, []); + + const handleResetCache = () => { + if (name) { + const cache = content_caches.value.find((c: ContentCache) => c.name === name); + if (cache) { + Toast.info("已从缓存中恢复未保存的内容"); + raw.value = cache.content; + } + } else { + const cache = content_caches.value.find((c: ContentCache) => c.name === "" && c.content); + if (cache) { + Toast.info("已从缓存中恢复未保存的内容"); + raw.value = cache.content; + } + } + }; + + const handleSetContentCache = debounce(() => { + if (name) { + const cache = content_caches.value.find((c: ContentCache) => c.name === name); + if (cache) { + cache.content = raw?.value; + } else { + content_caches.value.push({ + name: name, + content: raw?.value, + }); + } + } else { + const cache = content_caches.value.find((c: ContentCache) => c.name === ""); + if (cache) { + cache.content = raw?.value; + } else { + content_caches.value.push({ + name: "", + content: raw?.value, + }); + } + } + }, 500); + + const handleClearCache = (name: string) => { + if (name) { + const index = content_caches.value.findIndex((c: ContentCache) => c.name === name); + index > -1 && content_caches.value.splice(index, 1); + } else { + const index = content_caches.value.findIndex((c: ContentCache) => c.name === ""); + index > -1 && content_caches.value.splice(index, 1); + } + }; + + return { + handleClearCache, + handleResetCache, + handleSetContentCache, + }; +} diff --git a/console/src/composables/use-tag.ts b/console/src/composables/use-tag.ts new file mode 100644 index 0000000..69e813d --- /dev/null +++ b/console/src/composables/use-tag.ts @@ -0,0 +1,41 @@ +import { momentsConsoleApiClient, momentsUcApiClient } from "@/api"; +import { useQuery } from "@tanstack/vue-query"; +import type { Ref } from "vue"; + +export interface useTagQueryFetchProps { + keyword?: Ref; +} + +export function useConsoleTagQueryFetch(props: useTagQueryFetchProps): ReturnType { + return useTagQueryFetch("console", props); +} + +export function useUCTagQueryFetch(props: useTagQueryFetchProps): ReturnType { + return useTagQueryFetch("uc", props); +} + +export function useTagQueryFetch( + group: "console" | "uc", + props: useTagQueryFetchProps +): ReturnType { + return useQuery({ + queryKey: ["moments-tags", props.keyword], + queryFn: async () => { + if (group === "console") { + const { data } = await momentsConsoleApiClient.moment.listTags({ + name: props.keyword?.value, + }); + return data; + } + + if (group === "uc") { + const { data } = await momentsUcApiClient.moment.listTags1({ + name: props.keyword?.value, + }); + return data; + } + + throw new Error("Invalid group"); + }, + }); +} diff --git a/console/src/extensions/images/index.ts b/console/src/extensions/images/index.ts new file mode 100644 index 0000000..31c3750 --- /dev/null +++ b/console/src/extensions/images/index.ts @@ -0,0 +1,39 @@ +import { type Editor, ExtensionImage, type Range } from "@halo-dev/richtext-editor"; +import type { ExtensionOptions } from "@halo-dev/richtext-editor/dist/types"; +import { markRaw } from "vue"; +import MdiFileImageBox from "~icons/mdi/file-image-box"; + +export interface ImageOptions { + inline: boolean; + allowBase64: boolean; + HTMLAttributes: Record; +} + +const MomentExtensionImage = ExtensionImage.extend({ + addOptions() { + return { + ...this.parent?.(), + getCommandMenuItems() { + return { + priority: 100, + icon: markRaw(MdiFileImageBox), + title: "图片", + keywords: ["image", "tupian"], + command: ({ editor, range }: { editor: Editor; range: Range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .insertContent([ + { type: "image", attrs: { src: "" } }, + { type: "paragraph", content: "" }, + ]) + .run(); + }, + }; + }, + }; + }, +}); + +export default MomentExtensionImage; diff --git a/console/src/extensions/tags/TagsExtensionView.vue b/console/src/extensions/tags/TagsExtensionView.vue new file mode 100644 index 0000000..de6fc45 --- /dev/null +++ b/console/src/extensions/tags/TagsExtensionView.vue @@ -0,0 +1,142 @@ + + + + diff --git a/console/src/extensions/tags/index.ts b/console/src/extensions/tags/index.ts new file mode 100644 index 0000000..2cc03d9 --- /dev/null +++ b/console/src/extensions/tags/index.ts @@ -0,0 +1,199 @@ +import { + type Editor, + Mark, + VueRenderer, + markInputRule, + markPasteRule, + mergeAttributes, + type Range, +} from "@halo-dev/richtext-editor"; +import type { Instance } from "tippy.js"; +import TagsExtensionView from "./TagsExtensionView.vue"; +import tippy from "tippy.js"; +import Suggestion from "@tiptap/suggestion"; +import { PluginKey } from "@halo-dev/richtext-editor"; +import type { useTagQueryFetchProps } from "@/composables/use-tag"; +import type { UseQueryReturnType } from "@tanstack/vue-query"; + +export interface TagOptions { + HTMLAttributes: Record; + tagQueryFetch: (props: useTagQueryFetchProps) => UseQueryReturnType; +} + +declare module "@halo-dev/richtext-editor" { + interface Commands { + tag: { + /** + * Set a tag mark + */ + setTag: (name: string) => ReturnType; + }; + } +} + +export const inputRegex = /#([\u4E00-\u9FFFa-zA-Z0-9]+)(?({ + name: "tag", + + addOptions() { + return { + HTMLAttributes: { + class: "tag", + }, + tagQueryFetch: () => { + throw new Error("tagQueryFetch is not defined"); + }, + }; + }, + + excludes: "_", + + exitable: false, + + inclusive: false, + + addAttributes() { + return { + ...this.parent?.(), + tagText: { + default: null, + renderHTML(attributes) { + return { + href: `/moments?tag=${encodeURI(attributes.tagText)}`, + "data-pjax": "", + }; + }, + }, + }; + }, + + parseHTML() { + return [ + { + tag: "a", + }, + ]; + }, + + renderHTML({ HTMLAttributes }) { + return ["a", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; + }, + + addCommands() { + return { + setTag: + (tag) => + ({ commands }) => { + return commands.insertContent({ + type: "text", + marks: [ + { + type: this.name, + attrs: { + tagText: tag, + }, + }, + ], + text: tag, + }); + }, + }; + }, + + addInputRules() { + return [ + markInputRule({ + find: inputRegex, + type: this.type, + getAttributes(match) { + return { + tagText: match[1], + }; + }, + }), + ]; + }, + + addPasteRules() { + return [ + markPasteRule({ + find: pasteRegex, + type: this.type, + getAttributes(match) { + return { + tagText: match[1], + }; + }, + }), + ]; + }, + + addProseMirrorPlugins() { + return [ + Suggestion({ + pluginKey: new PluginKey("tagsSuggestion"), + editor: this.editor, + char: "#", + render: () => { + let component: VueRenderer; + let popup: Instance[]; + + return { + onStart: (props: Record) => { + component = new VueRenderer(TagsExtensionView, { + props: { ...props, tagQueryFetch: this.options.tagQueryFetch }, + editor: props.editor, + }); + + if (!props.clientRect) { + return; + } + + popup = tippy("body", { + getReferenceClientRect: props.clientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: "manual", + placement: "bottom-start", + }); + }, + + onUpdate(props: Record) { + component.updateProps(props); + + if (!props.clientRect) { + return; + } + + popup[0].setProps({ + getReferenceClientRect: props.clientRect, + }); + }, + + onKeyDown(props: Record) { + if (props.event.key === "Escape") { + popup[0].hide(); + + return true; + } + + return component.ref?.onKeyDown(props); + }, + + onExit() { + popup[0].destroy(); + component.destroy(); + }, + }; + }, + command: ({ editor, range, props }: { editor: Editor; range: Range; props: string }) => { + editor.chain().focus().deleteRange(range).setTag(props).run(); + }, + }), + ]; + }, +}); diff --git a/console/src/index.ts b/console/src/index.ts new file mode 100644 index 0000000..766de66 --- /dev/null +++ b/console/src/index.ts @@ -0,0 +1,91 @@ +import type { Extension } from "@halo-dev/api-client"; +import { type CommentSubjectRefResult, definePlugin } from "@halo-dev/console-shared"; +import { defineAsyncComponent, markRaw } from "vue"; +import MingcuteMomentsLine from "~icons/mingcute/moment-line"; +import type { Moment } from "./api/generated"; +import "uno.css"; +import "./styles/index.scss"; +import { formatDatetime } from "./utils/date"; +import { VLoading } from "@halo-dev/components"; + +export default definePlugin({ + components: {}, + routes: [ + { + parentName: "Root", + route: { + path: "/moments", + name: "Moments", + component: defineAsyncComponent({ + loader: () => import("@/views/MomentsList.vue"), + loadingComponent: VLoading, + }), + meta: { + permissions: ["plugin:moments:view"], + menu: { + name: "瞬间", + group: "content", + icon: markRaw(MingcuteMomentsLine), + }, + }, + }, + }, + ], + ucRoutes: [ + { + parentName: "Root", + route: { + path: "/moments", + name: "Moments", + component: defineAsyncComponent({ + loader: () => import("@/uc/MomentsList.vue"), + loadingComponent: VLoading, + }), + meta: { + permissions: ["uc:plugin:moments:publish"], + menu: { + name: "瞬间", + group: "content", + icon: markRaw(MingcuteMomentsLine), + }, + }, + }, + }, + ], + extensionPoints: { + "comment:subject-ref:create": () => { + return [ + { + kind: "Moment", + group: "moment.halo.run", + resolve: (subject: Extension): CommentSubjectRefResult => { + const moment = subject as Moment; + return { + label: "瞬间", + title: determineMomentTitle(moment), + externalUrl: `/moments/${moment.metadata.name}`, + route: { + name: "Moments", + }, + }; + }, + }, + ]; + }, + }, +}); + +const determineMomentTitle = (moment: Moment) => { + const pureContent = stripHtmlTags(moment.spec.content.raw || ""); + const title = !pureContent?.trim() + ? formatDatetime(new Date(moment.spec.releaseTime || "")) + : pureContent; + return title?.substring(0, 100); +}; + +const stripHtmlTags = (str: string) => { + // strip html tags + const stripped = str?.replace(/<\/?[^>]+(>|$)/gi, "") || ""; + // strip newlines and collapse spaces + return stripped.replace(/\n/g, " ").replace(/\s+/g, " "); +}; diff --git a/console/src/plugin-supports/shiki/directive.ts b/console/src/plugin-supports/shiki/directive.ts new file mode 100644 index 0000000..0a065df --- /dev/null +++ b/console/src/plugin-supports/shiki/directive.ts @@ -0,0 +1,40 @@ +import type { Directive } from "vue"; +import { hasShikiPlugin } from "./util"; + +const ShikiDirective: Directive = { + mounted: (el: HTMLElement) => { + renderShikiCode(el); + }, + updated: (el: HTMLElement) => { + renderShikiCode(el); + }, +}; + +function renderShikiCode(el: HTMLElement) { + if (!hasShikiPlugin()) { + return; + } + + const preElements = el.querySelectorAll("pre:has(code)"); + for (const preElement of preElements) { + const parent = preElement.parentElement; + if (!parent) { + continue; + } + + if (preElement.parentElement.tagName === "SHIKI-CODE") { + continue; + } + + preElement.style.padding = "1rem"; + preElement.style.filter = "blur(10px)"; + + const shikiElement = document.createElement("shiki-code"); + shikiElement.style.padding = "0 1px"; + + parent.insertBefore(shikiElement, preElement); + shikiElement.appendChild(preElement); + } +} + +export default ShikiDirective; diff --git a/console/src/plugin-supports/shiki/use-plugin-shiki-script-loader.ts b/console/src/plugin-supports/shiki/use-plugin-shiki-script-loader.ts new file mode 100644 index 0000000..35ee5fa --- /dev/null +++ b/console/src/plugin-supports/shiki/use-plugin-shiki-script-loader.ts @@ -0,0 +1,26 @@ +import { useScriptTag } from "@vueuse/core"; +import { onMounted, onUnmounted } from "vue"; +import { hasShikiPlugin, PLUGIN_SHIKI_SCRIPT_URL } from "./util"; + +export function usePluginShikiScriptLoader() { + const { unload, load } = useScriptTag( + `${PLUGIN_SHIKI_SCRIPT_URL}?version=${Date.now()}`, + () => { + // do nothing + }, + { + type: "module", + manual: true, + } + ); + + onMounted(() => { + if (hasShikiPlugin()) { + load(); + } + }); + + onUnmounted(() => { + unload(); + }); +} diff --git a/console/src/plugin-supports/shiki/util.ts b/console/src/plugin-supports/shiki/util.ts new file mode 100644 index 0000000..542752e --- /dev/null +++ b/console/src/plugin-supports/shiki/util.ts @@ -0,0 +1,6 @@ +export const PLUGIN_SHIKI_NAME = "shiki"; +export const PLUGIN_SHIKI_SCRIPT_URL = `/plugins/${PLUGIN_SHIKI_NAME}/assets/static/shiki-code.js`; + +export function hasShikiPlugin() { + return window.enabledPlugins.find((p) => p.name === PLUGIN_SHIKI_NAME); +} diff --git a/console/src/styles/index.scss b/console/src/styles/index.scss new file mode 100644 index 0000000..1562104 --- /dev/null +++ b/console/src/styles/index.scss @@ -0,0 +1,207 @@ +.moments-content { + a { + &.tag { + color: rgba(var(--colors-primary), 1); + cursor: pointer; + background-color: #eef3fe; + padding: 1px 4px; + font-size: 12px; + border-radius: 3px; + display: inline-block; + white-space: nowrap; + + &::before { + content: "#"; + } + } + } + + .halo-moment-editor { + box-sizing: border-box; + + .editor-header { + display: none; + } + + .editor-content { + height: 100%; + width: 100%; + + .ProseMirror { + min-height: 10rem; + overflow: auto; + outline: none !important; + padding: 0 !important; + + p { + &:first-child { + margin-top: 0 !important; + } + &.is-editor-empty { + &:first-child { + &::before { + content: attr(data-placeholder); + float: left; + color: #adb5bd; + pointer-events: none; + height: 0; + } + } + } + } + + ul { + &[data-type="taskList"] { + list-style: none; + padding: 0; + + li { + display: flex; + align-items: center; + + > label { + flex: 0 0 auto; + margin-right: 0.5rem; + } + } + } + } + + table { + .selectedCell { + &:after { + z-index: 2; + position: absolute; + content: ""; + left: 0; + right: 0; + top: 0; + bottom: 0; + background: rgba(200, 200, 255, 0.4); + pointer-events: none; + } + } + + .column-resize-handle { + position: absolute; + right: -2px; + top: 0; + bottom: -2px; + width: 4px; + background-color: #adf; + pointer-events: none; + cursor: col-resize !important; + } + } + } + } + } + + .range-time { + height: 2.25rem; + + .mx-input { + padding-top: 0; + padding-bottom: 0; + padding-left: 0.75rem; + padding-right: 2rem; + height: 100%; + border: 1px solid rgb(209 213 219); + box-shadow: none; + font-size: 0.875rem; + line-height: 1.25rem; + color: black; + cursor: pointer; + + &:focus { + border-color: #4ccba0; + } + + &:hover { + border: 1px solid rgb(209 213 219); + } + } + + .mx-input-wrapper { + height: 100%; + } + } + + .v-popper--theme-editor-block-dropdown { + .v-popper__arrow-container { + display: none; + } + } + + .btn-icon { + margin-right: 0 !important; + } + + .preview { + font-size: 14px; + + a { + color: #5783f7; + text-decoration: none; + + &.post-link { + font-weight: 700; + + &::before { + content: "#"; + font-weight: 400; + font-size: 16px; + } + } + } + + .moment-preview-html { + code { + border-radius: 0.375rem; + font-size: 0.8rem; + } + + &.markdown-body { + ul { + list-style: disc; + } + + ol { + list-style: decimal; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + border: none !important; + } + + pre { + code { + border: 1px solid #fbf6f6; + } + } + + p { + & > img { + border-radius: 0.4rem; + overflow: hidden; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), + 0 1px 2px 0 rgba(0, 0, 0, 0.06); + } + + &:last-child { + margin-bottom: 0 !important; + } + + &:not(pre) > code { + background-color: #afb8c133; + } + } + } + } + } +} diff --git a/console/src/types/index.ts b/console/src/types/index.ts new file mode 100644 index 0000000..d0e6c04 --- /dev/null +++ b/console/src/types/index.ts @@ -0,0 +1,10 @@ +import type { Component } from "vue"; + +export interface MenuItem { + type: "button" | "separator"; + icon?: Component; + title?: string; + action?: () => void; + isActive?: () => boolean; + children?: MenuItem[]; +} diff --git a/console/src/uc/MomentEdit.vue b/console/src/uc/MomentEdit.vue new file mode 100644 index 0000000..0e3d2c4 --- /dev/null +++ b/console/src/uc/MomentEdit.vue @@ -0,0 +1,387 @@ + + + diff --git a/console/src/uc/MomentItem.vue b/console/src/uc/MomentItem.vue new file mode 100644 index 0000000..144268e --- /dev/null +++ b/console/src/uc/MomentItem.vue @@ -0,0 +1,148 @@ + + diff --git a/console/src/uc/MomentsList.vue b/console/src/uc/MomentsList.vue new file mode 100644 index 0000000..9baa925 --- /dev/null +++ b/console/src/uc/MomentsList.vue @@ -0,0 +1,199 @@ + + + diff --git a/console/src/uc/TagFilterDropdown.vue b/console/src/uc/TagFilterDropdown.vue new file mode 100644 index 0000000..22728e1 --- /dev/null +++ b/console/src/uc/TagFilterDropdown.vue @@ -0,0 +1,103 @@ + + + diff --git a/console/src/utils/date.ts b/console/src/utils/date.ts new file mode 100644 index 0000000..bc7a613 --- /dev/null +++ b/console/src/utils/date.ts @@ -0,0 +1,60 @@ +//TODO 后续期望 Console 在 shared 包中提供统一的日期时间方法。 +import dayjs from "dayjs"; +import "dayjs/locale/zh-cn"; +import timezone from "dayjs/plugin/timezone"; +import utc from "dayjs/plugin/utc"; +import relativeTime from "dayjs/plugin/relativeTime"; + +dayjs.extend(timezone); +dayjs.extend(utc); +dayjs.extend(relativeTime); + +dayjs.locale("zh-cn"); + +export function formatDatetime(date: string | Date | undefined | null, tz?: string): string { + if (!date) { + return ""; + } + return dayjs(date).tz(tz).format("YYYY-MM-DD HH:mm:ss"); +} + +export function toISOString(date: string | Date | undefined | null): string { + if (!date) { + return ""; + } + return dayjs(date).utc(false).toISOString(); +} + +export function toDatetimeLocal(date: string | Date | undefined | null, tz?: string): string { + if (!date) { + return ""; + } + // see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local#the_y10k_problem_often_client-side + return dayjs(date).tz(tz).format("YYYY-MM-DDTHH:mm"); +} + +export function toISODayEndOfTime(date: string | Date | undefined | null): string { + if (!date) { + return ""; + } + return dayjs(date).endOf("day").toISOString(); +} + +/** + * Get relative time to end date + * + * @param date end date + * @returns relative time to end date + * + * @example + * + * // now is 2020-12-01 + * RelativeTimeTo("2021-01-01") // in 1 month + */ +export function relativeTimeTo(date: string | Date | undefined | null) { + if (!date) { + return; + } + + return dayjs().to(dayjs(date)); +} diff --git a/console/src/utils/id.ts b/console/src/utils/id.ts new file mode 100644 index 0000000..8cfe5d7 --- /dev/null +++ b/console/src/utils/id.ts @@ -0,0 +1,7 @@ +export function randomUUID() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { + const r = (Math.random() * 16) | 0, + v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} diff --git a/console/src/views/MomentsList.vue b/console/src/views/MomentsList.vue new file mode 100644 index 0000000..1598022 --- /dev/null +++ b/console/src/views/MomentsList.vue @@ -0,0 +1,214 @@ + + + diff --git a/console/tsconfig.json b/console/tsconfig.json new file mode 100644 index 0000000..0950d46 --- /dev/null +++ b/console/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["./env.d.ts", "./src/**/*", "./src/**/*.vue"], + "exclude": ["./src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "types": ["unplugin-icons/types/vue"] + } +} diff --git a/console/uno.config.ts b/console/uno.config.ts new file mode 100644 index 0000000..7c46f74 --- /dev/null +++ b/console/uno.config.ts @@ -0,0 +1,7 @@ +import { defineConfig, presetWind3, transformerCompileClass } from "unocss"; + +export default defineConfig({ + presets: [presetWind3()], + transformers: [transformerCompileClass()], + blocklist: ["transform", "inline"], +}); diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..6845d83 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +version=1.0.1-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..ccebba7 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..171d876 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..79a61d4 --- /dev/null +++ b/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..6689b85 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/images/plugin-moments-preview.png b/images/plugin-moments-preview.png new file mode 100644 index 0000000..6d2ba19 Binary files /dev/null and b/images/plugin-moments-preview.png differ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..6255941 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + } +} +rootProject.name = 'plugin-moments' diff --git a/src/main/java/run/halo/moments/CommentNotificationReasonPublisher.java b/src/main/java/run/halo/moments/CommentNotificationReasonPublisher.java new file mode 100644 index 0000000..86fb3ef --- /dev/null +++ b/src/main/java/run/halo/moments/CommentNotificationReasonPublisher.java @@ -0,0 +1,148 @@ +package run.halo.moments; + +import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; + +import com.fasterxml.jackson.core.type.TypeReference; +import io.micrometer.common.util.StringUtils; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import lombok.Builder; +import lombok.RequiredArgsConstructor; +import org.jsoup.Jsoup; +import org.jsoup.safety.Safelist; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import run.halo.app.core.extension.content.Comment; +import run.halo.app.core.extension.notification.Reason; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.MetadataUtil; +import run.halo.app.extension.Ref; +import run.halo.app.infra.ExternalLinkProcessor; +import run.halo.app.infra.utils.JsonUtils; +import run.halo.app.notification.NotificationReasonEmitter; +import run.halo.app.notification.UserIdentity; +import run.halo.moments.event.MomentHasNewCommentEvent; + +/** + * Notification reason publisher for {@link Comment}. + * + * @author guqing + * @since 1.1.0 + */ +@Component +@RequiredArgsConstructor +public class CommentNotificationReasonPublisher { + private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()); + + public static final String NEW_COMMENT_ON_MOMENT = "new-comment-on-moment"; + public static final String NOTIFIED_ANNO = "moment.halo.run/notified"; + + private final ExtensionClient client; + private final NotificationReasonEmitter notificationReasonEmitter; + private final ExternalLinkProcessor externalLinkProcessor; + + /** + * On new comment. + */ + @Async + @EventListener(MomentHasNewCommentEvent.class) + public void onNewComment(MomentHasNewCommentEvent event) { + Comment comment = event.getComment(); + var annotations = MetadataUtil.nullSafeAnnotations(comment); + if (annotations.containsKey(NOTIFIED_ANNO)) { + return; + } + publishReasonBy(comment); + markAsNotified(comment.getMetadata().getName()); + } + + private void markAsNotified(String commentName) { + client.fetch(Comment.class, commentName).ifPresent(latestComment -> { + MetadataUtil.nullSafeAnnotations(latestComment).put(NOTIFIED_ANNO, "true"); + client.update(latestComment); + }); + } + + public void publishReasonBy(Comment comment) { + Ref subjectRef = comment.getSpec().getSubjectRef(); + var moment = client.fetch(Moment.class, subjectRef.getName()).orElseThrow(); + if (doNotEmitReason(comment, moment)) { + return; + } + + String momentUrl = + externalLinkProcessor.processLink("/moments/" + moment.getMetadata().getName()); + var reasonSubject = Reason.Subject.builder() + .apiVersion(moment.getApiVersion()) + .kind(moment.getKind()) + .title("瞬间:" + moment.getMetadata().getName()) + .name(subjectRef.getName()) + .url(momentUrl) + .build(); + + var momentContent = + defaultIfNull(moment.getSpec().getContent(), new Moment.MomentContent()); + var owner = comment.getSpec().getOwner(); + notificationReasonEmitter.emit(NEW_COMMENT_ON_MOMENT, + builder -> { + var attributes = CommentOnMomentReasonData.builder() + .momentName(moment.getMetadata().getName()) + .momentOwner(moment.getSpec().getOwner()) + .momentCreatedAt( + DEFAULT_DATE_FORMATTER.format(moment.getMetadata().getCreationTimestamp())) + .momentHtmlContent(cleanHtmlTag(momentContent.getHtml(), Safelist.basic())) + .momentRawContent(cleanHtmlTag(momentContent.getRaw(), Safelist.simpleText())) + .momentUrl(momentUrl) + .commenter(owner.getDisplayName()) + .content(comment.getSpec().getContent()) + .commentName(comment.getMetadata().getName()) + .build(); + builder.attributes(toAttributeMap(attributes)) + .author(identityFrom(owner)) + .subject(reasonSubject); + }).block(); + } + + static String cleanHtmlTag(String html, Safelist safelist) { + if (StringUtils.isBlank(html)) { + return ""; + } + return Jsoup.clean(html, safelist); + } + + static Map toAttributeMap(T data) { + Assert.notNull(data, "Reason attributes must not be null"); + return JsonUtils.mapper().convertValue(data, new TypeReference<>() { + }); + } + + static UserIdentity identityFrom(Comment.CommentOwner owner) { + if (Comment.CommentOwner.KIND_EMAIL.equals(owner.getKind())) { + return UserIdentity.anonymousWithEmail(owner.getName()); + } + return UserIdentity.of(owner.getName()); + } + + boolean doNotEmitReason(Comment comment, Moment moment) { + Comment.CommentOwner commentOwner = comment.getSpec().getOwner(); + String kind = commentOwner.getKind(); + String name = commentOwner.getName(); + var momentOwner = moment.getSpec().getOwner(); + if (Comment.CommentOwner.KIND_EMAIL.equals(kind)) { + return false; + } + return name.equals(momentOwner); + } + + @Builder + record CommentOnMomentReasonData(String momentName, String momentOwner, String momentCreatedAt, + String momentHtmlContent, String momentRawContent, + String momentUrl, String commenter, String content, + String commentName) { + } +} diff --git a/src/main/java/run/halo/moments/CommentReconciler.java b/src/main/java/run/halo/moments/CommentReconciler.java new file mode 100644 index 0000000..36ec568 --- /dev/null +++ b/src/main/java/run/halo/moments/CommentReconciler.java @@ -0,0 +1,63 @@ +package run.halo.moments; + +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import run.halo.app.core.extension.content.Comment; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.ExtensionUtil; +import run.halo.app.extension.GroupVersionKind; +import run.halo.app.extension.Ref; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.Reconciler; +import run.halo.moments.event.MomentHasNewCommentEvent; + +/** + * Reconciler for comment. + * + * @author guqing + * @since 1.1.0 + */ +@Component +@RequiredArgsConstructor +public class CommentReconciler implements Reconciler { + + private static final String FINALIZER = "moment.halo.run/finalizer"; + private final ExtensionClient client; + private final ApplicationEventPublisher eventPublisher; + + @Override + public Result reconcile(Request request) { + client.fetch(Comment.class, request.name()).ifPresent(comment -> { + if (comment.getMetadata().getDeletionTimestamp() != null) { + if (ExtensionUtil.removeFinalizers(comment.getMetadata(), Set.of(FINALIZER))) { + client.update(comment); + } + return; + } + + var forMoment = Ref.groupKindEquals(comment.getSpec().getSubjectRef(), + GroupVersionKind.fromExtension(Moment.class)); + if (!forMoment) { + return; + } + + if (ExtensionUtil.addFinalizers(comment.getMetadata(), Set.of(FINALIZER))) { + eventPublisher.publishEvent(new MomentHasNewCommentEvent(this, comment)); + client.update(comment); + } + }); + return null; + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Comment()) + // avoid triggering notification on startup for old comments + .syncAllOnStart(false) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/Contributor.java b/src/main/java/run/halo/moments/Contributor.java new file mode 100644 index 0000000..aca9bb5 --- /dev/null +++ b/src/main/java/run/halo/moments/Contributor.java @@ -0,0 +1,13 @@ +package run.halo.moments; + +import lombok.Data; + +/** + * @author LIlGG + */ +@Data +public class Contributor { + private String displayName; + private String avatar; + private String name; +} diff --git a/src/main/java/run/halo/moments/CustomEndpointsBuilder.java b/src/main/java/run/halo/moments/CustomEndpointsBuilder.java new file mode 100644 index 0000000..006e507 --- /dev/null +++ b/src/main/java/run/halo/moments/CustomEndpointsBuilder.java @@ -0,0 +1,42 @@ +package run.halo.moments; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerResponse; +import run.halo.app.core.extension.endpoint.CustomEndpoint; +import run.halo.app.extension.GroupVersion; + +public class CustomEndpointsBuilder { + + private final Map>> routerFunctionsMap; + + public CustomEndpointsBuilder() { + routerFunctionsMap = new HashMap<>(); + } + + public CustomEndpointsBuilder add(CustomEndpoint customEndpoint) { + routerFunctionsMap + .computeIfAbsent(customEndpoint.groupVersion(), gv -> new LinkedList<>()) + .add(customEndpoint.endpoint()); + return this; + } + + public RouterFunction build() { + SpringdocRouteBuilder routeBuilder = SpringdocRouteBuilder.route(); + routerFunctionsMap.forEach((gv, routerFunctions) -> { + routeBuilder.nest(RequestPredicates.path("/apis/" + gv), + () -> routerFunctions.stream().reduce(RouterFunction::and).orElse(null), + builder -> builder.operationId("CustomEndpoints") + .description("Custom Endpoint") + .tag(gv + "/CustomEndpoint") + ); + }); + routerFunctionsMap.clear(); + return routeBuilder.build(); + } +} diff --git a/src/main/java/run/halo/moments/ListedMoment.java b/src/main/java/run/halo/moments/ListedMoment.java new file mode 100644 index 0000000..2bc34e7 --- /dev/null +++ b/src/main/java/run/halo/moments/ListedMoment.java @@ -0,0 +1,25 @@ +package run.halo.moments; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +/** + * Listed moment. + * + * @author LIlGG + * @since 1.0.0 + */ +@Data +@Builder +public class ListedMoment { + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private Moment moment; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private Contributor owner; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private Stats stats; +} diff --git a/src/main/java/run/halo/moments/ModelConst.java b/src/main/java/run/halo/moments/ModelConst.java new file mode 100644 index 0000000..b56f126 --- /dev/null +++ b/src/main/java/run/halo/moments/ModelConst.java @@ -0,0 +1,14 @@ +package run.halo.moments; + +/** + * Static variable keys for view model. + * + * @author guqing + * @since 2.0.0 + */ +public enum ModelConst { + ; + public static final String TEMPLATE_ID = "_templateId"; + public static final Integer DEFAULT_PAGE_SIZE = 10; + public static final Integer SEARCH_DEFAULT_PAGE_SIZE = 200; +} diff --git a/src/main/java/run/halo/moments/Moment.java b/src/main/java/run/halo/moments/Moment.java new file mode 100644 index 0000000..3b21c68 --- /dev/null +++ b/src/main/java/run/halo/moments/Moment.java @@ -0,0 +1,126 @@ +package run.halo.moments; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.Instant; +import java.util.List; +import java.util.Set; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import run.halo.app.extension.AbstractExtension; +import run.halo.app.extension.GVK; + +@GVK(group = "moment.halo.run", version = "v1alpha1", kind = "Moment", + plural = "moments", singular = "moment") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class Moment extends AbstractExtension { + public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup"; + + @Schema(requiredMode = REQUIRED) + private MomentSpec spec; + + private Status status; + + @Data + public static class MomentSpec { + + @Schema(requiredMode = REQUIRED) + private MomentContent content; + + @Schema(description = "Release timestamp. This field can be customized by owner") + private Instant releaseTime; + + @Schema(description = "Visible indicates when to show publicly. Default is public", + defaultValue = "PUBLIC") + private MomentVisible visible; + + @Schema(requiredMode = REQUIRED, description = "Owner of the moment") + private String owner; + + @Schema(description = "Tags of the moment") + private Set tags; + + @Schema(defaultValue = "false") + private Boolean approved; + + private Instant approvedTime; + } + + @Data + @Schema(name = "MomentStatus") + public static class Status { + private long observedVersion; + + private String permalink; + } + + @Data + public static class MomentContent { + + @Schema(description = "Raw of content") + private String raw; + + @Schema(description = "Rendered result with HTML format") + private String html; + + @ArraySchema( + uniqueItems = true, + arraySchema = @Schema(description = "Medium of moment"), + schema = @Schema(description = "Media item of moment")) + private List medium; + } + + @Data + public static class MomentMedia { + + @Schema(description = "Type of media") + private MomentMediaType type; + + @Schema(description = "External URL of media") + private String url; + + @Schema(description = "Origin type of media.") + private String originType; + } + + public enum MomentMediaType { + PHOTO, + VIDEO, + POST, + AUDIO, + // TODO Might add more types here in the future + } + + public enum MomentVisible { + /** + * Public is default visible of moment. + */ + PUBLIC, + + /** + * Private visible is only for view for self. + */ + PRIVATE; + // TODO Might add more visibles here in the future. + + /** + * Convert value string to {@link MomentVisible}. + * + * @param value enum value string + * @return {@link MomentVisible} if found, otherwise null + */ + public static MomentVisible from(String value) { + for (MomentVisible visible : MomentVisible.values()) { + if (visible.name().equalsIgnoreCase(value)) { + return visible; + } + } + return null; + } + } +} diff --git a/src/main/java/run/halo/moments/MomentCommentSubject.java b/src/main/java/run/halo/moments/MomentCommentSubject.java new file mode 100644 index 0000000..d5768b2 --- /dev/null +++ b/src/main/java/run/halo/moments/MomentCommentSubject.java @@ -0,0 +1,55 @@ +package run.halo.moments; + +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.jsoup.Jsoup; +import org.jsoup.safety.Safelist; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import reactor.core.publisher.Mono; +import run.halo.app.content.comment.CommentSubject; +import run.halo.app.extension.GroupVersionKind; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.extension.Ref; +import run.halo.app.infra.ExternalLinkProcessor; + +/** + *

Comment subject for moment.

+ * This class helps to get comment subject by name when comment list query. + * + * @author guqing + * @since 1.0.2 + */ +@Component +@RequiredArgsConstructor +public class MomentCommentSubject implements CommentSubject { + + private final ReactiveExtensionClient client; + private final ExternalLinkProcessor externalLinkProcessor; + + @Override + public Mono get(String name) { + return client.fetch(Moment.class, name); + } + + @Override + public Mono getSubjectDisplay(String name) { + return get(name).map(moment -> { + var content = Optional.ofNullable(moment.getSpec().getContent()) + .map(Moment.MomentContent::getRaw) + .map(raw -> Jsoup.clean(raw, Safelist.none())) + .map(raw -> raw.length() > 100 ? raw.substring(0, 100) : raw) + .orElse(name); + var momentUrl = externalLinkProcessor.processLink("/moments/" + name); + return new SubjectDisplay(content, momentUrl, "瞬间"); + }); + } + + @Override + public boolean supports(Ref ref) { + Assert.notNull(ref, "Subject ref must not be null."); + GroupVersionKind groupVersionKind = + new GroupVersionKind(ref.getGroup(), ref.getVersion(), ref.getKind()); + return GroupVersionKind.fromExtension(Moment.class).equals(groupVersionKind); + } +} diff --git a/src/main/java/run/halo/moments/MomentEndpoint.java b/src/main/java/run/halo/moments/MomentEndpoint.java new file mode 100644 index 0000000..2cc350d --- /dev/null +++ b/src/main/java/run/halo/moments/MomentEndpoint.java @@ -0,0 +1,142 @@ +package run.halo.moments; + +import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; +import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; +import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; +import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import java.time.Instant; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.fn.builders.schema.Builder; +import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.endpoint.CustomEndpoint; +import run.halo.app.extension.GroupVersion; +import run.halo.app.extension.ListResult; +import run.halo.moments.service.MomentService; + +/** + * A custom endpoint for {@link run.halo.moments.Moment}. + * + * @author LIlGG + * @since 1.0.0 + */ +@Component +@AllArgsConstructor +public class MomentEndpoint implements CustomEndpoint { + + private final MomentService momentService; + + @Override + public RouterFunction endpoint() { + final var tag = "console.api.moment.halo.run/v1alpha1/Moment"; + return SpringdocRouteBuilder.route() + .GET("moments", this::listMoment, builder -> { + builder.operationId("ListMoments") + .description("List moments.") + .tag(tag) + .response(responseBuilder() + .implementation(ListResult.generateGenericClass(ListedMoment.class)) + ); + MomentQuery.buildParameters(builder); + }) + .GET("moments/{name}", this::getMoment, + builder -> builder.operationId("GetMoment") + .description("Get a moment by name.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.PATH) + .description("Moment name") + .required(true) + .implementation(String.class) + ) + .response(responseBuilder() + .implementation(ListedMoment.class) + )) + .GET("tags", this::listMyTags, + builder -> builder.operationId("ListTags") + .description("List all moment tags.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.QUERY) + .description("Tag name to query") + .required(false) + .implementation(String.class) + ) + .response(responseBuilder() + .implementationArray(String.class) + )) + .POST("moments", this::createMoment, + builder -> builder.operationId("CreateMoment") + .description("Create a Moment.") + .tag(tag) + .requestBody(requestBodyBuilder() + .required(true) + .content(contentBuilder() + .mediaType(MediaType.APPLICATION_JSON_VALUE) + .schema(Builder.schemaBuilder() + .implementation(Moment.class)) + )) + .response(responseBuilder() + .implementation(Moment.class)) + ) + .build(); + } + + private Mono getMoment(ServerRequest request) { + var name = request.pathVariable("name"); + return momentService.findMomentByName(name) + .flatMap(moment -> ServerResponse.ok().bodyValue(moment)); + } + + @Override + public GroupVersion groupVersion() { + return GroupVersion.parseAPIVersion("console.api.moment.halo.run/v1alpha1"); + } + + private Mono createMoment(ServerRequest serverRequest) { + return serverRequest.bodyToMono(Moment.class) + .map(moment -> { + moment.getSpec().setApproved(true); + moment.getSpec().setApprovedTime(Instant.now()); + return moment; + }) + .flatMap(momentService::create) + .flatMap(moment -> ServerResponse.ok().bodyValue(moment)); + } + + private Mono listMoment(ServerRequest serverRequest) { + MomentQuery query = new MomentQuery(serverRequest.exchange()); + return momentService.listMoment(query) + .flatMap(listedMoments -> ServerResponse.ok().bodyValue(listedMoments)); + } + + private Mono listMyTags(ServerRequest request) { + String name = request.queryParam("name").orElse(null); + return getCurrentUser() + .map(username -> new MomentQuery(request.exchange(), username)) + .flatMapMany(momentService::listAllTags) + .filter(tagName -> StringUtils.isBlank(name) || StringUtils.containsIgnoreCase(tagName, + name)) + .collectList() + .flatMap(result -> ServerResponse.ok().bodyValue(result)); + } + + private Mono getCurrentUser() { + return ReactiveSecurityContextHolder.getContext() + .map(SecurityContext::getAuthentication) + .map(Authentication::getName); + } +} diff --git a/src/main/java/run/halo/moments/MomentMigration.java b/src/main/java/run/halo/moments/MomentMigration.java new file mode 100644 index 0000000..06d7787 --- /dev/null +++ b/src/main/java/run/halo/moments/MomentMigration.java @@ -0,0 +1,49 @@ +package run.halo.moments; + +import static run.halo.app.extension.index.query.QueryFactory.and; +import static run.halo.app.extension.index.query.QueryFactory.isNull; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import run.halo.app.extension.DefaultExtensionMatcher; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.Reconciler; +import run.halo.app.extension.router.selector.FieldSelector; + +/** + *

Migration for 1.16.0, populate approved attribute for all moments before 1.16.0.

+ *

Note That: This migration is only for the moments that approved attribute is null.

+ */ +@Component +@RequiredArgsConstructor +public class MomentMigration implements Reconciler { + + private final ExtensionClient client; + + @Override + public Result reconcile(Request request) { + client.fetch(Moment.class, request.name()).ifPresent(moment -> { + moment.getSpec().setApproved(true); + moment.getSpec().setApprovedTime(moment.getMetadata().getCreationTimestamp()); + client.update(moment); + }); + return Result.doNotRetry(); + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + final var moment = new Moment(); + return builder + .extension(moment) + .onAddMatcher(DefaultExtensionMatcher.builder(client, moment.groupVersionKind()) + .fieldSelector(FieldSelector.of( + and(isNull("spec.approved"), + isNull("metadata.deletionTimestamp")) + )) + .build() + ) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/MomentQuery.java b/src/main/java/run/halo/moments/MomentQuery.java new file mode 100644 index 0000000..4271152 --- /dev/null +++ b/src/main/java/run/halo/moments/MomentQuery.java @@ -0,0 +1,200 @@ +package run.halo.moments; + +import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; +import static run.halo.app.extension.index.query.QueryFactory.all; +import static run.halo.app.extension.index.query.QueryFactory.and; +import static run.halo.app.extension.index.query.QueryFactory.contains; +import static run.halo.app.extension.index.query.QueryFactory.equal; +import static run.halo.app.extension.index.query.QueryFactory.greaterThanOrEqual; +import static run.halo.app.extension.index.query.QueryFactory.lessThanOrEqual; +import static run.halo.app.extension.router.QueryParamBuildUtil.sortParameter; +import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions; + +import java.time.Instant; + +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.fn.builders.operation.Builder; +import org.springframework.data.domain.Sort; +import org.springframework.lang.Nullable; +import org.springframework.util.MultiValueMap; +import org.springframework.web.server.ServerWebExchange; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import run.halo.app.extension.ListOptions; +import run.halo.app.extension.PageRequest; +import run.halo.app.extension.PageRequestImpl; +import run.halo.app.extension.router.IListRequest; +import run.halo.app.extension.router.SortableRequest; +import run.halo.app.extension.router.selector.FieldSelector; + +/** + * A query object for {@link Moment} list. + * + * @author LIlGG + * @author guqing + * @since 1.0.0 + */ +public class MomentQuery extends SortableRequest { + private final MultiValueMap queryParams; + + private String username; + + public MomentQuery(ServerWebExchange exchange) { + super(exchange); + this.queryParams = exchange.getRequest().getQueryParams(); + } + + public MomentQuery(ServerWebExchange exchange, String username) { + this(exchange); + this.username = username; + } + + @Nullable + @Schema(description = "Moments filtered by keyword.") + public String getKeyword() { + return StringUtils.defaultIfBlank(queryParams.getFirst("keyword"), null); + } + + @Schema(description = "Owner name.") + public String getOwnerName() { + if (StringUtils.isNotBlank(username)) { + return username; + } + String ownerName = queryParams.getFirst("ownerName"); + return StringUtils.isBlank(ownerName) ? null : ownerName; + } + + @Schema(description = "Moment tag.") + public String getTag() { + return StringUtils.defaultIfBlank(queryParams.getFirst("tag"), null); + } + + @Nullable + public Moment.MomentVisible getVisible() { + String visible = queryParams.getFirst("visible"); + return Moment.MomentVisible.from(visible); + } + + @Schema + public Instant getStartDate() { + String startDate = queryParams.getFirst("startDate"); + return convertInstantOrNull(startDate); + } + + @Schema + public Instant getEndDate() { + String endDate = queryParams.getFirst("endDate"); + return convertInstantOrNull(endDate); + } + + /** + * Build {@link ListOptions} from query params. + * + * @return a list options. + */ + public ListOptions toListOptions() { + var listOptions = + labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector()); + var query = all(); + if (StringUtils.isNotBlank(getOwnerName())) { + query = and(query, equal("spec.owner", getOwnerName())); + } + if (StringUtils.isNotBlank(getTag())) { + query = and(query, equal("spec.tags", getTag())); + } + if (getVisible() != null) { + query = and(query, equal("spec.visible", getVisible().name())); + } + + if (getApproved() != null) { + query = and(query, equal("spec.approved", Boolean.toString(getApproved()))); + } + + if (getStartDate() != null) { + query = and(query, greaterThanOrEqual("spec.releaseTime", getStartDate().toString())); + } + if (getEndDate() != null) { + query = and(query, lessThanOrEqual("spec.releaseTime", getEndDate().toString())); + } + + if (listOptions.getFieldSelector() != null) { + query = and(query, listOptions.getFieldSelector().query()); + } + if (StringUtils.isNotBlank(getKeyword())) { + query = and(query, contains("spec.owner", getKeyword())); + } + listOptions.setFieldSelector(FieldSelector.of(query)); + return listOptions; + } + + public PageRequest toPageRequest() { + var sort = getSort(); + if (sort.isUnsorted()) { + sort = Sort.by("spec.releaseTime").descending(); + } + return PageRequestImpl.of(getPage(), getSize(), sort); + } + + @Schema(description = "moment approved.") + public Boolean getApproved() { + return convertBooleanOrNull(queryParams.getFirst("approved")); + } + + private Boolean convertBooleanOrNull(String value) { + return StringUtils.isBlank(value) ? null : Boolean.parseBoolean(value); + } + + private Instant convertInstantOrNull(String timeStr) { + return StringUtils.isBlank(timeStr) ? null : Instant.parse(timeStr); + } + + public static void buildParameters(Builder builder) { + IListRequest.buildParameters(builder); + builder.parameter(sortParameter()) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("keyword") + .description("Moments filtered by keyword.") + .implementation(String.class) + .required(false)) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("ownerName") + .description("Owner name.") + .implementation(String.class) + .required(false)) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("tag") + .description("Moment tag.") + .implementation(String.class) + .required(false)) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("visible") + .description("Moment visible.") + .implementation(Moment.MomentVisible.class) + .required(false)) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("startDate") + .implementation(Instant.class) + .description("Moment start date.") + .required(false)) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("endDate") + .implementation(Instant.class) + .description("Moment end date.") + .required(false)) + .parameter(parameterBuilder() + .in(ParameterIn.QUERY) + .name("approved") + .description("Moment approved.") + .implementation(Boolean.class) + .required(false)) + ; + } + +} diff --git a/src/main/java/run/halo/moments/MomentReconciler.java b/src/main/java/run/halo/moments/MomentReconciler.java new file mode 100644 index 0000000..a965a96 --- /dev/null +++ b/src/main/java/run/halo/moments/MomentReconciler.java @@ -0,0 +1,95 @@ +package run.halo.moments; + +import static run.halo.app.extension.index.query.QueryFactory.equal; + +import java.time.Instant; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import run.halo.app.core.extension.notification.Subscription; +import run.halo.app.extension.DefaultExtensionMatcher; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.ExtensionUtil; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.Reconciler; +import run.halo.app.extension.router.selector.FieldSelector; +import run.halo.app.notification.NotificationCenter; +import run.halo.moments.event.MomentDeletedEvent; +import run.halo.moments.event.MomentUpdatedEvent; + +/** + * {@link Reconciler} for {@link Moment}. + * + * @author guqing + * @since 1.1.0 + */ +@Component +@RequiredArgsConstructor +public class MomentReconciler implements Reconciler { + + private static final String FINALIZER = "moment-protection"; + private final ExtensionClient client; + private final NotificationCenter notificationCenter; + private final ApplicationEventPublisher eventPublisher; + + @Override + public Result reconcile(Request request) { + client.fetch(Moment.class, request.name()).ifPresent(moment -> { + if (ExtensionUtil.isDeleted(moment)) { + if (ExtensionUtil.removeFinalizers(moment.getMetadata(), Set.of(FINALIZER))) { + client.update(moment); + eventPublisher.publishEvent(new MomentDeletedEvent(this, request.name())); + } + return; + } + if (ExtensionUtil.addFinalizers(moment.getMetadata(), Set.of(FINALIZER))) { + // auto subscribe to new comment on moment + createCommentSubscriptionForMoment(moment); + } + var status = moment.getStatus(); + if (status == null) { + status = new Moment.Status(); + moment.setStatus(status); + } + status.setObservedVersion(moment.getMetadata().getVersion() + 1); + // add approved marks to the old data by default. + if (moment.getSpec().getApproved() == null) { + moment.getSpec().setApproved(true); + } + if (moment.getSpec().getApproved() && moment.getSpec().getApprovedTime() == null) { + moment.getSpec().setApprovedTime(Instant.now()); + } + client.update(moment); + + eventPublisher.publishEvent(new MomentUpdatedEvent(this, request.name())); + }); + return Result.doNotRetry(); + } + + void createCommentSubscriptionForMoment(Moment moment) { + var owner = moment.getSpec().getOwner(); + var interestReason = new Subscription.InterestReason(); + interestReason.setReasonType("new-comment-on-moment"); + interestReason.setExpression("props.momentOwner == '%s'".formatted(owner)); + var subscriber = new Subscription.Subscriber(); + subscriber.setName(owner); + notificationCenter.subscribe(subscriber, interestReason).block(); + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + final var moment = new Moment(); + return builder + .extension(moment) + .workerCount(5) + .onAddMatcher(DefaultExtensionMatcher.builder(client, moment.groupVersionKind()) + .fieldSelector( + FieldSelector.of(equal(Moment.REQUIRE_SYNC_ON_STARTUP_INDEX_NAME, "true")) + ) + .build() + ) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/MomentRouter.java b/src/main/java/run/halo/moments/MomentRouter.java new file mode 100644 index 0000000..33c08db --- /dev/null +++ b/src/main/java/run/halo/moments/MomentRouter.java @@ -0,0 +1,115 @@ +package run.halo.moments; + +import static org.springframework.web.reactive.function.server.RequestPredicates.GET; +import static org.springframework.web.reactive.function.server.RouterFunctions.route; +import static run.halo.app.theme.router.PageUrlUtils.totalPage; + +import java.util.Map; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.HandlerFunction; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; +import run.halo.app.plugin.ReactiveSettingFetcher; +import run.halo.app.theme.router.PageUrlUtils; +import run.halo.app.theme.router.UrlContextListResult; +import run.halo.moments.finders.MomentFinder; +import run.halo.moments.vo.MomentVo; + + +/** + * Provides a /moments route for the topic end to handle routing. + * Topic should contain a moments.html file. + *

+ * In order to handle pagination, an additional /moments/page/{page} route has been adapted. + *

+ * + * @author LIlGG + * @since 1.0.0 + */ +@Component +@RequiredArgsConstructor +public class MomentRouter { + private static final String TAG_PARAM = "tag"; + private final MomentFinder momentFinder; + + private final ReactiveSettingFetcher settingFetcher; + + @Bean + RouterFunction momentRouterFunction() { + return route(GET("/moments").or(GET("/moments/page/{page:\\d+}")), handlerFunction()) + .andRoute(GET("/moments/{momentName:\\S+}"), handlerMomentDefault()); + } + + private HandlerFunction handlerMomentDefault() { + return request -> { + String momentName = request.pathVariable("momentName"); + return ServerResponse.ok().render("moment", + Map.of("moment", momentFinder.get(momentName), + ModelConst.TEMPLATE_ID, "moment", + "title", getMomentTitle()) + ); + }; + } + + private HandlerFunction handlerFunction() { + return request -> ServerResponse.ok().render("moments", + Map.of("moments", momentList(request), + ModelConst.TEMPLATE_ID, "moments", + "tags", momentFinder.listAllTags(), + "title", getMomentTitle() + ) + ); + } + + Mono getMomentTitle() { + return this.settingFetcher.get("base") + .map(setting -> setting.get("title").asText("瞬间")) + .defaultIfEmpty("瞬间"); + } + + private Mono> momentList(ServerRequest request) { + String path = request.path(); + String tagVal = request.queryParam(TAG_PARAM) + .filter(StringUtils::isNotBlank) + .orElse(null); + int pageNum = pageNumInPathVariable(request); + String tag = tagPathQueryParam(request); + return this.settingFetcher.get("base") + .map(item -> item.get("pageSize").asInt(10)) + .defaultIfEmpty(10) + .flatMap(pageSize -> momentFinder.listByTag(pageNum, pageSize, tag) + .map(list -> new UrlContextListResult.Builder() + .listResult(list) + .nextUrl(appendTagParamIfPresent( + PageUrlUtils.nextPageUrl(path, totalPage(list)), tagVal) + ) + .prevUrl(appendTagParamIfPresent(PageUrlUtils.prevPageUrl(path), tagVal)) + .build() + ) + ); + } + + String appendTagParamIfPresent(String uriString, String tagValue) { + return UriComponentsBuilder.fromUriString(uriString) + .queryParamIfPresent(TAG_PARAM, Optional.ofNullable(tagValue)) + .build() + .toString(); + } + + private int pageNumInPathVariable(ServerRequest request) { + String page = request.pathVariables().get("page"); + return NumberUtils.toInt(page, 1); + } + + private String tagPathQueryParam(ServerRequest request) { + return request.queryParam(TAG_PARAM).orElse(null); + } +} diff --git a/src/main/java/run/halo/moments/MomentsPlugin.java b/src/main/java/run/halo/moments/MomentsPlugin.java new file mode 100644 index 0000000..65d5939 --- /dev/null +++ b/src/main/java/run/halo/moments/MomentsPlugin.java @@ -0,0 +1,87 @@ +package run.halo.moments; + +import static run.halo.app.extension.index.IndexAttributeFactory.multiValueAttribute; +import static run.halo.app.extension.index.IndexAttributeFactory.simpleAttribute; + +import java.util.Optional; +import java.util.Set; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import run.halo.app.extension.Scheme; +import run.halo.app.extension.SchemeManager; +import run.halo.app.extension.index.IndexSpec; +import run.halo.app.plugin.BasePlugin; +import run.halo.app.plugin.PluginContext; + +@Component +public class MomentsPlugin extends BasePlugin { + + private final SchemeManager schemeManager; + private final ApplicationEventPublisher eventPublisher; + + public MomentsPlugin(PluginContext pluginContext, SchemeManager schemeManager, + ApplicationEventPublisher eventPublisher) { + super(pluginContext); + this.schemeManager = schemeManager; + this.eventPublisher = eventPublisher; + } + + @Override + public void start() { + schemeManager.register(Moment.class, indexSpecs -> { + indexSpecs.add(new IndexSpec() + .setName("spec.tags") + .setIndexFunc(multiValueAttribute(Moment.class, moment -> { + var tags = moment.getSpec().getTags(); + return tags == null ? Set.of() : tags; + })) + ); + indexSpecs.add(new IndexSpec() + .setName("spec.owner") + .setIndexFunc( + simpleAttribute(Moment.class, moment -> moment.getSpec().getOwner()))); + indexSpecs.add(new IndexSpec() + .setName("spec.releaseTime") + .setIndexFunc(simpleAttribute(Moment.class, moment -> { + var releaseTime = moment.getSpec().getReleaseTime(); + return releaseTime == null ? null : releaseTime.toString(); + })) + ); + + indexSpecs.add(new IndexSpec() + .setName("spec.visible") + .setIndexFunc(simpleAttribute(Moment.class, moment -> { + var visible = moment.getSpec().getVisible(); + return visible == null ? null : visible.toString(); + })) + ); + indexSpecs.add(new IndexSpec() + .setName("spec.approved") + .setIndexFunc(simpleAttribute(Moment.class, moment -> { + var approved = moment.getSpec().getApproved(); + return approved == null ? null : approved.toString(); + })) + ); + + indexSpecs.add(new IndexSpec() + .setName(Moment.REQUIRE_SYNC_ON_STARTUP_INDEX_NAME) + .setIndexFunc(simpleAttribute(Moment.class, moment -> { + var observedVersion = Optional.ofNullable(moment.getStatus()) + .map(Moment.Status::getObservedVersion) + .orElse(-1L); + if (observedVersion < moment.getMetadata().getVersion()) { + return BooleanUtils.TRUE; + } + // don't care about the false case + return null; + }))); + }); + eventPublisher.publishEvent(new SchemeRegistered(this)); + } + + @Override + public void stop() { + schemeManager.unregister(Scheme.buildFromType(Moment.class)); + } +} diff --git a/src/main/java/run/halo/moments/SchemeRegistered.java b/src/main/java/run/halo/moments/SchemeRegistered.java new file mode 100644 index 0000000..8a60d2f --- /dev/null +++ b/src/main/java/run/halo/moments/SchemeRegistered.java @@ -0,0 +1,9 @@ +package run.halo.moments; + +import org.springframework.context.ApplicationEvent; + +public class SchemeRegistered extends ApplicationEvent { + public SchemeRegistered(Object source) { + super(source); + } +} diff --git a/src/main/java/run/halo/moments/Stats.java b/src/main/java/run/halo/moments/Stats.java new file mode 100644 index 0000000..5911530 --- /dev/null +++ b/src/main/java/run/halo/moments/Stats.java @@ -0,0 +1,29 @@ +package run.halo.moments; + +import lombok.Builder; +import lombok.Value; + +/** + * Stats of moment. + * + * @author LIlGG + * @since 1.0.0 + */ +@Value +@Builder +public class Stats { + + Integer upvote; + + Integer totalComment; + + Integer approvedComment; + + public static Stats empty() { + return Stats.builder() + .upvote(0) + .totalComment(0) + .approvedComment(0) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/SubscriptionMigration.java b/src/main/java/run/halo/moments/SubscriptionMigration.java new file mode 100644 index 0000000..225bcc3 --- /dev/null +++ b/src/main/java/run/halo/moments/SubscriptionMigration.java @@ -0,0 +1,131 @@ +package run.halo.moments; + +import static run.halo.app.extension.index.query.QueryFactory.and; +import static run.halo.app.extension.index.query.QueryFactory.equal; +import static run.halo.app.extension.index.query.QueryFactory.isNull; + +import java.time.Duration; +import java.time.Instant; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.domain.Sort; +import org.springframework.lang.NonNull; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.retry.Retry; +import run.halo.app.core.extension.User; +import run.halo.app.core.extension.notification.Subscription; +import run.halo.app.extension.Extension; +import run.halo.app.extension.ListOptions; +import run.halo.app.extension.PageRequest; +import run.halo.app.extension.PageRequestImpl; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.extension.router.selector.FieldSelector; +import run.halo.app.notification.NotificationCenter; + +/** + * Subscription migration to adapt to the new expression subscribe mechanism. + * + * @author guqing + * @since 1.7.0 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SubscriptionMigration implements ApplicationListener { + private final NotificationCenter notificationCenter; + private final ReactiveExtensionClient client; + static final String NEW_COMMENT_ON_MOMENT = "new-comment-on-moment"; + + @Async + @Override + public void onApplicationEvent(@NonNull SchemeRegistered event) { + var listOptions = new ListOptions(); + var query = isNull("metadata.deletionTimestamp"); + listOptions.setFieldSelector(FieldSelector.of(query)); + client.listAll(User.class, listOptions, Sort.unsorted()) + .flatMap(user -> removeInternalSubscriptionForUser(user.getMetadata().getName())) + .then() + .doOnSuccess(unused -> log.info("Cleanup user moment subscription completed")) + .block(); + } + + private Mono removeInternalSubscriptionForUser(String username) { + log.debug("Start to collating moment subscription for user: {}", username); + var subscriber = new Subscription.Subscriber(); + subscriber.setName(username); + + var listOptions = new ListOptions(); + var fieldQuery = and(isNull("metadata.deletionTimestamp"), + equal("spec.subscriber", subscriber.toString()), + equal("spec.reason.reasonType", NEW_COMMENT_ON_MOMENT) + ); + listOptions.setFieldSelector(FieldSelector.of(fieldQuery)); + + return deleteInitialBatch(Subscription.class, listOptions) + .map(subscription -> subscription.getSpec().getSubscriber().getName()) + .distinct() + .flatMap(this::createMomentCommentSubscription) + .then() + .doOnSuccess(unused -> + log.debug("Collating moment subscription for user: {} completed", username)); + } + + Mono createMomentCommentSubscription(String name) { + var interestReason = new Subscription.InterestReason(); + interestReason.setReasonType(NEW_COMMENT_ON_MOMENT); + interestReason.setExpression("props.momentOwner == '%s'".formatted(name)); + var subscriber = new Subscription.Subscriber(); + subscriber.setName(name); + log.debug("Create subscription for user: {} with reasonType: {}", name, + NEW_COMMENT_ON_MOMENT); + return notificationCenter.subscribe(subscriber, interestReason).then(); + } + + public Flux deleteInitialBatch(Class type, + ListOptions listOptions) { + var pageRequest = createPageRequest(); + var newFieldQuery = listOptions.getFieldSelector() + .andQuery(isNull("metadata.deletionTimestamp")); + listOptions.setFieldSelector(newFieldQuery); + final Instant now = Instant.now(); + + return client.listBy(type, listOptions, pageRequest) + // forever loop first page until no more to delete + .expand(result -> result.hasNext() + ? client.listBy(type, listOptions, pageRequest) : Mono.empty()) + .flatMap(result -> Flux.fromIterable(result.getItems())) + .takeWhile(item -> shouldTakeNext(item, now)) + .flatMap(this::deleteWithRetry); + } + + @SuppressWarnings("unchecked") + Mono deleteWithRetry(E item) { + return client.delete(item) + .onErrorResume(OptimisticLockingFailureException.class, + e -> attemptToDelete((Class) item.getClass(), item.getMetadata().getName())); + } + + private Mono attemptToDelete(Class type, String name) { + return Mono.defer(() -> client.fetch(type, name) + .flatMap(client::delete) + ) + .retryWhen(Retry.backoff(8, Duration.ofMillis(100)) + .filter(OptimisticLockingFailureException.class::isInstance)); + } + + static boolean shouldTakeNext(E item, Instant now) { + var creationTimestamp = item.getMetadata().getCreationTimestamp(); + return creationTimestamp.isBefore(now) + || creationTimestamp.equals(now); + } + + private PageRequest createPageRequest() { + return PageRequestImpl.of(1, 200, + Sort.by("metadata.creationTimestamp", "metadata.name")); + } +} diff --git a/src/main/java/run/halo/moments/TagReconciler.java b/src/main/java/run/halo/moments/TagReconciler.java new file mode 100644 index 0000000..237cfcd --- /dev/null +++ b/src/main/java/run/halo/moments/TagReconciler.java @@ -0,0 +1,45 @@ +package run.halo.moments; + + +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.ExtensionUtil; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.Reconciler; + +/** + * Compatible with the {@link TagReconciler#TAG_FINALIZER} added in old data to avoid the + * problem of data not being able to be deleted due to uncleared + * {@link TagReconciler#TAG_FINALIZER}. + */ +@Deprecated(forRemoval = true, since = "1.5.1") +@Component +@RequiredArgsConstructor +public class TagReconciler implements Reconciler { + + private static final String TAG_FINALIZER = "tag-moment-protection"; + private final ExtensionClient client; + + @Override + public Result reconcile(Request request) { + client.fetch(Moment.class, request.name()).ifPresent(moment -> { + if (ExtensionUtil.isDeleted(moment)) { + if (ExtensionUtil.removeFinalizers(moment.getMetadata(), Set.of(TAG_FINALIZER))) { + client.update(moment); + } + } + }); + return Result.doNotRetry(); + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + final var moment = new Moment(); + return builder + .extension(moment) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/event/MomentDeletedEvent.java b/src/main/java/run/halo/moments/event/MomentDeletedEvent.java new file mode 100644 index 0000000..608b27b --- /dev/null +++ b/src/main/java/run/halo/moments/event/MomentDeletedEvent.java @@ -0,0 +1,14 @@ +package run.halo.moments.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class MomentDeletedEvent extends ApplicationEvent { + private final String momentName; + + public MomentDeletedEvent(Object source, String momentName) { + super(source); + this.momentName = momentName; + } +} diff --git a/src/main/java/run/halo/moments/event/MomentHasNewCommentEvent.java b/src/main/java/run/halo/moments/event/MomentHasNewCommentEvent.java new file mode 100644 index 0000000..1a7adcf --- /dev/null +++ b/src/main/java/run/halo/moments/event/MomentHasNewCommentEvent.java @@ -0,0 +1,22 @@ +package run.halo.moments.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; +import run.halo.app.core.extension.content.Comment; + +/** + * Event for moment has new comment. + * + * @author guqing + * @since 1.1.0 + */ +@Getter +public class MomentHasNewCommentEvent extends ApplicationEvent { + + private final Comment comment; + + public MomentHasNewCommentEvent(Object source, Comment comment) { + super(source); + this.comment = comment; + } +} diff --git a/src/main/java/run/halo/moments/event/MomentUpdatedEvent.java b/src/main/java/run/halo/moments/event/MomentUpdatedEvent.java new file mode 100644 index 0000000..35fa833 --- /dev/null +++ b/src/main/java/run/halo/moments/event/MomentUpdatedEvent.java @@ -0,0 +1,14 @@ +package run.halo.moments.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class MomentUpdatedEvent extends ApplicationEvent { + private final String momentName; + + public MomentUpdatedEvent(Object source, String momentName) { + super(source); + this.momentName = momentName; + } +} diff --git a/src/main/java/run/halo/moments/exception/NotFoundException.java b/src/main/java/run/halo/moments/exception/NotFoundException.java new file mode 100644 index 0000000..08caa50 --- /dev/null +++ b/src/main/java/run/halo/moments/exception/NotFoundException.java @@ -0,0 +1,15 @@ +package run.halo.moments.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; + +/** + * NotFoundException. + * + * @author LIlGG + */ +public class NotFoundException extends ResponseStatusException { + public NotFoundException(String reason) { + super(HttpStatus.NOT_FOUND, reason); + } +} diff --git a/src/main/java/run/halo/moments/finders/MomentFinder.java b/src/main/java/run/halo/moments/finders/MomentFinder.java new file mode 100644 index 0000000..6fd3f1d --- /dev/null +++ b/src/main/java/run/halo/moments/finders/MomentFinder.java @@ -0,0 +1,47 @@ +package run.halo.moments.finders; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import run.halo.app.extension.ListResult; +import run.halo.moments.vo.MomentTagVo; +import run.halo.moments.vo.MomentVo; + + +/** + * A finder for {@link run.halo.moments.Moment}. + * + * @author LIlGG + * @since 1.0.0 + */ +public interface MomentFinder { + + /** + * List all moments. + * + * @return a flux of moment vo. + */ + Flux listAll(); + + /** + * List moments by page. + * + * @param page page number. + * @param size page size. + * @return a mono of list result. + */ + Mono> list(Integer page, Integer size); + + /** + * List moments by tag. + * + * @param tag tag name. + * @return a flux of moment vo. + */ + Flux listBy(String tag); + + Mono get(String momentName); + + Flux listAllTags(); + + Mono> listByTag(int pageNum, Integer pageSize, String tagName); +} diff --git a/src/main/java/run/halo/moments/finders/impl/MomentFinderImpl.java b/src/main/java/run/halo/moments/finders/impl/MomentFinderImpl.java new file mode 100644 index 0000000..8025305 --- /dev/null +++ b/src/main/java/run/halo/moments/finders/impl/MomentFinderImpl.java @@ -0,0 +1,191 @@ +package run.halo.moments.finders.impl; + +import static run.halo.app.extension.index.query.QueryFactory.all; +import static run.halo.app.extension.index.query.QueryFactory.and; +import static run.halo.app.extension.index.query.QueryFactory.equal; + +import jakarta.annotation.Nonnull; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.domain.Sort; +import org.springframework.web.util.UriUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.Counter; +import run.halo.app.core.extension.User; +import run.halo.app.extension.ExtensionUtil; +import run.halo.app.extension.ListOptions; +import run.halo.app.extension.ListResult; +import run.halo.app.extension.PageRequest; +import run.halo.app.extension.PageRequestImpl; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.extension.index.query.Query; +import run.halo.app.extension.router.selector.FieldSelector; +import run.halo.app.theme.finders.Finder; +import run.halo.moments.Moment; +import run.halo.moments.Stats; +import run.halo.moments.finders.MomentFinder; +import run.halo.moments.util.MeterUtils; +import run.halo.moments.vo.ContributorVo; +import run.halo.moments.vo.MomentTagVo; +import run.halo.moments.vo.MomentVo; + +/** + * A default implementation for {@link MomentFinder}. + * + * @author LIlGG + * @since 1.0.0 + */ +@Finder("momentFinder") +@RequiredArgsConstructor +public class MomentFinderImpl implements MomentFinder { + + public static final Predicate FIXED_PREDICATE = moment -> Objects.equals( + moment.getSpec().getVisible(), Moment.MomentVisible.PUBLIC) + && moment.getSpec().getApproved() == Boolean.TRUE; + + public static final Query FIXED_QUERY = and( + equal("spec.visible", Moment.MomentVisible.PUBLIC.name()), + equal("spec.approved", Boolean.TRUE.toString()) + ); + + private final ReactiveExtensionClient client; + + @Override + public Flux listAll() { + var listOptions = new ListOptions(); + listOptions.setFieldSelector( + FieldSelector.of(FIXED_QUERY)); + return client.listAll(Moment.class, listOptions, defaultSort()) + .concatMap(this::getMomentVo); + } + + @Override + public Mono> list(Integer page, Integer size) { + var pageRequest = PageRequestImpl.of(pageNullSafe(page), sizeNullSafe(size), defaultSort()); + return pageMoment(null, pageRequest); + } + + static Sort defaultSort() { + return Sort.by("spec.releaseTime").descending() + .and(ExtensionUtil.defaultSort()); + } + + @Override + public Flux listBy(String tag) { + var listOptions = new ListOptions(); + var query = and(FIXED_QUERY, equal("spec.tags", tag)); + listOptions.setFieldSelector(FieldSelector.of(query)); + return client.listAll(Moment.class, listOptions, defaultSort()) + .concatMap(this::getMomentVo); + } + + @Override + public Mono get(String momentName) { + return client.get(Moment.class, momentName) + .filter(FIXED_PREDICATE) + .flatMap(this::getMomentVo); + } + + @Override + public Flux listAllTags() { + var listOptions = new ListOptions(); + var query = and(all("spec.tags"), FIXED_QUERY); + listOptions.setFieldSelector(FieldSelector.of(query)); + return client.listAll(Moment.class, listOptions, defaultSort()) + .flatMapIterable(moment -> { + var tags = moment.getSpec().getTags(); + if (tags == null) { + return List.of(); + } + return tags.stream() + .map(tag -> new MomentTagPair(tag, moment.getMetadata().getName())) + .toList(); + }) + .groupBy(MomentTagPair::tagName) + .concatMap(groupedFlux -> groupedFlux.count() + .defaultIfEmpty(0L) + .map(count -> MomentTagVo.builder() + .name(groupedFlux.key()) + .momentCount(count.intValue()) + .permalink("/moments?tag=" + UriUtils.encode(groupedFlux.key(), + StandardCharsets.UTF_8)) + .build() + ) + ); + } + + record MomentTagPair(String tagName, String momentName) { + } + + @Override + public Mono> listByTag(int pageNum, Integer pageSize, String tagName) { + var query = all(); + if (StringUtils.isNoneBlank(tagName)) { + query = and(query, equal("spec.tags", tagName)); + } + var pageRequest = + PageRequestImpl.of(pageNullSafe(pageNum), sizeNullSafe(pageSize), defaultSort()); + return pageMoment(FieldSelector.of(query), pageRequest); + } + + private Mono> pageMoment(FieldSelector fieldSelector, PageRequest page) { + var listOptions = new ListOptions(); + var query = FIXED_QUERY; + if (fieldSelector != null) { + query = and(query, fieldSelector.query()); + } + listOptions.setFieldSelector(FieldSelector.of(query)); + return client.listBy(Moment.class, listOptions, page) + .flatMap(list -> Flux.fromStream(list.get()) + .concatMap(this::getMomentVo) + .collectList() + .map(momentVos -> new ListResult<>(list.getPage(), list.getSize(), + list.getTotal(), momentVos) + ) + ) + .defaultIfEmpty( + new ListResult<>(page.getPageNumber(), page.getPageSize(), 0L, List.of())); + } + + private Mono getMomentVo(@Nonnull Moment moment) { + MomentVo momentVo = MomentVo.from(moment); + return Mono.just(momentVo) + .flatMap(mv -> populateStats(momentVo) + .doOnNext(mv::setStats) + .thenReturn(mv) + ) + .flatMap(mv -> { + String owner = mv.getSpec().getOwner(); + return client.fetch(User.class, owner) + .map(ContributorVo::from) + .doOnNext(mv::setOwner) + .thenReturn(mv); + }) + .defaultIfEmpty(momentVo); + } + + private Mono populateStats(MomentVo momentVo) { + String name = momentVo.getMetadata().getName(); + return client.fetch(Counter.class, MeterUtils.nameOf(Moment.class, name)) + .map(counter -> Stats.builder() + .upvote(counter.getUpvote()) + .totalComment(counter.getTotalComment()) + .approvedComment(counter.getApprovedComment()) + .build()) + .defaultIfEmpty(Stats.empty()); + } + + int pageNullSafe(Integer page) { + return ObjectUtils.defaultIfNull(page, 1); + } + + int sizeNullSafe(Integer size) { + return ObjectUtils.defaultIfNull(size, 10); + } +} diff --git a/src/main/java/run/halo/moments/rss/MomentRssProvider.java b/src/main/java/run/halo/moments/rss/MomentRssProvider.java new file mode 100644 index 0000000..0faeee6 --- /dev/null +++ b/src/main/java/run/halo/moments/rss/MomentRssProvider.java @@ -0,0 +1,200 @@ +package run.halo.moments.rss; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Element; +import org.springframework.lang.NonNull; +import org.springframework.util.CollectionUtils; +import org.springframework.web.reactive.function.server.ServerRequest; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import run.halo.app.core.attachment.ThumbnailSize; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.infra.ExternalLinkProcessor; +import run.halo.app.infra.ExternalUrlSupplier; +import run.halo.app.infra.SystemInfoGetter; +import run.halo.app.plugin.ReactiveSettingFetcher; +import run.halo.feed.RSS2; +import run.halo.feed.RssRouteItem; +import run.halo.moments.Moment; +import run.halo.moments.finders.MomentFinder; +import run.halo.moments.vo.MomentVo; + +@RequiredArgsConstructor +public class MomentRssProvider implements RssRouteItem { + private final ExternalUrlSupplier externalUrlSupplier; + private final ExternalLinkProcessor externalLinkProcessor; + private final ReactiveExtensionClient client; + private final ReactiveSettingFetcher settingFetcher; + private final MomentFinder momentFinder; + private final SystemInfoGetter systemInfoGetter; + + @Override + public Mono pathPattern() { + return Mono.fromSupplier(() -> "/moments/rss.xml"); + } + + @Override + @NonNull + public String displayName() { + return "瞬间"; + } + + @Override + public String description() { + return "瞬间 RSS"; + } + + @Override + public String example() { + return "https://example.com/feed/moments/rss.xml"; + } + + @Override + public Mono handler(ServerRequest request) { + return buildRss(request); + } + + private Mono buildRss(ServerRequest request) { + var externalUrl = externalUrlSupplier.getURL(request.exchange().getRequest()); + + var builder = RSS2.builder(); + var rssMono = systemInfoGetter.get() + .flatMap(info -> getMomentPageTitle() + .doOnNext(momentTitle -> info.setTitle( + String.join(" | ", info.getTitle(), momentTitle)) + ) + .thenReturn(info) + ) + .map(basic -> builder + .title(basic.getTitle()) + .image(externalLinkProcessor.processLink(basic.getLogo())) + .description(StringUtils.defaultIfBlank(basic.getSubtitle(), + basic.getTitle())) + .link(externalUrl.toString()) + ) + .subscribeOn(Schedulers.boundedElastic()); + + var rssItemMono = momentFinder.listAll() + .map(moment -> { + var permalink = getMomentPermalink(moment); + var medium = moment.getSpec().getContent().getMedium(); + var mediumHtml = generateMediaHtmlList(medium); + var htmlContent = processHtml(moment.getSpec().getContent().getHtml()); + return RSS2.Item.builder() + .title(buildMomentTitle(moment)) + .link(externalLinkProcessor.processLink(permalink)) + .pubDate(moment.getSpec().getReleaseTime()) + .guid(permalink) + .description(htmlContent + mediumHtml) + .build(); + }) + .collectList() + .doOnNext(builder::items) + .subscribeOn(Schedulers.boundedElastic()); + return Mono.when(rssMono, rssItemMono) + .then(Mono.fromSupplier(builder::build)); + } + + private String processHtml(String html) { + var document = Jsoup.parse(html); + + // Process all links + var links = document.select("a[href]"); + for (Element link : links) { + var isTag = link.hasClass("tag"); + String href = link.attr("href"); + if (isTag && href.startsWith("?")) { + // 兼容旧版标签链接 + href = "/moments" + href; + } + var absoluteUrl = externalLinkProcessor.processLink(href); + link.attr("href", absoluteUrl); + } + // process all images + var images = document.select("img[src]"); + for (Element image : images) { + String src = image.attr("src"); + var thumb = genThumbUrl(src, ThumbnailSize.M); + var absoluteUrl = externalLinkProcessor.processLink(thumb); + image.attr("src", absoluteUrl); + } + return document.body().html(); + } + + private String genThumbUrl(String url, ThumbnailSize size) { + return externalLinkProcessor.processLink( + "/apis/api.storage.halo.run/v1alpha1/thumbnails/-/via-uri?uri=" + url + "&size=" + + size.name().toLowerCase() + ); + } + + private String generateMediaHtmlList(List medium) { + if (CollectionUtils.isEmpty(medium)) { + return ""; + } + return medium.stream() + .map(this::generateSingleMediaHtml) + .collect(Collectors.joining()); + } + + private String generateSingleMediaHtml(Moment.MomentMedia media) { + var url = media.getUrl(); + return switch (media.getType()) { + case PHOTO -> generatePhotoHtml(media); + case VIDEO -> + String.format("", + url); + case AUDIO -> + String.format("", + url); + case POST -> String.format("%s", url, url); + }; + } + + private String generatePhotoHtml(Moment.MomentMedia media) { + // the best practice is to use the thumbnail for src + var mSrc = genThumbUrl(media.getUrl(), ThumbnailSize.M); + // If the reader does not support srcset, then only src, + var srcSet = """ + %s 400w, + %s 800w, + %s 1200w, + """.formatted( + genThumbUrl(media.getUrl(), ThumbnailSize.S), + mSrc, + genThumbUrl(media.getUrl(), ThumbnailSize.L) + ); + return String.format( + "\"moment", + mSrc, + srcSet + ); + } + + private static List nullSafeList(List list) { + return list == null ? List.of() : list; + } + + private static String getMomentPermalink(MomentVo moment) { + return "moments/" + moment.getMetadata().getName(); + } + + private static String buildMomentTitle(MomentVo momentVo) { + return momentVo.getOwner().getDisplayName() + " published on " + + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) + .format(momentVo.getSpec().getReleaseTime()); + } + + Mono getMomentPageTitle() { + return this.settingFetcher.get("base") + .map(setting -> setting.get("title").asText("瞬间")) + .defaultIfEmpty("瞬间"); + } +} diff --git a/src/main/java/run/halo/moments/rss/OldRssRouteRedirectionFilter.java b/src/main/java/run/halo/moments/rss/OldRssRouteRedirectionFilter.java new file mode 100644 index 0000000..e3a88c4 --- /dev/null +++ b/src/main/java/run/halo/moments/rss/OldRssRouteRedirectionFilter.java @@ -0,0 +1,38 @@ +package run.halo.moments.rss; + +import java.net.URI; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.lang.NonNull; +import org.springframework.security.web.server.DefaultServerRedirectStrategy; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; +import run.halo.app.security.AdditionalWebFilter; + +/** + *

The detail page address of the moment is also /moments/{name}, so you need to + * use a filter for redirection instead of directly using the route.

+ */ +public class OldRssRouteRedirectionFilter implements AdditionalWebFilter { + private final DefaultServerRedirectStrategy redirectStrategy = + new DefaultServerRedirectStrategy(); + private final ServerWebExchangeMatcher requestMatcher = ServerWebExchangeMatchers.pathMatchers( + HttpMethod.GET, "/moments/rss.xml"); + + @Override + @NonNull + public Mono filter(@NonNull ServerWebExchange exchange, @NonNull WebFilterChain chain) { + return requestMatcher.matches(exchange) + .flatMap(matchResult -> { + if (matchResult.isMatch()) { + redirectStrategy.setHttpStatus(HttpStatus.PERMANENT_REDIRECT); + return redirectStrategy + .sendRedirect(exchange, URI.create("/feed/moments/rss.xml")); + } + return chain.filter(exchange); + }); + } +} diff --git a/src/main/java/run/halo/moments/rss/RssAutoConfiguration.java b/src/main/java/run/halo/moments/rss/RssAutoConfiguration.java new file mode 100644 index 0000000..efe8605 --- /dev/null +++ b/src/main/java/run/halo/moments/rss/RssAutoConfiguration.java @@ -0,0 +1,52 @@ +package run.halo.moments.rss; + +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.infra.ExternalLinkProcessor; +import run.halo.app.infra.ExternalUrlSupplier; +import run.halo.app.infra.SystemInfoGetter; +import run.halo.app.plugin.ReactiveSettingFetcher; +import run.halo.app.security.AdditionalWebFilter; +import run.halo.feed.CacheClearRule; +import run.halo.feed.RssCacheClearRequested; +import run.halo.moments.event.MomentDeletedEvent; +import run.halo.moments.event.MomentUpdatedEvent; +import run.halo.moments.finders.MomentFinder; + +@Configuration +@ConditionalOnClass(name = "run.halo.feed.RssRouteItem") +@RequiredArgsConstructor +public class RssAutoConfiguration { + private final ExternalUrlSupplier externalUrlSupplier; + private final ExternalLinkProcessor externalLinkProcessor; + private final ReactiveExtensionClient client; + private final ReactiveSettingFetcher settingFetcher; + private final MomentFinder momentFinder; + private final SystemInfoGetter systemInfoGetter; + private final ApplicationEventPublisher eventPublisher; + + @Bean + MomentRssProvider momentRssProvider() { + return new MomentRssProvider(externalUrlSupplier, externalLinkProcessor, client, + settingFetcher, momentFinder, systemInfoGetter); + } + + @Async + @EventListener({MomentUpdatedEvent.class, MomentDeletedEvent.class}) + public void onMomentUpdatedOrDeleted() { + var rule = CacheClearRule.forExact("/feed/moments/rss.xml"); + var event = RssCacheClearRequested.forRule(this, rule); + eventPublisher.publishEvent(event); + } + + @Bean + AdditionalWebFilter oldRssRedirectWebFilter() { + return new OldRssRouteRedirectionFilter(); + } +} diff --git a/src/main/java/run/halo/moments/search/DocumentConverter.java b/src/main/java/run/halo/moments/search/DocumentConverter.java new file mode 100644 index 0000000..4f475ad --- /dev/null +++ b/src/main/java/run/halo/moments/search/DocumentConverter.java @@ -0,0 +1,81 @@ +package run.halo.moments.search; + +import static run.halo.moments.search.MomentHaloDocumentsProvider.MOMENT_DOCUMENT_TYPE; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Optional; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.User; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.infra.ExternalUrlSupplier; +import run.halo.app.search.HaloDocument; +import run.halo.moments.Moment; + +/** + * @author LIlGG + */ +@Component +@RequiredArgsConstructor +public class DocumentConverter implements Converter> { + + private final ReactiveExtensionClient client; + + private final ExternalUrlSupplier externalUrlSupplier; + + private final DateTimeFormatter dateFormat = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); + + @Override + @NonNull + public Mono convert(Moment moment) { + var haloDoc = new HaloDocument(); + var momentContent = moment.getSpec().getContent(); + haloDoc.setMetadataName(moment.getMetadata().getName()); + haloDoc.setType(MOMENT_DOCUMENT_TYPE); + haloDoc.setId(haloDocId(moment)); + haloDoc.setDescription(momentContent.getHtml()); + haloDoc.setExposed(isExposed(moment)); + haloDoc.setContent(momentContent.getHtml()); + var tags = moment.getSpec().getTags(); + Optional.ofNullable(tags).ifPresent((tag) -> haloDoc.setTags(tag.stream().toList())); + haloDoc.setOwnerName(moment.getSpec().getOwner()); + haloDoc.setUpdateTimestamp(moment.getSpec().getReleaseTime()); + haloDoc.setCreationTimestamp(moment.getMetadata().getCreationTimestamp()); + haloDoc.setPermalink(getPermalink(moment)); + haloDoc.setPublished(true); + + return Mono.when(getTitle(moment).doOnNext(haloDoc::setTitle)) + .then(Mono.fromSupplier(() -> haloDoc)); + } + + String haloDocId(Moment moment) { + return MOMENT_DOCUMENT_TYPE + '-' + moment.getMetadata().getName(); + } + + private Mono getTitle(Moment moment) { + return client.fetch(User.class, moment.getSpec().getOwner()) + .map(user -> user.getSpec().getDisplayName()) + .map(displayName -> { + ZonedDateTime zonedDateTime = + moment.getSpec().getReleaseTime().atZone(ZoneId.systemDefault()); + return "发表于:" + dateFormat.format(zonedDateTime) + + " by " + displayName; + }); + } + + private String getPermalink(Moment moment) { + var externalUrl = externalUrlSupplier.get(); + return externalUrl.resolve("moments/" + moment.getMetadata().getName()).toString(); + } + + private static boolean isExposed(Moment moment) { + var visible = moment.getSpec().getVisible(); + return Moment.MomentVisible.PUBLIC.equals(visible); + } +} diff --git a/src/main/java/run/halo/moments/search/MomentHaloDocumentsProvider.java b/src/main/java/run/halo/moments/search/MomentHaloDocumentsProvider.java new file mode 100644 index 0000000..233f325 --- /dev/null +++ b/src/main/java/run/halo/moments/search/MomentHaloDocumentsProvider.java @@ -0,0 +1,56 @@ +package run.halo.moments.search; + +import static run.halo.moments.ModelConst.SEARCH_DEFAULT_PAGE_SIZE; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; +import run.halo.app.extension.ListOptions; +import run.halo.app.extension.ListResult; +import run.halo.app.extension.PageRequest; +import run.halo.app.extension.PageRequestImpl; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.extension.index.query.QueryFactory; +import run.halo.app.extension.router.selector.FieldSelector; +import run.halo.app.search.HaloDocument; +import run.halo.app.search.HaloDocumentsProvider; +import run.halo.moments.Moment; + +/** + * @author LIlGG + */ +@Component +@RequiredArgsConstructor +public class MomentHaloDocumentsProvider implements HaloDocumentsProvider { + + public static final String MOMENT_DOCUMENT_TYPE = "moment.moment.halo.run"; + + private final ReactiveExtensionClient client; + + private final DocumentConverter converter; + + @Override + public Flux fetchAll() { + var options = new ListOptions(); + var notDeleted = QueryFactory.isNull("metadata.deletionTimestamp"); + var approved = QueryFactory.equal("spec.approved", "true"); + options.setFieldSelector(FieldSelector.of(notDeleted).andQuery(approved)); + var pageRequest = createPageRequest(); + // make sure the moments are approved and not deleted. + return client.listBy(Moment.class, options, pageRequest) + .map(ListResult::getItems) + .flatMapMany(Flux::fromIterable) + .flatMap(converter::convert); + } + + @Override + public String getType() { + return MOMENT_DOCUMENT_TYPE; + } + + private PageRequest createPageRequest() { + return PageRequestImpl.of(1, SEARCH_DEFAULT_PAGE_SIZE, + Sort.by("metadata.creationTimestamp", "metadata.name")); + } +} diff --git a/src/main/java/run/halo/moments/search/MomentSearchReconciler.java b/src/main/java/run/halo/moments/search/MomentSearchReconciler.java new file mode 100644 index 0000000..abdc570 --- /dev/null +++ b/src/main/java/run/halo/moments/search/MomentSearchReconciler.java @@ -0,0 +1,64 @@ +package run.halo.moments.search; + +import java.util.List; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.ExtensionUtil; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.Reconciler; +import run.halo.app.search.event.HaloDocumentAddRequestEvent; +import run.halo.app.search.event.HaloDocumentDeleteRequestEvent; +import run.halo.moments.Moment; + +/** + * @author LIlGG + */ +@Component +@RequiredArgsConstructor +public class MomentSearchReconciler implements Reconciler { + + private static final String FINALIZER = "moment-search-protection"; + + private final ApplicationEventPublisher eventPublisher; + + private final ExtensionClient client; + + private final DocumentConverter converter; + + @Override + public Result reconcile(Request request) { + client.fetch(Moment.class, request.name()).ifPresent(moment -> { + if (ExtensionUtil.isDeleted(moment)) { + if (ExtensionUtil.removeFinalizers(moment.getMetadata(), Set.of(FINALIZER))) { + eventPublisher.publishEvent( + new HaloDocumentDeleteRequestEvent(this, + List.of(converter.haloDocId(moment))) + ); + client.update(moment); + } + return; + } + ExtensionUtil.addFinalizers(moment.getMetadata(), Set.of(FINALIZER)); + + var haloDoc = converter.convert(moment) + .blockOptional().orElseThrow(); + eventPublisher.publishEvent( + new HaloDocumentAddRequestEvent(this, List.of(haloDoc))); + + client.update(moment); + }); + return Result.doNotRetry(); + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Moment()) + .workerCount(1) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/service/MomentService.java b/src/main/java/run/halo/moments/service/MomentService.java new file mode 100644 index 0000000..4249ea3 --- /dev/null +++ b/src/main/java/run/halo/moments/service/MomentService.java @@ -0,0 +1,30 @@ +package run.halo.moments.service; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import run.halo.app.extension.ListResult; +import run.halo.moments.ListedMoment; +import run.halo.moments.Moment; +import run.halo.moments.MomentQuery; + +/** + * Service for {@link run.halo.moments.Moment}. + * + * @author LIlGG + * @since 1.0.0 + */ +public interface MomentService { + Mono> listMoment(MomentQuery query); + + Mono create(Moment moment); + + Flux listAllTags(MomentQuery query); + + Mono findMomentByName(String name); + + Mono getByUsername(String momentName, String username); + + Mono updateBy(Moment moment); + + Mono deleteBy(Moment moment); +} diff --git a/src/main/java/run/halo/moments/service/RoleService.java b/src/main/java/run/halo/moments/service/RoleService.java new file mode 100644 index 0000000..a7a4290 --- /dev/null +++ b/src/main/java/run/halo/moments/service/RoleService.java @@ -0,0 +1,15 @@ +package run.halo.moments.service; + +import java.util.Collection; +import reactor.core.publisher.Mono; + +public interface RoleService { + /** + * verify whether the source role contains any role in the candidates. + * + * @param source the role to be verified + * @param candidates the roles to be verified + * @return

true if the source role contains any role in the candidates, otherwise false

+ */ + Mono joint(Collection source, Collection candidates); +} diff --git a/src/main/java/run/halo/moments/service/impl/DefaultRoleService.java b/src/main/java/run/halo/moments/service/impl/DefaultRoleService.java new file mode 100644 index 0000000..38ebead --- /dev/null +++ b/src/main/java/run/halo/moments/service/impl/DefaultRoleService.java @@ -0,0 +1,103 @@ +package run.halo.moments.service.impl; + +import static run.halo.app.extension.Comparators.compareCreationTimestamp; + +import com.fasterxml.jackson.core.type.TypeReference; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.Role; +import run.halo.app.extension.MetadataUtil; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.app.infra.utils.JsonUtils; +import run.halo.moments.service.RoleService; +import run.halo.moments.util.AuthorityUtils; + +@Slf4j +@Component +@RequiredArgsConstructor +public class DefaultRoleService implements RoleService { + + private final ReactiveExtensionClient client; + + @Override + public Mono joint(Collection source, Collection candidates) { + if (source.contains(AuthorityUtils.SUPER_ROLE_NAME)) { + return Mono.just(true); + } + return listDependencies(new HashSet<>(source)) + .map(role -> role.getMetadata().getName()) + .collect(Collectors.toSet()) + .map(roleNames -> !Collections.disjoint(roleNames, candidates)); + } + + private Flux listDependencies(Set names) { + var visited = new HashSet(); + return listRoles(names) + .expand(role -> { + var name = role.getMetadata().getName(); + if (visited.contains(name)) { + return Flux.empty(); + } + if (log.isTraceEnabled()) { + log.trace("Expand role: {}", role.getMetadata().getName()); + } + visited.add(name); + var annotations = MetadataUtil.nullSafeAnnotations(role); + var dependenciesJson = annotations.get(Role.ROLE_DEPENDENCIES_ANNO); + var dependencies = stringToList(dependenciesJson); + + return Flux.fromIterable(dependencies) + .filter(dep -> !visited.contains(dep)) + .collect(Collectors.toSet()) + .flatMapMany(this::listRoles); + }) + .concatWith(Flux.defer(() -> listAggregatedRoles(visited))); + } + + private Flux listAggregatedRoles(Set roleNames) { + var aggregatedLabelNames = roleNames.stream() + .map(roleName -> Role.ROLE_AGGREGATE_LABEL_PREFIX + roleName) + .collect(Collectors.toSet()); + Predicate predicate = role -> { + var labels = role.getMetadata().getLabels(); + if (labels == null) { + return false; + } + return aggregatedLabelNames.stream() + .anyMatch(aggregatedLabel -> Boolean.parseBoolean(labels.get(aggregatedLabel))); + }; + return client.list(Role.class, predicate, compareCreationTimestamp(true)); + } + + private Flux listRoles(Set names) { + if (CollectionUtils.isEmpty(names)) { + return Flux.empty(); + } + + Predicate predicate = role -> names.contains(role.getMetadata().getName()); + return client.list(Role.class, predicate, compareCreationTimestamp(true)); + } + + @NonNull + private List stringToList(String str) { + if (StringUtils.isBlank(str)) { + return Collections.emptyList(); + } + return JsonUtils.jsonToObject(str, + new TypeReference<>() { + }); + } +} diff --git a/src/main/java/run/halo/moments/service/impl/MomentServiceImpl.java b/src/main/java/run/halo/moments/service/impl/MomentServiceImpl.java new file mode 100644 index 0000000..4423d29 --- /dev/null +++ b/src/main/java/run/halo/moments/service/impl/MomentServiceImpl.java @@ -0,0 +1,149 @@ +package run.halo.moments.service.impl; + +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.web.server.ServerWebInputException; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.Counter; +import run.halo.app.core.extension.User; +import run.halo.app.extension.ListOptions; +import run.halo.app.extension.ListResult; +import run.halo.app.extension.ReactiveExtensionClient; +import run.halo.moments.Contributor; +import run.halo.moments.ListedMoment; +import run.halo.moments.Moment; +import run.halo.moments.MomentQuery; +import run.halo.moments.Stats; +import run.halo.moments.exception.NotFoundException; +import run.halo.moments.service.MomentService; +import run.halo.moments.util.MeterUtils; + +/** + * Listed moment. + * + * @author LIlGG + * @author guqing + * @since 1.0.0 + */ +@Component +@RequiredArgsConstructor +public class MomentServiceImpl implements MomentService { + + private final ReactiveExtensionClient client; + + @Override + public Mono> listMoment(MomentQuery query) { + return client.listBy(Moment.class, query.toListOptions(), query.toPageRequest()) + .flatMap(listResult -> Flux.fromStream(listResult.get()) + .concatMap(this::toListedMoment) + .collectList() + .map(list -> new ListResult<>(listResult.getPage(), listResult.getSize(), + listResult.getTotal(), list) + ) + ); + } + + @Override + public Mono create(Moment moment) { + if (Objects.isNull(moment.getSpec().getReleaseTime())) { + moment.getSpec().setReleaseTime(Instant.now()); + } + + if (Objects.isNull(moment.getSpec().getVisible())) { + moment.getSpec().setVisible(Moment.MomentVisible.PUBLIC); + } + + return getContextUser() + .flatMap(user -> { + moment.getSpec().setOwner(user.getMetadata().getName()); + return client.create(moment); + }); + } + + @Override + public Flux listAllTags(MomentQuery query) { + return client.listAll(Moment.class, query.toListOptions(), + Sort.by("metadata.name").descending()) + .flatMapIterable(moment -> { + var tags = moment.getSpec().getTags(); + return Objects.requireNonNullElseGet(tags, List::of); + }) + .distinct(); + } + + @Override + public Mono findMomentByName(String name) { + return client.fetch(Moment.class, name) + .switchIfEmpty(Mono.error(new NotFoundException("Moment not found."))) + .flatMap(this::toListedMoment); + } + + @Override + public Mono getByUsername(String momentName, String username) { + return client.get(Moment.class, momentName) + .filter(post -> post.getSpec() != null) + .filter(post -> Objects.equals(username, post.getSpec().getOwner())); + } + + @Override + public Mono deleteBy(Moment moment) { + return client.delete(moment); + } + + @Override + public Mono updateBy(Moment moment) { + return client.update(moment); + } + + private Mono toListedMoment(Moment moment) { + ListedMoment.ListedMomentBuilder momentBuilder = ListedMoment.builder() + .moment(moment); + return Mono.just(momentBuilder) + .map(ListedMoment.ListedMomentBuilder::build) + .flatMap(lm -> fetchStats(moment) + .doOnNext(lm::setStats) + .thenReturn(lm)) + .flatMap(lm -> setOwner(moment.getSpec().getOwner(), lm)); + } + + private Mono setOwner(String owner, ListedMoment moment) { + return client.fetch(User.class, owner) + .map(user -> { + Contributor contributor = new Contributor(); + contributor.setName(user.getMetadata().getName()); + contributor.setDisplayName(user.getSpec().getDisplayName()); + contributor.setAvatar(user.getSpec().getAvatar()); + return contributor; + }) + .doOnNext(moment::setOwner) + .thenReturn(moment); + } + + private Mono fetchStats(Moment moment) { + Assert.notNull(moment, "The moment must not be null."); + String name = moment.getMetadata().getName(); + return client.fetch(Counter.class, MeterUtils.nameOf(Moment.class, name)) + .map(counter -> Stats.builder() + .upvote(counter.getUpvote()) + .totalComment(counter.getTotalComment()) + .approvedComment(counter.getApprovedComment()) + .build()) + .defaultIfEmpty(Stats.empty()); + + } + + protected Mono getContextUser() { + return ReactiveSecurityContextHolder.getContext() + .flatMap(ctx -> { + var name = ctx.getAuthentication().getName(); + return client.fetch(User.class, name); + }); + } +} diff --git a/src/main/java/run/halo/moments/uc/UcMomentEndpoint.java b/src/main/java/run/halo/moments/uc/UcMomentEndpoint.java new file mode 100644 index 0000000..8502a1a --- /dev/null +++ b/src/main/java/run/halo/moments/uc/UcMomentEndpoint.java @@ -0,0 +1,235 @@ +package run.halo.moments.uc; + +import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; +import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; +import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; +import static org.springdoc.core.fn.builders.requestbody.Builder.requestBodyBuilder; + +import java.time.Instant; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.fn.builders.schema.Builder; +import org.springdoc.webflux.core.fn.SpringdocRouteBuilder; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.ResponseStatusException; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import lombok.AllArgsConstructor; +import reactor.core.publisher.Mono; +import run.halo.app.core.extension.endpoint.CustomEndpoint; +import run.halo.app.extension.GroupVersion; +import run.halo.app.extension.ListResult; +import run.halo.moments.ListedMoment; +import run.halo.moments.Moment; +import run.halo.moments.MomentQuery; +import run.halo.moments.service.MomentService; +import run.halo.moments.service.RoleService; +import run.halo.moments.util.AuthorityUtils; + +/** + * A custom endpoint for {@link run.halo.moments.Moment}. + * + * @author LIlGG + * @since 1.0.0 + */ +@Component +@AllArgsConstructor +public class UcMomentEndpoint implements CustomEndpoint { + + private final MomentService momentService; + + private final RoleService roleService; + + @Override + public RouterFunction endpoint() { + final var tag = groupVersion() + "/moment"; + return SpringdocRouteBuilder.route() + .GET("moments", this::listMyMoment, builder -> { + builder.operationId("ListMyMoments") + .description("List My moments.") + .tag(tag) + .response(responseBuilder() + .implementation(ListResult.generateGenericClass(ListedMoment.class)) + ); + MomentQuery.buildParameters(builder); + }) + .GET("moments/{name}", this::getMyMoment, + builder -> builder.operationId("GetMyMoment") + .description("Get a My Moment.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.PATH) + .required(true) + .implementation(String.class) + ) + .response(responseBuilder() + .implementation(Moment.class)) + ) + .POST("moments", this::createMyMoment, + builder -> builder.operationId("CreateMyMoment") + .description("Create a My Moment.") + .tag(tag) + .requestBody(requestBodyBuilder() + .required(true) + .content(contentBuilder() + .mediaType(MediaType.APPLICATION_JSON_VALUE) + .schema(Builder.schemaBuilder() + .implementation(Moment.class)) + )) + .response(responseBuilder() + .implementation(Moment.class)) + ) + .PUT("moments/{name}", this::updateMyMoment, + builder -> builder.operationId("UpdateMyMoment") + .description("Update a My Moment.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.PATH) + .required(true) + .implementation(String.class) + ) + .requestBody(requestBodyBuilder() + .required(true) + .content(contentBuilder() + .mediaType(MediaType.APPLICATION_JSON_VALUE) + .schema(Builder.schemaBuilder() + .implementation(Moment.class)) + )) + .response(responseBuilder() + .implementation(Moment.class)) + ) + .DELETE("moments/{name}", this::deleteMyMoment, + builder -> builder.operationId("DeleteMyMoment") + .description("Delete a My Moment.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.PATH) + .required(true) + .implementation(String.class) + ) + .response(responseBuilder() + .implementation(Moment.class)) + ) + .GET("tags", this::listMyTags, + builder -> builder.operationId("ListTags") + .description("List all moment tags.") + .tag(tag) + .parameter(parameterBuilder() + .name("name") + .in(ParameterIn.QUERY) + .description("Tag name to query") + .required(false) + .implementation(String.class) + ) + .response(responseBuilder() + .implementationArray(String.class) + )) + .build(); + } + + private Mono deleteMyMoment(ServerRequest request) { + var name = request.pathVariable("name"); + return getMyMoment(name) + .flatMap(momentService::deleteBy) + .flatMap(moment -> ServerResponse.ok().bodyValue(moment)); + } + + private Mono updateMyMoment(ServerRequest request) { + var name = request.pathVariable("name"); + return getMyMoment(name) + .flatMap(oldMoment -> { + Moment.MomentSpec oldSpec = oldMoment.getSpec(); + + return request.bodyToMono(Moment.class) + .doOnNext(newMoment -> { + Moment.MomentSpec newSpec = newMoment.getSpec(); + newSpec.setOwner(oldSpec.getOwner()); + newSpec.setReleaseTime(oldSpec.getReleaseTime()); + // Every update needs to be re-reviewed. + newSpec.setApproved(false); + }) + .flatMap(momentService::updateBy); + }) + .flatMap(moment -> ServerResponse.ok().bodyValue(moment)); + } + + private Mono getMyMoment(ServerRequest request) { + var name = request.pathVariable("name"); + return getMyMoment(name) + .flatMap(moment -> ServerResponse.ok().bodyValue(moment)); + } + + private Mono getMyMoment(String momentName) { + return getCurrentUser() + .flatMap(user -> momentService.getByUsername(momentName, user.getName()) + .switchIfEmpty( + Mono.error(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, + "The moment was not found or deleted")) + ) + ); + } + + private Mono createMyMoment(ServerRequest request) { + return getCurrentUser() + .flatMap(user -> request.bodyToMono(Moment.class) + .flatMap(post -> { + post.getSpec().setApproved(false); + post.getSpec().setOwner(user.getName()); + var roles = AuthorityUtils.authoritiesToRoles(user.getAuthorities()); + return roleService.joint(roles, + Set.of(AuthorityUtils.MOMENT_PUBLISH_APPROVAL_ROLE_NAME, + AuthorityUtils.SUPER_ROLE_NAME)) + .doOnNext(result -> { + if (result) { + // If it is a user with audit authority, there is no need to review. + post.getSpec().setApproved(true); + post.getSpec().setApprovedTime(Instant.now()); + } + }) + .thenReturn(post); + }) + ) + .flatMap(momentService::create) + .flatMap(moment -> ServerResponse.ok().bodyValue(moment)); + } + + private Mono listMyMoment(ServerRequest request) { + return getCurrentUser() + .map(user -> new MomentQuery(request.exchange(), user.getName())) + .flatMap(momentService::listMoment) + .flatMap(listedMoments -> ServerResponse.ok().bodyValue(listedMoments)); + } + + private Mono getCurrentUser() { + return ReactiveSecurityContextHolder.getContext() + .map(SecurityContext::getAuthentication); + } + + private Mono listMyTags(ServerRequest request) { + String name = request.queryParam("name").orElse(null); + return getCurrentUser() + .map(user -> new MomentQuery(request.exchange(), user.getName())) + .flatMapMany(momentService::listAllTags) + .filter(tagName -> StringUtils.isBlank(name) || StringUtils.containsIgnoreCase(tagName, + name)) + .collectList() + .flatMap(result -> ServerResponse.ok().bodyValue(result)); + } + + @Override + public GroupVersion groupVersion() { + return GroupVersion.parseAPIVersion("uc.api.moment.halo.run/v1alpha1"); + } +} diff --git a/src/main/java/run/halo/moments/util/AuthorityUtils.java b/src/main/java/run/halo/moments/util/AuthorityUtils.java new file mode 100644 index 0000000..fe2d351 --- /dev/null +++ b/src/main/java/run/halo/moments/util/AuthorityUtils.java @@ -0,0 +1,42 @@ +package run.halo.moments.util; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.core.GrantedAuthority; + +/** + * Utility methods for manipulating GrantedAuthority collection. + * + * @author johnniang + */ +public enum AuthorityUtils { + ; + public static final String ROLE_PREFIX = "ROLE_"; + public static final String SUPER_ROLE_NAME = "super-role"; + + public static final String MOMENT_PUBLISH_APPROVAL_ROLE_NAME = + "role-template-uc-moments-approved"; + + public static final String MOMENT_MANAGEMENT_ROLE_NAME = "role-template-moments-manage"; + + /** + * Converts an array of GrantedAuthority objects to a role set. + * + * @return a Set of the Strings obtained from each call to + * GrantedAuthority.getAuthority() and filtered by prefix "ROLE_". + */ + public static Set authoritiesToRoles( + Collection authorities) { + return authorities.stream() + .map(GrantedAuthority::getAuthority) + .filter(authority -> StringUtils.startsWith(authority, ROLE_PREFIX)) + .map(authority -> StringUtils.removeStart(authority, ROLE_PREFIX)) + .collect(Collectors.toSet()); + } + + public static boolean containsSuperRole(Collection roles) { + return roles.contains(SUPER_ROLE_NAME); + } +} \ No newline at end of file diff --git a/src/main/java/run/halo/moments/util/MeterUtils.java b/src/main/java/run/halo/moments/util/MeterUtils.java new file mode 100644 index 0000000..ee6fd22 --- /dev/null +++ b/src/main/java/run/halo/moments/util/MeterUtils.java @@ -0,0 +1,58 @@ +package run.halo.moments.util; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import org.apache.commons.lang3.StringUtils; +import run.halo.app.extension.AbstractExtension; +import run.halo.app.extension.GVK; + +/** + * Meter utils. + * + * @author guqing + * @since 2.0.0 + */ +public class MeterUtils { + + public static final Tag METRICS_COMMON_TAG = Tag.of("metrics.halo.run", "true"); + + /** + * Build a counter name. + * + * @param group extension group + * @param plural extension plural + * @param name extension name + * @return counter name + */ + public static String nameOf(String group, String plural, String name) { + if (StringUtils.isBlank(group)) { + return String.join("/", plural, name); + } + return String.join(".", plural, group) + "/" + name; + } + + public static String nameOf(Class clazz, String name) { + GVK annotation = clazz.getAnnotation(GVK.class); + return nameOf(annotation.group(), annotation.plural(), name); + } + + /** + * Build a {@link Counter} for halo extension. + * + * @param registry meter registry + * @param name counter name,build by {@link #nameOf(String, String, String)} + * @return counter find by name from registry if exists, otherwise create a new one. + */ + private static Counter counter(MeterRegistry registry, String name, Tag... tags) { + Tags withTags = Tags.of(METRICS_COMMON_TAG).and(tags); + Counter counter = registry.find(name) + .tags(withTags) + .counter(); + if (counter == null) { + return registry.counter(name, withTags); + } + return counter; + } +} diff --git a/src/main/java/run/halo/moments/vo/ContributorVo.java b/src/main/java/run/halo/moments/vo/ContributorVo.java new file mode 100644 index 0000000..53065f7 --- /dev/null +++ b/src/main/java/run/halo/moments/vo/ContributorVo.java @@ -0,0 +1,35 @@ +package run.halo.moments.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import run.halo.app.core.extension.User; + +/** + * Listed comment. + * + * @author LIlGG + * @since 2.0.0 + */ +@Data +@SuperBuilder +@ToString +@EqualsAndHashCode +public class ContributorVo { + private String name; + + private String avatar; + + private String bio; + + private String displayName; + + public static ContributorVo from(User user) { + return builder().name(user.getMetadata().getName()) + .displayName(user.getSpec().getDisplayName()) + .avatar(user.getSpec().getAvatar()) + .bio(user.getSpec().getBio()) + .build(); + } +} diff --git a/src/main/java/run/halo/moments/vo/MomentTagVo.java b/src/main/java/run/halo/moments/vo/MomentTagVo.java new file mode 100644 index 0000000..8e8375b --- /dev/null +++ b/src/main/java/run/halo/moments/vo/MomentTagVo.java @@ -0,0 +1,18 @@ +package run.halo.moments.vo; + +import lombok.Builder; +import lombok.ToString; +import lombok.Value; +import org.springframework.web.util.UriUtils; +import java.nio.charset.StandardCharsets; + +@Value +@Builder +public class MomentTagVo { + + String name; + + String permalink; + + Integer momentCount; +} diff --git a/src/main/java/run/halo/moments/vo/MomentVo.java b/src/main/java/run/halo/moments/vo/MomentVo.java new file mode 100644 index 0000000..d29ad40 --- /dev/null +++ b/src/main/java/run/halo/moments/vo/MomentVo.java @@ -0,0 +1,39 @@ +package run.halo.moments.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.springframework.util.Assert; +import run.halo.app.extension.MetadataOperator; +import run.halo.moments.Moment; +import run.halo.moments.Stats; + +/** + * Listed moment. + * + * @author LIlGG + * @since 1.0.0 + */ +@Data +@SuperBuilder +@ToString +@EqualsAndHashCode +public class MomentVo { + + private MetadataOperator metadata; + + private Moment.MomentSpec spec; + + private ContributorVo owner; + + private Stats stats; + + public static MomentVo from(Moment moment) { + Assert.notNull(moment, "The moment must not be null."); + return MomentVo.builder() + .metadata(moment.getMetadata()) + .spec(moment.getSpec()) + .build(); + } +} diff --git a/src/main/resources/extensions/ext-definition.yaml b/src/main/resources/extensions/ext-definition.yaml new file mode 100644 index 0000000..b65746c --- /dev/null +++ b/src/main/resources/extensions/ext-definition.yaml @@ -0,0 +1,19 @@ +apiVersion: plugin.halo.run/v1alpha1 +kind: ExtensionDefinition +metadata: + name: moment-rss-provider +spec: + className: run.halo.moments.rss.MomentRssProvider + extensionPointName: feed-rss-route-item + displayName: "瞬间订阅" + description: "用于生成瞬间的 RSS 订阅源" +--- +apiVersion: plugin.halo.run/v1alpha1 +kind: ExtensionDefinition +metadata: + name: moment-old-rss-redirection-filter +spec: + className: run.halo.moments.rss.OldRssRouteRedirectionFilter + extensionPointName: additional-webfilter + displayName: "瞬间旧 RSS 重定向" + description: "用于重定向旧的 RSS 订阅源到新的订阅路径" \ No newline at end of file diff --git a/src/main/resources/extensions/moment-notification.yaml b/src/main/resources/extensions/moment-notification.yaml new file mode 100644 index 0000000..aae820d --- /dev/null +++ b/src/main/resources/extensions/moment-notification.yaml @@ -0,0 +1,68 @@ +apiVersion: notification.halo.run/v1alpha1 +kind: ReasonType +metadata: + name: new-comment-on-moment +spec: + displayName: "我发布的瞬间收到新评论" + description: "当你发布的瞬间收到新评论时,你将会收到一条通知,告诉你有新的评论。" + properties: + - name: momentName + type: string + description: "The name of the moment." + - name: momentCreatedAt + type: string + - name: momentRawContent + type: string + - name: momentHtmlContent + type: string + - name: momentUrl + type: string + - name: commenter + type: string + description: "The display name of the commenter." + - name: commentName + type: string + description: "The name of the comment." + - name: content + type: string + description: "The content of the comment." +--- +apiVersion: notification.halo.run/v1alpha1 +kind: NotificationTemplate +metadata: + name: template-new-comment-on-moment +spec: + reasonSelector: + reasonType: new-comment-on-moment + language: default + template: + title: "[(${commenter})] 评论了你在 [(${momentCreatedAt})] 时刻发布的瞬间" + rawBody: | + [(${subscriber.displayName})] 你好: + + [(${commenter})] 评论了你的瞬间“[(${momentRawContent})]”, 以下是评论的具体内容: + + [(${content})] + htmlBody: | +
+
+

+
+
+
+
+
+ + +
+
以下是评论的具体内容:
+
+
+
+
+
diff --git a/src/main/resources/extensions/roleTemplate.yaml b/src/main/resources/extensions/roleTemplate.yaml new file mode 100644 index 0000000..bea0cc4 --- /dev/null +++ b/src/main/resources/extensions/roleTemplate.yaml @@ -0,0 +1,85 @@ +apiVersion: v1alpha1 +kind: Role +metadata: + name: role-template-moments-view + labels: + halo.run/role-template: "true" + annotations: + rbac.authorization.halo.run/module: "瞬间" + rbac.authorization.halo.run/display-name: "瞬间查看" + rbac.authorization.halo.run/ui-permissions: | + ["plugin:moments:view"] +rules: + - apiGroups: ["moment.halo.run"] + resources: ["moments"] + verbs: ["get", "list"] + - apiGroups: ["console.api.moment.halo.run"] + resources: ["moments", "tags"] + verbs: ["get", "list"] +--- +apiVersion: v1alpha1 +kind: Role +metadata: + name: role-template-moments-manage + labels: + halo.run/role-template: "true" + annotations: + rbac.authorization.halo.run/module: "瞬间" + rbac.authorization.halo.run/display-name: "瞬间管理" + rbac.authorization.halo.run/ui-permissions: | + ["plugin:moments:manage"] + rbac.authorization.halo.run/dependencies: | + ["role-template-moments-view"] +rules: + - apiGroups: ["moment.halo.run"] + resources: ["moments"] + verbs: ["create", "patch", "update", "delete", "deletecollection"] + - apiGroups: ["console.api.moment.halo.run"] + resources: ["moments", "tags"] + verbs: ["create", "patch", "update", "delete", "deletecollection"] +--- +apiVersion: v1alpha1 +kind: Role +metadata: + name: role-template-uc-moments-publish + labels: + halo.run/role-template: "true" + annotations: + rbac.authorization.halo.run/module: "瞬间" + rbac.authorization.halo.run/display-name: "允许发布自己的瞬间" + rbac.authorization.halo.run/ui-permissions: | + ["uc:plugin:moments:publish"] +rules: + - apiGroups: ["uc.api.moment.halo.run"] + resources: ["moments", "tags"] + verbs: ["get", "list", "create", "update"] +--- +apiVersion: v1alpha1 +kind: Role +metadata: + name: role-template-uc-moments-approved + labels: + halo.run/role-template: "true" + annotations: + rbac.authorization.halo.run/module: "瞬间" + rbac.authorization.halo.run/display-name: "发布瞬间无需审核" + rbac.authorization.halo.run/dependencies: | + ["role-template-uc-moments-publish"] +rules: + - nonResourceURLs: ["*"] +--- +apiVersion: v1alpha1 +kind: Role +metadata: + name: role-template-uc-moments-delete + labels: + halo.run/role-template: "true" + annotations: + rbac.authorization.halo.run/module: "瞬间" + rbac.authorization.halo.run/display-name: "允许删除自己的瞬间" + rbac.authorization.halo.run/ui-permissions: | + ["uc:plugin:moments:delete"] +rules: + - apiGroups: ["uc.api.moment.halo.run"] + resources: ["moments", "tags"] + verbs: ["delete", "deletecollection"] diff --git a/src/main/resources/extensions/settings.yaml b/src/main/resources/extensions/settings.yaml new file mode 100644 index 0000000..09d2224 --- /dev/null +++ b/src/main/resources/extensions/settings.yaml @@ -0,0 +1,19 @@ +apiVersion: v1alpha1 +kind: Setting +metadata: + name: plugin-moments-settings +spec: + forms: + - group: base + label: 基本设置 + formSchema: + - $formkit: text + label: 页面标题 + name: title + validation: required + value: '瞬间' + - $formkit: text + label: 瞬间列表显示条数 + name: pageSize + validation: required|Number + value: 10 \ No newline at end of file diff --git a/src/main/resources/logo.svg b/src/main/resources/logo.svg new file mode 100644 index 0000000..fd0d3fd --- /dev/null +++ b/src/main/resources/logo.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/main/resources/plugin.yaml b/src/main/resources/plugin.yaml new file mode 100644 index 0000000..9541bc5 --- /dev/null +++ b/src/main/resources/plugin.yaml @@ -0,0 +1,25 @@ +apiVersion: plugin.halo.run/v1alpha1 +kind: Plugin +metadata: + name: PluginMoments + annotations: + "store.halo.run/app-id": "app-SnwWD" +spec: + enabled: true + requires: ">=2.21.0" + author: + name: Halo + website: https://github.com/halo-dev + logo: logo.svg + configMapName: plugin-moments-configmap + settingName: plugin-moments-settings + homepage: https://www.halo.run/store/apps/app-SnwWD + repo: https://github.com/halo-sigs/plugin-moments + issues: https://github.com/halo-sigs/plugin-moments/issues + displayName: "瞬间" + description: "Halo 2.0 的瞬间管理插件,提供一个轻量级的内容发布功能,支持发布图文、视频、音频等内容。" + pluginDependencies: + "PluginFeed?": ">=1.4.0" + license: + - name: "GPL-3.0" + url: "https://github.com/halo-sigs/plugin-moments/blob/main/LICENSE"