From c6ba83f5d782c116e5192787da9067c72f50d2c3 Mon Sep 17 00:00:00 2001 From: anian Date: Sun, 19 Jul 2026 01:16:28 +0800 Subject: [PATCH] =?UTF-8?q?1.13.1=E5=8E=9F=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 520 ++ .gitignore | 81 + LICENSE | 674 ++ OWNERS | 11 + README.md | 336 + api-docs/openapi/v3_0/momentsApi.json | 1155 ++++ build.gradle | 74 + console/.eslintrc.cjs | 20 + console/env.d.ts | 18 + console/package.json | 51 + .../patches/@tiptap__suggestion@2.11.2.patch | 14 + console/pnpm-lock.yaml | 5609 +++++++++++++++++ console/pnpm-workspace.yaml | 7 + console/rsbuild.config.mjs | 39 + console/src/api/generated/.gitignore | 4 + console/src/api/generated/.npmignore | 1 + .../api/generated/.openapi-generator-ignore | 23 + .../api/generated/.openapi-generator/FILES | 31 + .../api/generated/.openapi-generator/VERSION | 1 + console/src/api/generated/api.ts | 20 + ...api-moment-halo-run-v1alpha1-moment-api.ts | 573 ++ .../api/generated/api/moment-v1alpha1-api.ts | 665 ++ ...api-moment-halo-run-v1alpha1-moment-api.ts | 759 +++ console/src/api/generated/base.ts | 86 + console/src/api/generated/common.ts | 150 + console/src/api/generated/configuration.ts | 110 + console/src/api/generated/git_push.sh | 57 + console/src/api/generated/index.ts | 18 + .../src/api/generated/models/add-operation.ts | 49 + .../src/api/generated/models/contributor.ts | 42 + .../api/generated/models/copy-operation.ts | 49 + console/src/api/generated/models/index.ts | 18 + .../api/generated/models/json-patch-inner.ts | 41 + .../generated/models/listed-moment-list.ts | 81 + .../src/api/generated/models/listed-moment.ts | 51 + console/src/api/generated/models/metadata.ts | 72 + .../api/generated/models/moment-content.ts | 45 + .../src/api/generated/models/moment-list.ts | 81 + .../src/api/generated/models/moment-media.ts | 52 + .../src/api/generated/models/moment-spec.ts | 77 + .../src/api/generated/models/moment-status.ts | 36 + console/src/api/generated/models/moment.ts | 63 + .../api/generated/models/move-operation.ts | 49 + .../api/generated/models/remove-operation.ts | 43 + .../api/generated/models/replace-operation.ts | 49 + console/src/api/generated/models/stats.ts | 42 + .../api/generated/models/test-operation.ts | 49 + console/src/api/index.ts | 20 + console/src/assets/logo.svg | 1 + console/src/components/EditorBubbleMenu.vue | 48 + .../components/EditorLinkBubbleMenuItems.vue | 97 + console/src/components/FilterDropdown.vue | 73 + console/src/components/MediaCard.vue | 103 + console/src/components/MomentEdit.vue | 400 ++ console/src/components/MomentItem.vue | 168 + console/src/components/MomentPreview.vue | 227 + console/src/components/PreviewDetailModal.vue | 45 + console/src/components/TagFilterDropdown.vue | 103 + console/src/components/TextEditor.vue | 200 + .../components/composables/use-extension.ts | 62 + console/src/composables/use-content-cache.ts | 79 + console/src/composables/use-tag.ts | 41 + console/src/extensions/images/index.ts | 39 + .../src/extensions/tags/TagsExtensionView.vue | 142 + console/src/extensions/tags/index.ts | 199 + console/src/index.ts | 91 + .../src/plugin-supports/shiki/directive.ts | 40 + .../shiki/use-plugin-shiki-script-loader.ts | 26 + console/src/plugin-supports/shiki/util.ts | 6 + console/src/styles/index.scss | 207 + console/src/types/index.ts | 10 + console/src/uc/MomentEdit.vue | 387 ++ console/src/uc/MomentItem.vue | 148 + console/src/uc/MomentsList.vue | 199 + console/src/uc/TagFilterDropdown.vue | 103 + console/src/utils/date.ts | 60 + console/src/utils/id.ts | 7 + console/src/views/MomentsList.vue | 214 + console/tsconfig.json | 14 + console/uno.config.ts | 7 + gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 244 + gradlew.bat | 92 + images/plugin-moments-preview.png | Bin 0 -> 225310 bytes settings.gradle | 7 + .../CommentNotificationReasonPublisher.java | 148 + .../run/halo/moments/CommentReconciler.java | 63 + .../java/run/halo/moments/Contributor.java | 13 + .../halo/moments/CustomEndpointsBuilder.java | 42 + .../java/run/halo/moments/ListedMoment.java | 25 + .../java/run/halo/moments/ModelConst.java | 14 + src/main/java/run/halo/moments/Moment.java | 126 + .../halo/moments/MomentCommentSubject.java | 55 + .../java/run/halo/moments/MomentEndpoint.java | 142 + .../run/halo/moments/MomentMigration.java | 49 + .../java/run/halo/moments/MomentQuery.java | 200 + .../run/halo/moments/MomentReconciler.java | 95 + .../java/run/halo/moments/MomentRouter.java | 115 + .../java/run/halo/moments/MomentsPlugin.java | 87 + .../run/halo/moments/SchemeRegistered.java | 9 + src/main/java/run/halo/moments/Stats.java | 29 + .../halo/moments/SubscriptionMigration.java | 131 + .../java/run/halo/moments/TagReconciler.java | 45 + .../moments/event/MomentDeletedEvent.java | 14 + .../event/MomentHasNewCommentEvent.java | 22 + .../moments/event/MomentUpdatedEvent.java | 14 + .../moments/exception/NotFoundException.java | 15 + .../halo/moments/finders/MomentFinder.java | 47 + .../finders/impl/MomentFinderImpl.java | 191 + .../halo/moments/rss/MomentRssProvider.java | 200 + .../rss/OldRssRouteRedirectionFilter.java | 38 + .../moments/rss/RssAutoConfiguration.java | 52 + .../moments/search/DocumentConverter.java | 81 + .../search/MomentHaloDocumentsProvider.java | 56 + .../search/MomentSearchReconciler.java | 64 + .../halo/moments/service/MomentService.java | 30 + .../run/halo/moments/service/RoleService.java | 15 + .../service/impl/DefaultRoleService.java | 103 + .../service/impl/MomentServiceImpl.java | 149 + .../run/halo/moments/uc/UcMomentEndpoint.java | 235 + .../run/halo/moments/util/AuthorityUtils.java | 42 + .../run/halo/moments/util/MeterUtils.java | 58 + .../run/halo/moments/vo/ContributorVo.java | 35 + .../java/run/halo/moments/vo/MomentTagVo.java | 18 + .../java/run/halo/moments/vo/MomentVo.java | 39 + .../resources/extensions/ext-definition.yaml | 19 + .../extensions/moment-notification.yaml | 68 + .../resources/extensions/roleTemplate.yaml | 85 + src/main/resources/extensions/settings.yaml | 19 + src/main/resources/logo.svg | 2 + src/main/resources/plugin.yaml | 25 + 133 files changed, 19136 insertions(+) create mode 100644 .editorconfig create mode 100755 .gitignore create mode 100644 LICENSE create mode 100644 OWNERS create mode 100644 README.md create mode 100644 api-docs/openapi/v3_0/momentsApi.json create mode 100644 build.gradle create mode 100644 console/.eslintrc.cjs create mode 100644 console/env.d.ts create mode 100644 console/package.json create mode 100644 console/patches/@tiptap__suggestion@2.11.2.patch create mode 100644 console/pnpm-lock.yaml create mode 100644 console/pnpm-workspace.yaml create mode 100644 console/rsbuild.config.mjs create mode 100644 console/src/api/generated/.gitignore create mode 100644 console/src/api/generated/.npmignore create mode 100644 console/src/api/generated/.openapi-generator-ignore create mode 100644 console/src/api/generated/.openapi-generator/FILES create mode 100644 console/src/api/generated/.openapi-generator/VERSION create mode 100644 console/src/api/generated/api.ts create mode 100644 console/src/api/generated/api/console-api-moment-halo-run-v1alpha1-moment-api.ts create mode 100644 console/src/api/generated/api/moment-v1alpha1-api.ts create mode 100644 console/src/api/generated/api/uc-api-moment-halo-run-v1alpha1-moment-api.ts create mode 100644 console/src/api/generated/base.ts create mode 100644 console/src/api/generated/common.ts create mode 100644 console/src/api/generated/configuration.ts create mode 100644 console/src/api/generated/git_push.sh create mode 100644 console/src/api/generated/index.ts create mode 100644 console/src/api/generated/models/add-operation.ts create mode 100644 console/src/api/generated/models/contributor.ts create mode 100644 console/src/api/generated/models/copy-operation.ts create mode 100644 console/src/api/generated/models/index.ts create mode 100644 console/src/api/generated/models/json-patch-inner.ts create mode 100644 console/src/api/generated/models/listed-moment-list.ts create mode 100644 console/src/api/generated/models/listed-moment.ts create mode 100644 console/src/api/generated/models/metadata.ts create mode 100644 console/src/api/generated/models/moment-content.ts create mode 100644 console/src/api/generated/models/moment-list.ts create mode 100644 console/src/api/generated/models/moment-media.ts create mode 100644 console/src/api/generated/models/moment-spec.ts create mode 100644 console/src/api/generated/models/moment-status.ts create mode 100644 console/src/api/generated/models/moment.ts create mode 100644 console/src/api/generated/models/move-operation.ts create mode 100644 console/src/api/generated/models/remove-operation.ts create mode 100644 console/src/api/generated/models/replace-operation.ts create mode 100644 console/src/api/generated/models/stats.ts create mode 100644 console/src/api/generated/models/test-operation.ts create mode 100644 console/src/api/index.ts create mode 100644 console/src/assets/logo.svg create mode 100644 console/src/components/EditorBubbleMenu.vue create mode 100644 console/src/components/EditorLinkBubbleMenuItems.vue create mode 100644 console/src/components/FilterDropdown.vue create mode 100644 console/src/components/MediaCard.vue create mode 100644 console/src/components/MomentEdit.vue create mode 100644 console/src/components/MomentItem.vue create mode 100644 console/src/components/MomentPreview.vue create mode 100644 console/src/components/PreviewDetailModal.vue create mode 100644 console/src/components/TagFilterDropdown.vue create mode 100644 console/src/components/TextEditor.vue create mode 100644 console/src/components/composables/use-extension.ts create mode 100644 console/src/composables/use-content-cache.ts create mode 100644 console/src/composables/use-tag.ts create mode 100644 console/src/extensions/images/index.ts create mode 100644 console/src/extensions/tags/TagsExtensionView.vue create mode 100644 console/src/extensions/tags/index.ts create mode 100644 console/src/index.ts create mode 100644 console/src/plugin-supports/shiki/directive.ts create mode 100644 console/src/plugin-supports/shiki/use-plugin-shiki-script-loader.ts create mode 100644 console/src/plugin-supports/shiki/util.ts create mode 100644 console/src/styles/index.scss create mode 100644 console/src/types/index.ts create mode 100644 console/src/uc/MomentEdit.vue create mode 100644 console/src/uc/MomentItem.vue create mode 100644 console/src/uc/MomentsList.vue create mode 100644 console/src/uc/TagFilterDropdown.vue create mode 100644 console/src/utils/date.ts create mode 100644 console/src/utils/id.ts create mode 100644 console/src/views/MomentsList.vue create mode 100644 console/tsconfig.json create mode 100644 console/uno.config.ts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 images/plugin-moments-preview.png create mode 100644 settings.gradle create mode 100644 src/main/java/run/halo/moments/CommentNotificationReasonPublisher.java create mode 100644 src/main/java/run/halo/moments/CommentReconciler.java create mode 100644 src/main/java/run/halo/moments/Contributor.java create mode 100644 src/main/java/run/halo/moments/CustomEndpointsBuilder.java create mode 100644 src/main/java/run/halo/moments/ListedMoment.java create mode 100644 src/main/java/run/halo/moments/ModelConst.java create mode 100644 src/main/java/run/halo/moments/Moment.java create mode 100644 src/main/java/run/halo/moments/MomentCommentSubject.java create mode 100644 src/main/java/run/halo/moments/MomentEndpoint.java create mode 100644 src/main/java/run/halo/moments/MomentMigration.java create mode 100644 src/main/java/run/halo/moments/MomentQuery.java create mode 100644 src/main/java/run/halo/moments/MomentReconciler.java create mode 100644 src/main/java/run/halo/moments/MomentRouter.java create mode 100644 src/main/java/run/halo/moments/MomentsPlugin.java create mode 100644 src/main/java/run/halo/moments/SchemeRegistered.java create mode 100644 src/main/java/run/halo/moments/Stats.java create mode 100644 src/main/java/run/halo/moments/SubscriptionMigration.java create mode 100644 src/main/java/run/halo/moments/TagReconciler.java create mode 100644 src/main/java/run/halo/moments/event/MomentDeletedEvent.java create mode 100644 src/main/java/run/halo/moments/event/MomentHasNewCommentEvent.java create mode 100644 src/main/java/run/halo/moments/event/MomentUpdatedEvent.java create mode 100644 src/main/java/run/halo/moments/exception/NotFoundException.java create mode 100644 src/main/java/run/halo/moments/finders/MomentFinder.java create mode 100644 src/main/java/run/halo/moments/finders/impl/MomentFinderImpl.java create mode 100644 src/main/java/run/halo/moments/rss/MomentRssProvider.java create mode 100644 src/main/java/run/halo/moments/rss/OldRssRouteRedirectionFilter.java create mode 100644 src/main/java/run/halo/moments/rss/RssAutoConfiguration.java create mode 100644 src/main/java/run/halo/moments/search/DocumentConverter.java create mode 100644 src/main/java/run/halo/moments/search/MomentHaloDocumentsProvider.java create mode 100644 src/main/java/run/halo/moments/search/MomentSearchReconciler.java create mode 100644 src/main/java/run/halo/moments/service/MomentService.java create mode 100644 src/main/java/run/halo/moments/service/RoleService.java create mode 100644 src/main/java/run/halo/moments/service/impl/DefaultRoleService.java create mode 100644 src/main/java/run/halo/moments/service/impl/MomentServiceImpl.java create mode 100644 src/main/java/run/halo/moments/uc/UcMomentEndpoint.java create mode 100644 src/main/java/run/halo/moments/util/AuthorityUtils.java create mode 100644 src/main/java/run/halo/moments/util/MeterUtils.java create mode 100644 src/main/java/run/halo/moments/vo/ContributorVo.java create mode 100644 src/main/java/run/halo/moments/vo/MomentTagVo.java create mode 100644 src/main/java/run/halo/moments/vo/MomentVo.java create mode 100644 src/main/resources/extensions/ext-definition.yaml create mode 100644 src/main/resources/extensions/moment-notification.yaml create mode 100644 src/main/resources/extensions/roleTemplate.yaml create mode 100644 src/main/resources/extensions/settings.yaml create mode 100644 src/main/resources/logo.svg create mode 100644 src/main/resources/plugin.yaml 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 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6d2ba1998c9ebc1d602bcacfeed96be21f88e813 GIT binary patch literal 225310 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 XXTN$C$BxJPKewSkQDIi1fYM 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

0}d9J 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 Sqss{Z0000# literal 0 HcmV?d00001 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"