From 3bcadff1522ff11a9c5fdca10432939f8d6fa211 Mon Sep 17 00:00:00 2001 From: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Date: Fri, 28 Jun 2024 16:54:54 +0200 Subject: [PATCH 01/12] fix: settings changes + ai layout improvements (#5656) * fix: settings changes * fix: improve chat layout --- .../lib/plugins/ai_chat/chat.dart | 4 +- .../lib/plugins/ai_chat/chat_page.dart | 151 +++++++++--------- .../presentation/chat_welcome_page.dart | 25 ++- .../application/user/user_workspace_bloc.dart | 2 +- .../home/menu/sidebar/sidebar.dart | 3 +- .../settings/pages/settings_ai_view.dart | 77 +++++---- .../settings_plan_comparison_dialog.dart | 6 +- .../settings/pages/settings_plan_view.dart | 1 + .../pages/settings_shortcuts_view.dart | 7 +- .../pages/settings_workspace_view.dart | 18 ++- .../settings/settings_dialog.dart | 2 +- .../settings/shared/settings_body.dart | 2 +- 12 files changed, 155 insertions(+), 143 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/chat.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/chat.dart index 4d9869e349..c34b0abcfe 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/chat.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/chat.dart @@ -71,7 +71,6 @@ class AIChatPagePlugin extends Plugin { void dispose() { _viewInfoBloc.close(); notifier.dispose(); - super.dispose(); } } @@ -119,4 +118,7 @@ class AIChatPagePluginWidgetBuilder extends PluginWidgetBuilder @override List get navigationItems => [this]; + + @override + EdgeInsets get contentPadding => EdgeInsets.zero; } diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart index 1a7393a0a9..c6a5e832c3 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/chat_page.dart @@ -1,3 +1,6 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; import 'package:appflowy/plugins/ai_chat/presentation/ai_message_bubble.dart'; @@ -10,12 +13,10 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart'; -import 'package:flutter_chat_ui/flutter_chat_ui.dart' show Chat; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; +import 'package:flutter_chat_ui/flutter_chat_ui.dart' show Chat; import 'presentation/chat_input.dart'; import 'presentation/chat_popmenu.dart'; @@ -27,11 +28,11 @@ import 'presentation/message/user_text_message.dart'; class AIChatUILayout { static EdgeInsets get chatPadding => - isMobile ? EdgeInsets.zero : const EdgeInsets.symmetric(horizontal: 70); + isMobile ? EdgeInsets.zero : const EdgeInsets.symmetric(horizontal: 20); static EdgeInsets get welcomePagePadding => isMobile ? const EdgeInsets.symmetric(horizontal: 20) - : const EdgeInsets.symmetric(horizontal: 100); + : const EdgeInsets.symmetric(horizontal: 50); static double get messageWidthRatio => 0.85; @@ -44,7 +45,8 @@ class AIChatUILayout { query.padding.right, query.viewInsets.bottom + query.padding.bottom, ) - : const EdgeInsets.symmetric(horizontal: 70); + : const EdgeInsets.symmetric(horizontal: 50) + + const EdgeInsets.only(bottom: 20); } } @@ -77,92 +79,89 @@ class _AIChatPageState extends State { Widget build(BuildContext context) { if (widget.userProfile.authenticator == AuthenticatorPB.AppFlowyCloud) { return buildChatWidget(); - } else { - return Center( - child: FlowyText( - LocaleKeys.chat_unsupportedCloudPrompt.tr(), - fontSize: 20, - ), - ); } + + return Center( + child: FlowyText( + LocaleKeys.chat_unsupportedCloudPrompt.tr(), + fontSize: 20, + ), + ); } Widget buildChatWidget() { - return SizedBox.expand( - child: Padding( - padding: AIChatUILayout.chatPadding, - child: BlocProvider( - create: (context) => ChatBloc( - view: widget.view, - userProfile: widget.userProfile, - )..add(const ChatEvent.initialLoad()), - child: BlocBuilder( - builder: (blocContext, state) { - return Chat( - messages: state.messages, - onAttachmentPressed: () {}, - onSendPressed: (types.PartialText message) { - // We use custom bottom widget for chat input, so - // do not need to handle this event. - }, - customBottomWidget: buildChatInput(blocContext), - user: _user, - theme: buildTheme(context), - onEndReached: () async { - if (state.hasMorePrevMessage && - state.loadingPreviousStatus != - const LoadingState.loading()) { - blocContext - .read() - .add(const ChatEvent.startLoadingPrevMessage()); - } - }, - emptyState: BlocBuilder( - builder: (context, state) { - return state.initialLoadingStatus == + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 784), + child: BlocProvider( + create: (_) => ChatBloc( + view: widget.view, + userProfile: widget.userProfile, + )..add(const ChatEvent.initialLoad()), + child: BlocBuilder( + builder: (blocContext, state) => Chat( + messages: state.messages, + onSendPressed: (_) { + // We use custom bottom widget for chat input, so + // do not need to handle this event. + }, + customBottomWidget: buildChatInput(blocContext), + user: _user, + theme: buildTheme(context), + onEndReached: () async { + if (state.hasMorePrevMessage && + state.loadingPreviousStatus != + const LoadingState.loading()) { + blocContext + .read() + .add(const ChatEvent.startLoadingPrevMessage()); + } + }, + emptyState: BlocBuilder( + builder: (_, state) => state.initialLoadingStatus == const LoadingState.finish() ? Padding( padding: AIChatUILayout.welcomePagePadding, child: ChatWelcomePage( - onSelectedQuestion: (question) { - blocContext - .read() - .add(ChatEvent.sendMessage(question)); - }, + onSelectedQuestion: (question) => blocContext + .read() + .add(ChatEvent.sendMessage(question)), ), ) : const Center( child: CircularProgressIndicator.adaptive(), - ); + ), + ), + messageWidthRatio: AIChatUILayout.messageWidthRatio, + textMessageBuilder: ( + textMessage, { + required messageWidth, + required showName, + }) => + _buildAITextMessage(blocContext, textMessage), + bubbleBuilder: ( + child, { + required message, + required nextMessageInGroup, + }) { + if (message.author.id == _user.id) { + return ChatUserMessageBubble( + message: message, + child: child, + ); + } + + return _buildAIBubble(message, blocContext, state, child); }, ), - messageWidthRatio: AIChatUILayout.messageWidthRatio, - textMessageBuilder: ( - textMessage, { - required messageWidth, - required showName, - }) { - return _buildAITextMessage(blocContext, textMessage); - }, - bubbleBuilder: ( - child, { - required message, - required nextMessageInGroup, - }) { - if (message.author.id == _user.id) { - return ChatUserMessageBubble( - message: message, - child: child, - ); - } else { - return _buildAIBubble(message, blocContext, state, child); - } - }, - ); - }, + ), + ), ), ), - ), + ], ); } diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart index 5aceca2025..48c69eef97 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/chat_welcome_page.dart @@ -1,9 +1,10 @@ +import 'package:flutter/material.dart'; + import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flutter/material.dart'; import 'chat_input.dart'; @@ -31,19 +32,15 @@ class ChatWelcomePage extends StatelessWidget { size: Size.square(44), ), const SizedBox(height: 40), - GridView.builder( - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isMobile ? 2 : 4, - crossAxisSpacing: 6, - mainAxisSpacing: 6, - childAspectRatio: 16.0 / 9.0, - ), - itemCount: items.length, - itemBuilder: (context, index) => WelcomeQuestion( - question: items[index], - onSelected: onSelectedQuestion, - ), + Wrap( + children: items + .map( + (i) => WelcomeQuestion( + question: i, + onSelected: onSelectedQuestion, + ), + ) + .toList(), ), ], ), diff --git a/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart index 4e900f91d2..e1ca000939 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/user/user_workspace_bloc.dart @@ -70,7 +70,6 @@ class UserWorkspaceBloc extends Bloc { final workspaceMemberResult = await _userService.getWorkspaceMember(); final workspaceMember = workspaceMemberResult.toNullable(); - emit(state.copyWith(currentWorkspaceMember: workspaceMember)); }, fetchWorkspaces: () async { @@ -510,6 +509,7 @@ class UserWorkspaceState with _$UserWorkspaceState { if (identical(this, other)) return true; return other is UserWorkspaceState && + other.currentWorkspaceMember == currentWorkspaceMember && other.currentWorkspace == currentWorkspace && _deepCollectionEquality.equals(other.workspaces, workspaces) && identical(other.actionResult, actionResult); diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart index 3f5f0057a3..a47d9db862 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:flutter/material.dart'; + import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/blank/blank.dart'; @@ -34,7 +36,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; /// Home Sidebar is the left side bar of the home page. diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart index d5f4a62558..a047afff0f 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart @@ -10,7 +10,6 @@ import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class AIFeatureOnlySupportedWhenUsingAppFlowyCloud extends StatelessWidget { @@ -31,30 +30,25 @@ class AIFeatureOnlySupportedWhenUsingAppFlowyCloud extends StatelessWidget { } class SettingsAIView extends StatelessWidget { - const SettingsAIView({ - super.key, - required this.userProfile, - }); + const SettingsAIView({super.key, required this.userProfile}); final UserProfilePB userProfile; @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => + create: (_) => SettingsAIBloc(userProfile)..add(const SettingsAIEvent.started()), child: BlocBuilder( - builder: (context, state) { - return SettingsBody( - title: LocaleKeys.settings_aiPage_title.tr(), - description: - LocaleKeys.settings_aiPage_keys_aiSettingsDescription.tr(), - children: const [ - AIModelSeclection(), - _AISearchToggle(value: false), - ], - ); - }, + builder: (_, __) => SettingsBody( + title: LocaleKeys.settings_aiPage_title.tr(), + description: + LocaleKeys.settings_aiPage_keys_aiSettingsDescription.tr(), + children: const [ + AIModelSeclection(), + _AISearchToggle(value: false), + ], + ), ), ); } @@ -66,23 +60,22 @@ class AIModelSeclection extends StatelessWidget { @override Widget build(BuildContext context) { return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - FlowyText( - LocaleKeys.settings_aiPage_keys_llmModel.tr(), - fontSize: 14, + Flexible( + child: FlowyText.medium( + LocaleKeys.settings_aiPage_keys_llmModel.tr(), + ), ), const Spacer(), - BlocBuilder( - builder: (context, state) { - return Expanded( - child: SettingsDropdown( + Flexible( + child: BlocBuilder( + builder: (context, state) { + return SettingsDropdown( key: const Key('AIModelDropdown'), - expandWidth: false, - onChanged: (format) { - context.read().add( - SettingsAIEvent.selectModel(format), - ); - }, + onChanged: (model) => context + .read() + .add(SettingsAIEvent.selectModel(model)), selectedOption: state.userProfile.aiModel, options: _availableModels .map( @@ -93,9 +86,9 @@ class AIModelSeclection extends StatelessWidget { ), ) .toList(), - ), - ); - }, + ); + }, + ), ), ], ); @@ -139,17 +132,21 @@ class _AISearchToggle extends StatelessWidget { Widget build(BuildContext context) { return Row( children: [ - Expanded( - child: FlowyText.regular( - LocaleKeys.settings_aiPage_keys_enableAISearchTitle.tr(), - fontSize: 16, - ), + FlowyText.medium( + LocaleKeys.settings_aiPage_keys_enableAISearchTitle.tr(), ), - const HSpace(16), + const Spacer(), BlocBuilder( builder: (context, state) { if (state.aiSettings == null) { - return const CircularProgressIndicator.adaptive(); + return const Padding( + padding: EdgeInsets.only(top: 6), + child: SizedBox( + height: 26, + width: 26, + child: CircularProgressIndicator.adaptive(), + ), + ); } else { return Toggle( value: state.enableSearchIndexing, diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_comparison_dialog.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_comparison_dialog.dart index 96f3cde646..33c4f3ab0f 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_comparison_dialog.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_comparison_dialog.dart @@ -494,6 +494,7 @@ class _ActionButton extends StatelessWidget { ? SystemMouseCursors.click : MouseCursor.defer, child: _drawBorder( + context, isLM: isLM, isUpgrade: isUpgrade, child: Container( @@ -544,7 +545,8 @@ class _ActionButton extends StatelessWidget { ); } - Widget _drawBorder({ + Widget _drawBorder( + BuildContext context, { required bool isLM, required bool isUpgrade, required Widget child, @@ -562,7 +564,7 @@ class _ActionButton extends StatelessWidget { ], ) : null, - border: isUpgrade ? null : Border.all(), + border: isUpgrade ? null : Border.all(color: const Color(0xFF333333)), borderRadius: BorderRadius.circular(16), ), child: child, diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_view.dart index 3c67d6c4f3..edbb698f92 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_plan_view.dart @@ -70,6 +70,7 @@ class SettingsPlanView extends StatelessWidget { usage: state.workspaceUsage, subscription: state.subscription, ), + const VSpace(16), _CurrentPlanBox(subscription: state.subscription), ], ), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_shortcuts_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_shortcuts_view.dart index 27b0596d3a..972e818b55 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_shortcuts_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_shortcuts_view.dart @@ -490,14 +490,11 @@ class KeyBadge extends StatelessWidget { ), child: Center( child: iconData != null - ? FlowySvg( - iconData!, - color: AFThemeExtension.of(context).strongText, - ) + ? FlowySvg(iconData!, color: Colors.black) : FlowyText.medium( keyLabel.toLowerCase(), fontSize: 12, - color: AFThemeExtension.of(context).strongText, + color: Colors.black, ), ), ); diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart index 5cce796f8d..c105d1bb4d 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_workspace_view.dart @@ -24,6 +24,7 @@ import 'package:appflowy/workspace/presentation/settings/shared/setting_list_til import 'package:appflowy/workspace/presentation/settings/shared/settings_alert_dialog.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_category.dart'; +import 'package:appflowy/workspace/presentation/settings/shared/settings_category_spacer.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_dashed_divider.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_dropdown.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_input_field.dart'; @@ -85,6 +86,7 @@ class SettingsWorkspaceView extends StatelessWidget { return SettingsBody( title: LocaleKeys.settings_workspacePage_title.tr(), description: LocaleKeys.settings_workspacePage_description.tr(), + autoSeparate: false, children: [ // We don't allow changing workspace name/icon for local/offline if (userProfile.authenticator != AuthenticatorPB.Local) ...[ @@ -93,6 +95,7 @@ class SettingsWorkspaceView extends StatelessWidget { .tr(), children: [_WorkspaceNameSetting(member: workspaceMember)], ), + const SettingsCategorySpacer(), SettingsCategory( title: LocaleKeys.settings_workspacePage_workspaceIcon_title .tr(), @@ -106,11 +109,14 @@ class SettingsWorkspaceView extends StatelessWidget { ), ], ), + const SettingsCategorySpacer(), ], SettingsCategory( title: LocaleKeys.settings_workspacePage_appearance_title.tr(), children: const [AppearanceSelector()], ), + const VSpace(16), + // const SettingsCategorySpacer(), SettingsCategory( title: LocaleKeys.settings_workspacePage_theme_title.tr(), description: @@ -121,6 +127,7 @@ class SettingsWorkspaceView extends StatelessWidget { _DocumentSelectionColorSetting(), ], ), + const SettingsCategorySpacer(), SettingsCategory( title: LocaleKeys.settings_workspacePage_workspaceFont_title.tr(), @@ -129,7 +136,9 @@ class SettingsWorkspaceView extends StatelessWidget { currentFont: context.read().state.font, ), - const SettingsDashedDivider(), + SettingsDashedDivider( + color: Theme.of(context).colorScheme.outline, + ), SettingsCategory( title: LocaleKeys.settings_workspacePage_textDirection_title .tr(), @@ -140,11 +149,14 @@ class SettingsWorkspaceView extends StatelessWidget { ), ], ), + const VSpace(16), SettingsCategory( title: LocaleKeys.settings_workspacePage_layoutDirection_title .tr(), children: const [_LayoutDirectionSelect()], ), + const SettingsCategorySpacer(), + SettingsCategory( title: LocaleKeys.settings_workspacePage_dateTime_title.tr(), children: [ @@ -156,10 +168,14 @@ class SettingsWorkspaceView extends StatelessWidget { const _DateFormatDropdown(), ], ), + const SettingsCategorySpacer(), + SettingsCategory( title: LocaleKeys.settings_workspacePage_language_title.tr(), children: const [LanguageDropdown()], ), + const SettingsCategorySpacer(), + if (userProfile.authenticator != AuthenticatorPB.Local) ...[ SingleSettingAction( label: LocaleKeys.settings_workspacePage_manageWorkspace_title diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart index e464963ef8..de7f167a45 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart @@ -1,4 +1,3 @@ -import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:flutter/material.dart'; import 'package:appflowy/startup/startup.dart'; @@ -15,6 +14,7 @@ import 'package:appflowy/workspace/presentation/settings/widgets/feature_flags/f import 'package:appflowy/workspace/presentation/settings/widgets/members/workspace_member_page.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_notifications_view.dart'; +import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/shared/settings_body.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/shared/settings_body.dart index 041822947f..8091a72684 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/shared/settings_body.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/shared/settings_body.dart @@ -33,7 +33,7 @@ class SettingsBody extends StatelessWidget { mainAxisSize: MainAxisSize.min, separatorBuilder: () => autoSeparate ? const SettingsCategorySpacer() - : const VSpace(16), + : const SizedBox.shrink(), crossAxisAlignment: CrossAxisAlignment.start, children: children, ), From e1c68c1b72db4ec46a9f76f0f078e19ad2d8bfec Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Sun, 30 Jun 2024 17:38:39 +0800 Subject: [PATCH 02/12] feat: Run Local AI model in AppFlowy (#5655) * chore: load plugin * chore: sidecar * chore: fix test * chore: clippy * chore: save chat config * chore: arc plugin * chore: add plugins * chore: clippy * chore: test streaming * chore: config chat * chore: stream message * chore: response with local ai * chore: fix compile * chore: config ui * chore: fix load plugin * chore: add docs * chore: update docs * chore: disable local ai * chore: fix compile * chore: clippy --- frontend/appflowy_flutter/ios/Podfile.lock | 4 +- .../settings/ai/setting_local_ai_bloc.dart | 195 +++++++ .../settings/pages/settings_ai_view.dart | 138 ++++- frontend/appflowy_tauri/src-tauri/Cargo.lock | 84 +-- frontend/appflowy_tauri/src-tauri/Cargo.toml | 16 +- frontend/appflowy_web/wasm-libs/Cargo.lock | 26 +- frontend/appflowy_web/wasm-libs/Cargo.toml | 17 +- .../appflowy_web_app/src-tauri/Cargo.lock | 73 ++- .../appflowy_web_app/src-tauri/Cargo.toml | 16 +- frontend/rust-lib/Cargo.lock | 93 ++-- frontend/rust-lib/Cargo.toml | 23 +- .../tests/chat/chat_message_test.rs | 16 +- frontend/rust-lib/flowy-chat-pub/src/cloud.rs | 28 +- frontend/rust-lib/flowy-chat/Cargo.toml | 14 + frontend/rust-lib/flowy-chat/dev.env | 5 + frontend/rust-lib/flowy-chat/src/chat.rs | 21 +- .../rust-lib/flowy-chat/src/chat_manager.rs | 59 ++- .../flowy-chat/src/chat_service_impl.rs | 243 +++++++++ frontend/rust-lib/flowy-chat/src/entities.rs | 33 ++ .../rust-lib/flowy-chat/src/event_handler.rs | 33 +- frontend/rust-lib/flowy-chat/src/event_map.rs | 17 +- frontend/rust-lib/flowy-chat/src/lib.rs | 2 + .../flowy-chat/src/local_ai/chat_plugin.rs | 128 +++++ .../src/local_ai/embedding_plugin.rs | 50 ++ .../flowy-chat/src/local_ai/llm_chat.rs | 315 +++++++++++ .../rust-lib/flowy-chat/src/local_ai/mod.rs | 4 + .../src/persistence/chat_message_sql.rs | 14 +- .../flowy-chat/src/persistence/chat_sql.rs | 29 +- .../flowy-chat/tests/chat_test/mod.rs | 41 ++ frontend/rust-lib/flowy-chat/tests/main.rs | 2 + frontend/rust-lib/flowy-chat/tests/util.rs | 171 ++++++ .../flowy-config/src/event_handler.rs | 8 +- .../rust-lib/flowy-config/src/event_map.rs | 4 +- frontend/rust-lib/flowy-core/src/config.rs | 6 +- .../flowy-core/src/deps_resolve/chat_deps.rs | 8 +- .../src/deps_resolve/folder_deps.rs | 4 +- .../flowy-core/src/deps_resolve/user_deps.rs | 4 +- .../rust-lib/flowy-core/src/integrate/log.rs | 15 +- .../flowy-core/src/integrate/server.rs | 6 +- .../flowy-core/src/integrate/trait_impls.rs | 44 +- frontend/rust-lib/flowy-core/src/lib.rs | 17 +- frontend/rust-lib/flowy-error/Cargo.toml | 3 +- frontend/rust-lib/flowy-error/src/code.rs | 3 + frontend/rust-lib/flowy-error/src/errors.rs | 1 + .../rust-lib/flowy-error/src/impl_from/mod.rs | 2 + .../flowy-error/src/impl_from/sidecar.rs | 8 + frontend/rust-lib/flowy-folder/src/manager.rs | 6 +- .../flowy-server/src/af_cloud/impls/chat.rs | 70 +-- .../rust-lib/flowy-server/src/default_impl.rs | 26 +- frontend/rust-lib/flowy-sidecar/Cargo.toml | 23 + .../rust-lib/flowy-sidecar/src/core/mod.rs | 5 + .../rust-lib/flowy-sidecar/src/core/parser.rs | 71 +++ .../rust-lib/flowy-sidecar/src/core/plugin.rs | 205 +++++++ .../flowy-sidecar/src/core/rpc_loop.rs | 269 ++++++++++ .../flowy-sidecar/src/core/rpc_object.rs | 111 ++++ .../flowy-sidecar/src/core/rpc_peer.rs | 500 ++++++++++++++++++ frontend/rust-lib/flowy-sidecar/src/error.rs | 174 ++++++ frontend/rust-lib/flowy-sidecar/src/lib.rs | 3 + .../rust-lib/flowy-sidecar/src/manager.rs | 201 +++++++ .../2024-06-26-015936_chat_setting/down.sql | 1 + .../2024-06-26-015936_chat_setting/up.sql | 13 + frontend/rust-lib/flowy-sqlite/src/kv/kv.rs | 10 +- frontend/rust-lib/flowy-sqlite/src/schema.rs | 13 + .../rust-lib/flowy-storage/src/uploader.rs | 1 + .../rust-lib/flowy-user/src/event_handler.rs | 24 +- .../src/migrations/session_migration.rs | 4 +- .../src/services/authenticate_user.rs | 6 +- .../flowy-user/src/services/cloud_config.rs | 12 +- .../data_import/appflowy_data_import.rs | 4 +- .../flowy-user/src/user_manager/manager.rs | 8 +- frontend/rust-lib/lib-infra/Cargo.toml | 1 + frontend/rust-lib/lib-infra/src/lib.rs | 1 + .../rust-lib/lib-infra/src/stream_util.rs | 21 + frontend/rust-lib/lib-infra/src/util.rs | 58 +- frontend/rust-lib/lib-log/src/lib.rs | 6 +- 75 files changed, 3494 insertions(+), 396 deletions(-) create mode 100644 frontend/appflowy_flutter/lib/workspace/application/settings/ai/setting_local_ai_bloc.dart create mode 100644 frontend/rust-lib/flowy-chat/dev.env create mode 100644 frontend/rust-lib/flowy-chat/src/chat_service_impl.rs create mode 100644 frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs create mode 100644 frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs create mode 100644 frontend/rust-lib/flowy-chat/src/local_ai/llm_chat.rs create mode 100644 frontend/rust-lib/flowy-chat/src/local_ai/mod.rs create mode 100644 frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs create mode 100644 frontend/rust-lib/flowy-chat/tests/main.rs create mode 100644 frontend/rust-lib/flowy-chat/tests/util.rs create mode 100644 frontend/rust-lib/flowy-error/src/impl_from/sidecar.rs create mode 100644 frontend/rust-lib/flowy-sidecar/Cargo.toml create mode 100644 frontend/rust-lib/flowy-sidecar/src/core/mod.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/core/parser.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/core/plugin.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/error.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/lib.rs create mode 100644 frontend/rust-lib/flowy-sidecar/src/manager.rs create mode 100644 frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/down.sql create mode 100644 frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/up.sql create mode 100644 frontend/rust-lib/lib-infra/src/stream_util.rs diff --git a/frontend/appflowy_flutter/ios/Podfile.lock b/frontend/appflowy_flutter/ios/Podfile.lock index 93a8eb77e1..10aa1f9df1 100644 --- a/frontend/appflowy_flutter/ios/Podfile.lock +++ b/frontend/appflowy_flutter/ios/Podfile.lock @@ -170,7 +170,7 @@ SPEC CHECKSUMS: file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 + fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425 integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 @@ -191,4 +191,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca -COCOAPODS: 1.15.2 +COCOAPODS: 1.11.3 diff --git a/frontend/appflowy_flutter/lib/workspace/application/settings/ai/setting_local_ai_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/settings/ai/setting_local_ai_bloc.dart new file mode 100644 index 0000000000..e8d9c5eb31 --- /dev/null +++ b/frontend/appflowy_flutter/lib/workspace/application/settings/ai/setting_local_ai_bloc.dart @@ -0,0 +1,195 @@ +import 'dart:io'; + +import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart'; +import 'package:appflowy_backend/dispatch/dispatch.dart'; +import 'package:appflowy_backend/log.dart'; +import 'package:appflowy_backend/protobuf/flowy-chat/entities.pb.dart'; +import 'package:bloc/bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:path/path.dart' as path; +import 'package:protobuf/protobuf.dart'; + +part 'setting_local_ai_bloc.freezed.dart'; + +class SettingsAILocalBloc + extends Bloc { + SettingsAILocalBloc() : super(const SettingsAILocalState()) { + on(_handleEvent); + } + + /// Handles incoming events and dispatches them to the appropriate handler. + Future _handleEvent( + SettingsAILocalEvent event, + Emitter emit, + ) async { + await event.when( + started: _handleStarted, + didUpdateAISetting: (settings) async { + _handleDidUpdateAISetting(settings, emit); + }, + updateChatBin: (chatBinPath) async { + await _handleUpdatePath( + filePath: chatBinPath, + emit: emit, + stateUpdater: () => state.copyWith( + chatBinPath: chatBinPath.trim(), + chatBinPathError: null, + ), + errorUpdater: (error) => state.copyWith(chatBinPathError: error), + ); + }, + updateChatModelPath: (chatModelPath) async { + await _handleUpdatePath( + filePath: chatModelPath, + emit: emit, + stateUpdater: () => state.copyWith( + chatModelPath: chatModelPath.trim(), + chatModelPathError: null, + ), + errorUpdater: (error) => state.copyWith(chatModelPathError: error), + ); + }, + toggleLocalAI: () async { + emit(state.copyWith(localAIEnabled: !state.localAIEnabled)); + }, + saveSetting: () async { + _handleSaveSetting(); + }, + ); + } + + /// Handles the event to fetch local AI settings when the application starts. + Future _handleStarted() async { + final result = await ChatEventGetLocalAISetting().send(); + result.fold( + (setting) { + if (!isClosed) { + add(SettingsAILocalEvent.didUpdateAISetting(setting)); + } + }, + (err) => Log.error('Failed to get local AI setting: $err'), + ); + } + + /// Handles the event to update the AI settings in the state. + void _handleDidUpdateAISetting( + LocalLLMSettingPB settings, + Emitter emit, + ) { + final newState = state.copyWith( + aiSettings: settings, + chatBinPath: settings.chatBinPath, + chatModelPath: settings.chatModelPath, + localAIEnabled: settings.enabled, + loadingState: const LoadingState.finish(), + ); + emit(newState.copyWith(saveButtonEnabled: _saveButtonEnabled(newState))); + } + + /// Handles updating file paths (both chat binary and chat model paths). + Future _handleUpdatePath({ + required String filePath, + required Emitter emit, + required SettingsAILocalState Function() stateUpdater, + required SettingsAILocalState Function(String) errorUpdater, + }) async { + filePath = filePath.trim(); + if (filePath.isEmpty) { + emit(stateUpdater()); + return; + } + + final validationError = await _validatePath(filePath); + if (validationError != null) { + emit(errorUpdater(validationError)); + return; + } + + final newState = stateUpdater(); + emit(newState.copyWith(saveButtonEnabled: _saveButtonEnabled(newState))); + } + + /// Validates the provided file path. + Future _validatePath(String filePath) async { + if (!isAbsolutePath(filePath)) { + return "$filePath must be absolute"; + } + + if (!await pathExists(filePath)) { + return "$filePath does not exist"; + } + return null; + } + + /// Handles saving the updated settings. + void _handleSaveSetting() { + if (state.aiSettings == null) return; + state.aiSettings!.freeze(); + final newSetting = state.aiSettings!.rebuild((value) { + value + ..chatBinPath = state.chatBinPath ?? value.chatBinPath + ..chatModelPath = state.chatModelPath ?? value.chatModelPath + ..enabled = state.localAIEnabled; + }); + + ChatEventUpdateLocalAISetting(newSetting).send().then((result) { + result.fold( + (_) { + if (!isClosed) { + add(SettingsAILocalEvent.didUpdateAISetting(newSetting)); + } + }, + (err) => Log.error('Failed to update local AI setting: $err'), + ); + }); + } + + /// Determines if the save button should be enabled based on the state. + bool _saveButtonEnabled(SettingsAILocalState newState) { + return newState.chatBinPathError == null && + newState.chatModelPathError == null && + newState.chatBinPath != null && + newState.chatModelPath != null; + } +} + +@freezed +class SettingsAILocalEvent with _$SettingsAILocalEvent { + const factory SettingsAILocalEvent.started() = _Started; + const factory SettingsAILocalEvent.didUpdateAISetting( + LocalLLMSettingPB settings, + ) = _GetAISetting; + const factory SettingsAILocalEvent.updateChatBin(String chatBinPath) = + _UpdateChatBin; + const factory SettingsAILocalEvent.updateChatModelPath(String chatModelPath) = + _UpdateChatModelPath; + const factory SettingsAILocalEvent.toggleLocalAI() = _EnableLocalAI; + const factory SettingsAILocalEvent.saveSetting() = _SaveSetting; +} + +@freezed +class SettingsAILocalState with _$SettingsAILocalState { + const factory SettingsAILocalState({ + LocalLLMSettingPB? aiSettings, + String? chatBinPath, + String? chatBinPathError, + String? chatModelPath, + String? chatModelPathError, + @Default(false) bool localAIEnabled, + @Default(false) bool saveButtonEnabled, + @Default(LoadingState.loading()) LoadingState loadingState, + }) = _SettingsAILocalState; +} + +/// Checks if a given file path is absolute. +bool isAbsolutePath(String filePath) { + return path.isAbsolute(filePath); +} + +/// Checks if a given file or directory path exists. +Future pathExists(String filePath) async { + final file = File(filePath); + final directory = Directory(filePath); + + return await file.exists() || await directory.exists(); +} diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart index a047afff0f..a64f602bbe 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_ai_view.dart @@ -1,3 +1,7 @@ +import 'package:appflowy/workspace/application/settings/ai/setting_local_ai_bloc.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter/material.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; @@ -40,22 +44,26 @@ class SettingsAIView extends StatelessWidget { create: (_) => SettingsAIBloc(userProfile)..add(const SettingsAIEvent.started()), child: BlocBuilder( - builder: (_, __) => SettingsBody( - title: LocaleKeys.settings_aiPage_title.tr(), - description: - LocaleKeys.settings_aiPage_keys_aiSettingsDescription.tr(), - children: const [ - AIModelSeclection(), - _AISearchToggle(value: false), - ], - ), + builder: (context, state) { + return SettingsBody( + title: LocaleKeys.settings_aiPage_title.tr(), + description: + LocaleKeys.settings_aiPage_keys_aiSettingsDescription.tr(), + children: const [ + AIModelSelection(), + _AISearchToggle(value: false), + // Disable local AI configuration for now. It's not ready for production. + // LocalAIConfiguration(), + ], + ); + }, ), ); } } -class AIModelSeclection extends StatelessWidget { - const AIModelSeclection({super.key}); +class AIModelSelection extends StatelessWidget { + const AIModelSelection({super.key}); @override Widget build(BuildContext context) { @@ -161,3 +169,111 @@ class _AISearchToggle extends StatelessWidget { ); } } + +class LocalAIConfiguration extends StatelessWidget { + const LocalAIConfiguration({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => + SettingsAILocalBloc()..add(const SettingsAILocalEvent.started()), + child: BlocBuilder( + builder: (context, state) { + return state.loadingState.when( + loading: () { + return const SizedBox.shrink(); + }, + finish: () { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AIConfigurateTextField( + title: 'chat bin path', + hitText: '', + errorText: state.chatBinPathError ?? '', + value: state.aiSettings?.chatBinPath ?? '', + onChanged: (value) { + context.read().add( + SettingsAILocalEvent.updateChatBin(value), + ); + }, + ), + const VSpace(16), + AIConfigurateTextField( + title: 'chat model path', + hitText: '', + errorText: state.chatModelPathError ?? '', + value: state.aiSettings?.chatModelPath ?? '', + onChanged: (value) { + context.read().add( + SettingsAILocalEvent.updateChatModelPath(value), + ); + }, + ), + const VSpace(16), + Toggle( + value: state.localAIEnabled, + onChanged: (_) => context + .read() + .add(const SettingsAILocalEvent.toggleLocalAI()), + ), + const VSpace(16), + FlowyButton( + disable: !state.saveButtonEnabled, + text: const FlowyText("save"), + onTap: () { + context.read().add( + const SettingsAILocalEvent.saveSetting(), + ); + }, + ), + ], + ); + }, + ); + }, + ), + ); + } +} + +class AIConfigurateTextField extends StatelessWidget { + const AIConfigurateTextField({ + required this.title, + required this.hitText, + required this.errorText, + required this.value, + required this.onChanged, + super.key, + }); + + final String title; + final String hitText; + final String errorText; + final String value; + final void Function(String) onChanged; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FlowyText( + title, + ), + const VSpace(8), + RoundedInputField( + hintText: hitText, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + normalBorderColor: Theme.of(context).colorScheme.outline, + errorBorderColor: Theme.of(context).colorScheme.error, + cursorColor: Theme.of(context).colorScheme.primary, + errorText: errorText, + initialValue: value, + onChanged: onChanged, + ), + ], + ); + } +} diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index cf43f97f8d..e85feb9663 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -172,7 +172,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -772,7 +772,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -821,7 +821,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -833,7 +833,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -907,7 +907,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -931,7 +931,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -961,7 +961,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -981,7 +981,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "bytes", @@ -996,7 +996,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "chrono", @@ -1034,7 +1034,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-stream", @@ -1073,7 +1073,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -1098,7 +1098,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1115,7 +1115,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -1294,12 +1294,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1344,7 +1341,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa 1.0.6", - "phf 0.11.2", + "phf 0.8.0", "smallvec", ] @@ -1455,7 +1452,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -1856,6 +1853,7 @@ dependencies = [ "flowy-derive", "flowy-error", "flowy-notification", + "flowy-sidecar", "flowy-sqlite", "futures", "lib-dispatch", @@ -2319,6 +2317,24 @@ dependencies = [ "serde_repr", ] +[[package]] +name = "flowy-sidecar" +version = "0.1.0" +dependencies = [ + "anyhow", + "crossbeam-utils", + "lib-infra", + "log", + "once_cell", + "parking_lot 0.12.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "flowy-sqlite" version = "0.1.0" @@ -2430,7 +2446,6 @@ dependencies = [ "anyhow", "base64 0.21.5", "chrono", - "client-api", "collab", "collab-entity", "flowy-error", @@ -2899,7 +2914,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -2916,7 +2931,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -3348,7 +3363,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -3596,6 +3611,7 @@ dependencies = [ "async-trait", "atomic_refcell", "bytes", + "cfg-if", "chrono", "futures", "futures-core", @@ -4216,9 +4232,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oneshot" @@ -4855,7 +4871,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", "heck 0.4.1", - "itertools 0.11.0", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -4876,7 +4892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.47", @@ -5690,9 +5706,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa 1.0.6", "ryu", @@ -5840,7 +5856,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -6847,9 +6863,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 0af253b25a..6dd8b25b86 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -52,7 +52,7 @@ collab-user = { version = "0.2" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d61524d63605aa010afa6a734cbbe4fb4cd68ea1" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [dependencies] serde_json.workspace = true @@ -106,10 +106,10 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } diff --git a/frontend/appflowy_web/wasm-libs/Cargo.lock b/frontend/appflowy_web/wasm-libs/Cargo.lock index 7b3fe44248..ecde57219d 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.lock +++ b/frontend/appflowy_web/wasm-libs/Cargo.lock @@ -215,7 +215,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -235,7 +235,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -561,7 +561,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -610,7 +610,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -622,7 +622,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -800,7 +800,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -825,7 +825,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1039,7 +1039,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -1666,7 +1666,6 @@ dependencies = [ "anyhow", "base64 0.21.7", "chrono", - "client-api", "collab", "collab-entity", "flowy-error", @@ -1924,7 +1923,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -1941,7 +1940,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -2242,7 +2241,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -2383,6 +2382,7 @@ dependencies = [ "async-trait", "atomic_refcell", "bytes", + "cfg-if 1.0.0", "chrono", "futures", "futures-core", @@ -3956,7 +3956,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", diff --git a/frontend/appflowy_web/wasm-libs/Cargo.toml b/frontend/appflowy_web/wasm-libs/Cargo.toml index 6e50744953..a3578b9cb3 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.toml +++ b/frontend/appflowy_web/wasm-libs/Cargo.toml @@ -20,7 +20,6 @@ flowy-derive = { path = "../../rust-lib/build-tool/flowy-derive" } flowy-codegen = { path = "../../rust-lib/build-tool/flowy-codegen" } flowy-document = { path = "../../rust-lib/flowy-document" } flowy-folder = { path = "../../rust-lib/flowy-folder" } -flowy-storage = { path = "../../rust-lib/flowy-storage" } lib-infra = { path = "../../rust-lib/lib-infra" } bytes = { version = "1.5" } protobuf = { version = "2.28.0" } @@ -55,7 +54,7 @@ yrs = "0.18.8" # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d61524d63605aa010afa6a734cbbe4fb4cd68ea1" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [profile.dev] opt-level = 0 @@ -68,10 +67,10 @@ opt-level = 3 codegen-units = 1 [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 64bdd8a62a..05a7af34e6 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -746,7 +746,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -795,7 +795,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -807,7 +807,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -944,7 +944,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "bytes", @@ -979,7 +979,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "chrono", @@ -1017,7 +1017,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-stream", @@ -1056,7 +1056,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -1081,7 +1081,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -1098,7 +1098,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -1284,9 +1284,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1331,7 +1331,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa 1.0.10", - "phf 0.11.2", + "phf 0.8.0", "smallvec", ] @@ -1442,7 +1442,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -1893,6 +1893,7 @@ dependencies = [ "flowy-derive", "flowy-error", "flowy-notification", + "flowy-sidecar", "flowy-sqlite", "futures", "lib-dispatch", @@ -2356,6 +2357,24 @@ dependencies = [ "serde_repr", ] +[[package]] +name = "flowy-sidecar" +version = "0.1.0" +dependencies = [ + "anyhow", + "crossbeam-utils", + "lib-infra", + "log", + "once_cell", + "parking_lot 0.12.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "flowy-sqlite" version = "0.1.0" @@ -2467,7 +2486,6 @@ dependencies = [ "anyhow", "base64 0.21.7", "chrono", - "client-api", "collab", "collab-entity", "flowy-error", @@ -2973,7 +2991,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -2990,7 +3008,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -3427,7 +3445,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -3680,6 +3698,7 @@ dependencies = [ "async-trait", "atomic_refcell", "bytes", + "cfg-if", "chrono", "futures", "futures-core", @@ -4936,7 +4955,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", "heck 0.4.1", - "itertools 0.11.0", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -4957,7 +4976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.55", @@ -5782,9 +5801,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "indexmap 2.2.6", "itoa 1.0.10", @@ -5935,7 +5954,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index 30d60cba0d..c87aa9e925 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -52,7 +52,7 @@ collab-user = { version = "0.2" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d61524d63605aa010afa6a734cbbe4fb4cd68ea1" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [dependencies] serde_json.workspace = true @@ -107,10 +107,10 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 08cff91a24..215fbdd43b 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -163,7 +163,7 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -664,7 +664,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "again", "anyhow", @@ -713,7 +713,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "collab-entity", "collab-rt-entity", @@ -725,7 +725,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "futures-channel", "futures-util", @@ -768,7 +768,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -792,7 +792,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-trait", @@ -822,7 +822,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -842,7 +842,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "bytes", @@ -857,7 +857,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "chrono", @@ -895,7 +895,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "async-stream", @@ -934,7 +934,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bincode", @@ -959,7 +959,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "async-trait", @@ -976,7 +976,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" dependencies = [ "anyhow", "collab", @@ -1146,12 +1146,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1279,7 +1276,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -1471,9 +1468,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -1669,22 +1666,30 @@ name = "flowy-chat" version = "0.1.0" dependencies = [ "allo-isolate", + "anyhow", "bytes", "dashmap", + "dotenv", "flowy-chat-pub", "flowy-codegen", "flowy-derive", "flowy-error", "flowy-notification", + "flowy-sidecar", "flowy-sqlite", "futures", "lib-dispatch", "lib-infra", "log", + "parking_lot 0.12.1", "protobuf", + "serde", + "serde_json", "strum_macros 0.21.1", "tokio", + "tokio-stream", "tracing", + "tracing-subscriber", "uuid", "validator", ] @@ -1957,6 +1962,7 @@ dependencies = [ "fancy-regex 0.11.0", "flowy-codegen", "flowy-derive", + "flowy-sidecar", "flowy-sqlite", "lib-dispatch", "protobuf", @@ -2147,6 +2153,24 @@ dependencies = [ "serde_repr", ] +[[package]] +name = "flowy-sidecar" +version = "0.1.0" +dependencies = [ + "anyhow", + "crossbeam-utils", + "lib-infra", + "log", + "once_cell", + "parking_lot 0.12.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "flowy-sqlite" version = "0.1.0" @@ -2572,7 +2596,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "futures-util", @@ -2589,7 +2613,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -2954,7 +2978,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "bytes", @@ -3104,6 +3128,7 @@ dependencies = [ "atomic_refcell", "brotli", "bytes", + "cfg-if", "chrono", "futures", "futures-core", @@ -3352,9 +3377,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -3562,9 +3587,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oneshot" @@ -4951,9 +4976,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -5054,7 +5079,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=d61524d63605aa010afa6a734cbbe4fb4cd68ea1#d61524d63605aa010afa6a734cbbe4fb4cd68ea1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" dependencies = [ "anyhow", "app-error", @@ -5752,9 +5777,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 4edd92bab9..70b6b5e7e2 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -31,6 +31,8 @@ members = [ "flowy-search-pub", "flowy-chat", "flowy-chat-pub", + "flowy-storage-pub", + "flowy-sidecar", ] resolver = "2" @@ -66,6 +68,7 @@ collab-integrate = { workspace = true, path = "collab-integrate" } flowy-date = { workspace = true, path = "flowy-date" } flowy-chat = { workspace = true, path = "flowy-chat" } flowy-chat-pub = { workspace = true, path = "flowy-chat-pub" } +flowy-sidecar = { workspace = true, path = "flowy-sidecar" } anyhow = "1.0" tracing = "0.1.40" bytes = "1.5.0" @@ -93,11 +96,11 @@ validator = { version = "0.16.1", features = ["derive"] } # Please using the following command to update the revision id # Current directory: frontend -# Run the script: +# Run the script.add_workspace_members: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d61524d63605aa010afa6a734cbbe4fb4cd68ea1" } -client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d61524d63605aa010afa6a734cbbe4fb4cd68ea1" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } +client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } [profile.dev] opt-level = 1 @@ -136,10 +139,10 @@ rocksdb = { git = "https://github.com/LucasXu0/rust-rocksdb", rev = "21cf4a23ec1 # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } diff --git a/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs b/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs index 8594193ab6..8e84dfe827 100644 --- a/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs +++ b/frontend/rust-lib/event-integration-test/tests/chat/chat_message_test.rs @@ -5,7 +5,7 @@ use flowy_chat::entities::ChatMessageListPB; use flowy_chat::notification::ChatNotification; use flowy_chat_pub::cloud::ChatMessageType; -use futures_util::StreamExt; + use std::time::Duration; #[tokio::test] @@ -19,8 +19,8 @@ async fn af_cloud_create_chat_message_test() { let chat_id = view.id.clone(); let chat_service = test.server_provider.get_server().unwrap().chat_service(); for i in 0..10 { - let mut stream = chat_service - .send_chat_message( + let _ = chat_service + .save_question( ¤t_workspace.id, &chat_id, &format!("hello world {}", i), @@ -28,9 +28,6 @@ async fn af_cloud_create_chat_message_test() { ) .await .unwrap(); - while let Some(message) = stream.next().await { - message.unwrap(); - } } let rx = test .notification_sender @@ -77,8 +74,8 @@ async fn af_cloud_load_remote_system_message_test() { let chat_service = test.server_provider.get_server().unwrap().chat_service(); for i in 0..10 { - let mut stream = chat_service - .send_chat_message( + let _ = chat_service + .save_question( ¤t_workspace.id, &chat_id, &format!("hello server {}", i), @@ -86,9 +83,6 @@ async fn af_cloud_load_remote_system_message_test() { ) .await .unwrap(); - while let Some(message) = stream.next().await { - message.unwrap(); - } } let rx = test diff --git a/frontend/rust-lib/flowy-chat-pub/src/cloud.rs b/frontend/rust-lib/flowy-chat-pub/src/cloud.rs index 7ea853f1fa..fae11d979e 100644 --- a/frontend/rust-lib/flowy-chat-pub/src/cloud.rs +++ b/frontend/rust-lib/flowy-chat-pub/src/cloud.rs @@ -12,7 +12,7 @@ use lib_infra::async_trait::async_trait; use lib_infra::future::FutureResult; pub type ChatMessageStream = BoxStream<'static, Result>; -pub type StreamAnswer = BoxStream<'static, Result>; +pub type StreamAnswer = BoxStream<'static, Result>; pub type StreamComplete = BoxStream<'static, Result>; #[async_trait] pub trait ChatCloudService: Send + Sync + 'static { @@ -23,15 +23,7 @@ pub trait ChatCloudService: Send + Sync + 'static { chat_id: &str, ) -> FutureResult<(), FlowyError>; - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result; - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, @@ -47,13 +39,20 @@ pub trait ChatCloudService: Send + Sync + 'static { question_id: i64, ) -> FutureResult; - async fn stream_answer( + async fn ask_question( &self, workspace_id: &str, chat_id: &str, message_id: i64, ) -> Result; + async fn generate_answer( + &self, + workspace_id: &str, + chat_id: &str, + question_message_id: i64, + ) -> Result; + fn get_chat_messages( &self, workspace_id: &str, @@ -69,13 +68,6 @@ pub trait ChatCloudService: Send + Sync + 'static { message_id: i64, ) -> FutureResult; - fn generate_answer( - &self, - workspace_id: &str, - chat_id: &str, - question_message_id: i64, - ) -> FutureResult; - async fn stream_complete( &self, workspace_id: &str, diff --git a/frontend/rust-lib/flowy-chat/Cargo.toml b/frontend/rust-lib/flowy-chat/Cargo.toml index 1abbb62a17..879b707c1a 100644 --- a/frontend/rust-lib/flowy-chat/Cargo.toml +++ b/frontend/rust-lib/flowy-chat/Cargo.toml @@ -11,6 +11,8 @@ flowy-notification = { workspace = true } flowy-error = { path = "../flowy-error", features = [ "impl_from_dispatch_error", "impl_from_collab_folder", + "impl_from_sqlite", + "impl_from_sidecar" ] } lib-dispatch = { workspace = true } tracing.workspace = true @@ -27,6 +29,17 @@ tokio.workspace = true futures.workspace = true allo-isolate = { version = "^0.1", features = ["catch-unwind"] } log = "0.4.21" +flowy-sidecar = { workspace = true, features = ["verbose"] } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +anyhow = "1.0.86" +tokio-stream = "0.1.15" +parking_lot.workspace = true + +[dev-dependencies] +dotenv = "0.15.0" +uuid.workspace = true +tracing-subscriber = { version = "0.3.17", features = ["registry", "env-filter", "ansi", "json"] } [build-dependencies] flowy-codegen.workspace = true @@ -35,3 +48,4 @@ flowy-codegen.workspace = true dart = ["flowy-codegen/dart", "flowy-notification/dart"] tauri_ts = ["flowy-codegen/ts", "flowy-notification/tauri_ts"] web_ts = ["flowy-codegen/ts", "flowy-notification/web_ts"] + diff --git a/frontend/rust-lib/flowy-chat/dev.env b/frontend/rust-lib/flowy-chat/dev.env new file mode 100644 index 0000000000..5cff5dd858 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/dev.env @@ -0,0 +1,5 @@ + +CHAT_BIN_PATH= +LOCAL_AI_MODEL_DIR= +LOCAL_AI_CHAT_MODEL_NAME= +LOCAL_AI_EMBEDDING_MODEL_NAME= diff --git a/frontend/rust-lib/flowy-chat/src/chat.rs b/frontend/rust-lib/flowy-chat/src/chat.rs index 3581c8ef49..2854d12a92 100644 --- a/frontend/rust-lib/flowy-chat/src/chat.rs +++ b/frontend/rust-lib/flowy-chat/src/chat.rs @@ -1,4 +1,5 @@ use crate::chat_manager::ChatUserService; +use crate::chat_service_impl::ChatService; use crate::entities::{ ChatMessageErrorPB, ChatMessageListPB, ChatMessagePB, RepeatedRelatedQuestionPB, }; @@ -25,7 +26,7 @@ pub struct Chat { chat_id: String, uid: i64, user_service: Arc, - cloud_service: Arc, + chat_service: Arc, prev_message_state: Arc>, latest_message_id: Arc, stop_stream: Arc, @@ -37,12 +38,12 @@ impl Chat { uid: i64, chat_id: String, user_service: Arc, - cloud_service: Arc, + chat_service: Arc, ) -> Chat { Chat { uid, chat_id, - cloud_service, + chat_service, user_service, prev_message_state: Arc::new(RwLock::new(PrevMessageState::HasMore)), latest_message_id: Default::default(), @@ -92,8 +93,8 @@ impl Chat { let workspace_id = self.user_service.workspace_id()?; let question = self - .cloud_service - .send_question(&workspace_id, &self.chat_id, message, message_type) + .chat_service + .save_question(&workspace_id, &self.chat_id, message, message_type) .await .map_err(|err| { error!("Failed to send question: {}", err); @@ -109,12 +110,12 @@ impl Chat { let stop_stream = self.stop_stream.clone(); let chat_id = self.chat_id.clone(); let question_id = question.message_id; - let cloud_service = self.cloud_service.clone(); + let cloud_service = self.chat_service.clone(); let user_service = self.user_service.clone(); tokio::spawn(async move { let mut text_sink = IsolateSink::new(Isolate::new(text_stream_port)); match cloud_service - .stream_answer(&workspace_id, &chat_id, question_id) + .ask_question(&workspace_id, &chat_id, question_id) .await { Ok(mut stream) => { @@ -300,7 +301,7 @@ impl Chat { ); let workspace_id = self.user_service.workspace_id()?; let chat_id = self.chat_id.clone(); - let cloud_service = self.cloud_service.clone(); + let cloud_service = self.chat_service.clone(); let user_service = self.user_service.clone(); let uid = self.uid; let prev_message_state = self.prev_message_state.clone(); @@ -369,7 +370,7 @@ impl Chat { ) -> Result { let workspace_id = self.user_service.workspace_id()?; let resp = self - .cloud_service + .chat_service .get_related_message(&workspace_id, &self.chat_id, message_id) .await?; @@ -391,7 +392,7 @@ impl Chat { ); let workspace_id = self.user_service.workspace_id()?; let answer = self - .cloud_service + .chat_service .generate_answer(&workspace_id, &self.chat_id, question_message_id) .await?; diff --git a/frontend/rust-lib/flowy-chat/src/chat_manager.rs b/frontend/rust-lib/flowy-chat/src/chat_manager.rs index 4e22f26aa7..20fd340698 100644 --- a/frontend/rust-lib/flowy-chat/src/chat_manager.rs +++ b/frontend/rust-lib/flowy-chat/src/chat_manager.rs @@ -1,9 +1,13 @@ use crate::chat::Chat; +use crate::chat_service_impl::ChatService; use crate::entities::{ChatMessageListPB, ChatMessagePB, RepeatedRelatedQuestionPB}; +use crate::local_ai::llm_chat::{LocalChatLLMChat, LocalLLMSetting}; use crate::persistence::{insert_chat, ChatTable}; use dashmap::DashMap; use flowy_chat_pub::cloud::{ChatCloudService, ChatMessageType}; use flowy_error::{FlowyError, FlowyResult}; +use flowy_sidecar::manager::SidecarManager; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; use lib_infra::util::timestamp; use std::sync::Arc; @@ -17,25 +21,56 @@ pub trait ChatUserService: Send + Sync + 'static { } pub struct ChatManager { - pub(crate) cloud_service: Arc, - pub(crate) user_service: Arc, + pub chat_service: Arc, + pub user_service: Arc, chats: Arc>>, + store_preferences: Arc, } +const LOCAL_AI_SETTING_KEY: &str = "local_ai_setting"; impl ChatManager { pub fn new( cloud_service: Arc, user_service: impl ChatUserService, + store_preferences: Arc, ) -> ChatManager { let user_service = Arc::new(user_service); + let local_ai_setting = store_preferences + .get_object::(LOCAL_AI_SETTING_KEY) + .unwrap_or_default(); + let sidecar_manager = Arc::new(SidecarManager::new()); + + // setup local AI chat plugin + let local_llm_ctrl = Arc::new(LocalChatLLMChat::new(sidecar_manager)); + // setup local chat service + let chat_service = Arc::new(ChatService::new( + user_service.clone(), + cloud_service, + local_llm_ctrl, + local_ai_setting, + )); Self { - cloud_service, + chat_service, user_service, chats: Arc::new(DashMap::new()), + store_preferences, } } + pub fn update_local_ai_setting(&self, setting: LocalLLMSetting) -> FlowyResult<()> { + self.chat_service.update_local_ai_setting(setting.clone())?; + self + .store_preferences + .set_object(LOCAL_AI_SETTING_KEY, setting)?; + Ok(()) + } + + pub fn get_local_ai_setting(&self) -> FlowyResult { + let setting = self.chat_service.get_local_ai_setting(); + Ok(setting) + } + pub async fn open_chat(&self, chat_id: &str) -> Result<(), FlowyError> { trace!("open chat: {}", chat_id); self.chats.entry(chat_id.to_string()).or_insert_with(|| { @@ -43,20 +78,24 @@ impl ChatManager { self.user_service.user_id().unwrap(), chat_id.to_string(), self.user_service.clone(), - self.cloud_service.clone(), + self.chat_service.clone(), )) }); + self.chat_service.notify_open_chat(chat_id); Ok(()) } - pub async fn close_chat(&self, _chat_id: &str) -> Result<(), FlowyError> { + pub async fn close_chat(&self, chat_id: &str) -> Result<(), FlowyError> { + trace!("close chat: {}", chat_id); + self.chat_service.notify_close_chat(chat_id); Ok(()) } pub async fn delete_chat(&self, chat_id: &str) -> Result<(), FlowyError> { if let Some((_, chat)) = self.chats.remove(chat_id) { chat.close(); + self.chat_service.notify_close_chat(chat_id); } Ok(()) } @@ -64,7 +103,7 @@ impl ChatManager { pub async fn create_chat(&self, uid: &i64, chat_id: &str) -> Result, FlowyError> { let workspace_id = self.user_service.workspace_id()?; self - .cloud_service + .chat_service .create_chat(uid, &workspace_id, chat_id) .await?; save_chat(self.user_service.sqlite_connection(*uid)?, chat_id)?; @@ -73,7 +112,7 @@ impl ChatManager { self.user_service.user_id().unwrap(), chat_id.to_string(), self.user_service.clone(), - self.cloud_service.clone(), + self.chat_service.clone(), )); self.chats.insert(chat_id.to_string(), chat.clone()); Ok(chat) @@ -101,7 +140,7 @@ impl ChatManager { self.user_service.user_id().unwrap(), chat_id.to_string(), self.user_service.clone(), - self.cloud_service.clone(), + self.chat_service.clone(), )); self.chats.insert(chat_id.to_string(), chat.clone()); Ok(chat) @@ -183,6 +222,10 @@ fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> { chat_id: chat_id.to_string(), created_at: timestamp(), name: "".to_string(), + local_model_path: "".to_string(), + local_model_name: "".to_string(), + local_enabled: false, + sync_to_cloud: true, }; insert_chat(conn, &row)?; diff --git a/frontend/rust-lib/flowy-chat/src/chat_service_impl.rs b/frontend/rust-lib/flowy-chat/src/chat_service_impl.rs new file mode 100644 index 0000000000..59dd810dd8 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/chat_service_impl.rs @@ -0,0 +1,243 @@ +use crate::chat_manager::ChatUserService; +use crate::local_ai::llm_chat::{LocalChatLLMChat, LocalLLMSetting}; +use crate::persistence::select_single_message; +use flowy_chat_pub::cloud::{ + ChatCloudService, ChatMessage, ChatMessageType, CompletionType, MessageCursor, + RepeatedChatMessage, RepeatedRelatedQuestion, StreamAnswer, StreamComplete, +}; +use flowy_error::{FlowyError, FlowyResult}; +use futures::{StreamExt, TryStreamExt}; +use lib_infra::async_trait::async_trait; +use lib_infra::future::FutureResult; +use parking_lot::RwLock; +use std::sync::Arc; +use tracing::{error, info, trace}; + +pub struct ChatService { + pub cloud_service: Arc, + user_service: Arc, + local_llm_chat: Arc, + local_llm_setting: Arc>, +} + +impl ChatService { + pub fn new( + user_service: Arc, + cloud_service: Arc, + local_llm_ctrl: Arc, + local_llm_setting: LocalLLMSetting, + ) -> Self { + if local_llm_setting.enabled { + setup_local_chat(&local_llm_setting, local_llm_ctrl.clone()); + } + + Self { + user_service, + cloud_service, + local_llm_chat: local_llm_ctrl, + local_llm_setting: Arc::new(RwLock::new(local_llm_setting)), + } + } + + pub fn notify_open_chat(&self, chat_id: &str) { + if self.local_llm_setting.read().enabled { + trace!("[Chat Plugin] notify open chat: {}", chat_id); + let chat_id = chat_id.to_string(); + let weak_ctrl = Arc::downgrade(&self.local_llm_chat); + tokio::spawn(async move { + if let Some(ctrl) = weak_ctrl.upgrade() { + if let Err(err) = ctrl.create_chat(&chat_id).await { + error!("[Chat Plugin] failed to open chat: {:?}", err); + } + } + }); + } + } + + pub fn notify_close_chat(&self, chat_id: &str) { + if self.local_llm_setting.read().enabled { + trace!("[Chat Plugin] notify close chat: {}", chat_id); + let weak_ctrl = Arc::downgrade(&self.local_llm_chat); + let chat_id = chat_id.to_string(); + tokio::spawn(async move { + if let Some(ctrl) = weak_ctrl.upgrade() { + if let Err(err) = ctrl.close_chat(&chat_id).await { + error!("[Chat Plugin] failed to close chat: {:?}", err); + } + } + }); + } + } + + pub fn get_local_ai_setting(&self) -> LocalLLMSetting { + self.local_llm_setting.read().clone() + } + + pub fn update_local_ai_setting(&self, setting: LocalLLMSetting) -> FlowyResult<()> { + setting.validate()?; + + setup_local_chat(&setting, self.local_llm_chat.clone()); + *self.local_llm_setting.write() = setting; + Ok(()) + } + + fn get_message_content(&self, message_id: i64) -> FlowyResult { + let uid = self.user_service.user_id()?; + let conn = self.user_service.sqlite_connection(uid)?; + let content = select_single_message(conn, message_id)? + .map(|data| data.content) + .ok_or_else(|| { + FlowyError::record_not_found().with_context(format!("Message not found: {}", message_id)) + })?; + + Ok(content) + } +} + +#[async_trait] +impl ChatCloudService for ChatService { + fn create_chat( + &self, + uid: &i64, + workspace_id: &str, + chat_id: &str, + ) -> FutureResult<(), FlowyError> { + self.cloud_service.create_chat(uid, workspace_id, chat_id) + } + + fn save_question( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + message_type: ChatMessageType, + ) -> FutureResult { + self + .cloud_service + .save_question(workspace_id, chat_id, message, message_type) + } + + fn save_answer( + &self, + workspace_id: &str, + chat_id: &str, + message: &str, + question_id: i64, + ) -> FutureResult { + self + .cloud_service + .save_answer(workspace_id, chat_id, message, question_id) + } + + async fn ask_question( + &self, + workspace_id: &str, + chat_id: &str, + message_id: i64, + ) -> Result { + if self.local_llm_setting.read().enabled { + let content = self.get_message_content(message_id)?; + let stream = self + .local_llm_chat + .ask_question(chat_id, &content) + .await? + .map_err(FlowyError::from); + Ok(stream.boxed()) + } else { + self + .cloud_service + .ask_question(workspace_id, chat_id, message_id) + .await + } + } + + async fn generate_answer( + &self, + workspace_id: &str, + chat_id: &str, + question_message_id: i64, + ) -> Result { + if self.local_llm_setting.read().enabled { + let content = self.get_message_content(question_message_id)?; + let _answer = self + .local_llm_chat + .generate_answer(chat_id, &content) + .await?; + todo!() + } else { + self + .cloud_service + .generate_answer(workspace_id, chat_id, question_message_id) + .await + } + } + + fn get_chat_messages( + &self, + workspace_id: &str, + chat_id: &str, + offset: MessageCursor, + limit: u64, + ) -> FutureResult { + self + .cloud_service + .get_chat_messages(workspace_id, chat_id, offset, limit) + } + + fn get_related_message( + &self, + workspace_id: &str, + chat_id: &str, + message_id: i64, + ) -> FutureResult { + if self.local_llm_setting.read().enabled { + FutureResult::new(async move { + Ok(RepeatedRelatedQuestion { + message_id, + items: vec![], + }) + }) + } else { + self + .cloud_service + .get_related_message(workspace_id, chat_id, message_id) + } + } + + async fn stream_complete( + &self, + workspace_id: &str, + text: &str, + complete_type: CompletionType, + ) -> Result { + if self.local_llm_setting.read().enabled { + todo!() + } else { + self + .cloud_service + .stream_complete(workspace_id, text, complete_type) + .await + } + } +} + +fn setup_local_chat(local_llm_setting: &LocalLLMSetting, llm_chat_ctrl: Arc) { + if local_llm_setting.enabled { + if let Ok(config) = local_llm_setting.chat_config() { + tokio::spawn(async move { + trace!("[Chat Plugin] setup local chat: {:?}", config); + + if let Err(err) = llm_chat_ctrl.init_chat_plugin(config).await { + error!("[Chat Plugin] failed to setup plugin: {:?}", err); + } + }); + } + } else { + tokio::spawn(async move { + match llm_chat_ctrl.destroy_chat_plugin().await { + Ok(_) => info!("[Chat Plugin] destroy plugin successfully"), + Err(err) => error!("[Chat Plugin] failed to destroy plugin: {:?}", err), + } + }); + } +} diff --git a/frontend/rust-lib/flowy-chat/src/entities.rs b/frontend/rust-lib/flowy-chat/src/entities.rs index 12bf2c3753..bf7f9227ed 100644 --- a/frontend/rust-lib/flowy-chat/src/entities.rs +++ b/frontend/rust-lib/flowy-chat/src/entities.rs @@ -1,3 +1,4 @@ +use crate::local_ai::llm_chat::LocalLLMSetting; use flowy_chat_pub::cloud::{ ChatMessage, RelatedQuestion, RepeatedChatMessage, RepeatedRelatedQuestion, }; @@ -206,6 +207,38 @@ impl From for RepeatedRelatedQuestionPB { } } +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct LocalLLMSettingPB { + #[pb(index = 1)] + pub chat_bin_path: String, + + #[pb(index = 2)] + pub chat_model_path: String, + + #[pb(index = 3)] + pub enabled: bool, +} + +impl From for LocalLLMSettingPB { + fn from(value: LocalLLMSetting) -> Self { + LocalLLMSettingPB { + chat_bin_path: value.chat_bin_path, + chat_model_path: value.chat_model_path, + enabled: value.enabled, + } + } +} + +impl From for LocalLLMSetting { + fn from(value: LocalLLMSettingPB) -> Self { + LocalLLMSetting { + chat_bin_path: value.chat_bin_path, + chat_model_path: value.chat_model_path, + enabled: value.enabled, + } + } +} + #[derive(Default, ProtoBuf, Clone, Debug)] pub struct CompleteTextPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-chat/src/event_handler.rs b/frontend/rust-lib/flowy-chat/src/event_handler.rs index 93734aa7d0..924687ca5d 100644 --- a/frontend/rust-lib/flowy-chat/src/event_handler.rs +++ b/frontend/rust-lib/flowy-chat/src/event_handler.rs @@ -1,4 +1,5 @@ use flowy_chat_pub::cloud::ChatMessageType; + use std::sync::{Arc, Weak}; use validator::Validate; @@ -93,9 +94,15 @@ pub(crate) async fn get_answer_handler( ) -> DataResult { let chat_manager = upgrade_chat_manager(chat_manager)?; let data = data.into_inner(); - let message = chat_manager - .generate_answer(&data.chat_id, data.message_id) - .await?; + let (tx, rx) = tokio::sync::oneshot::channel(); + tokio::spawn(async move { + let message = chat_manager + .generate_answer(&data.chat_id, data.message_id) + .await?; + let _ = tx.send(message); + Ok::<_, FlowyError>(()) + }); + let message = rx.await?; data_result_ok(message) } @@ -113,6 +120,26 @@ pub(crate) async fn stop_stream_handler( } #[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn get_local_ai_setting_handler( + chat_manager: AFPluginState>, +) -> DataResult { + let chat_manager = upgrade_chat_manager(chat_manager)?; + let setting = chat_manager.get_local_ai_setting()?; + let pb = setting.into(); + data_result_ok(pb) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn update_local_ai_setting_handler( + data: AFPluginData, + chat_manager: AFPluginState>, +) -> Result<(), FlowyError> { + let data = data.into_inner(); + let chat_manager = upgrade_chat_manager(chat_manager)?; + chat_manager.update_local_ai_setting(data.into())?; + Ok(()) +} + pub(crate) async fn start_complete_text_handler( data: AFPluginData, tools: AFPluginState>, diff --git a/frontend/rust-lib/flowy-chat/src/event_map.rs b/frontend/rust-lib/flowy-chat/src/event_map.rs index 5b3fa74644..52aad53503 100644 --- a/frontend/rust-lib/flowy-chat/src/event_map.rs +++ b/frontend/rust-lib/flowy-chat/src/event_map.rs @@ -11,7 +11,7 @@ use crate::event_handler::*; pub fn init(chat_manager: Weak) -> AFPlugin { let user_service = Arc::downgrade(&chat_manager.upgrade().unwrap().user_service); - let cloud_service = Arc::downgrade(&chat_manager.upgrade().unwrap().cloud_service); + let cloud_service = Arc::downgrade(&chat_manager.upgrade().unwrap().chat_service); let ai_tools = Arc::new(AITools::new(cloud_service, user_service)); AFPlugin::new() .name("Flowy-Chat") @@ -23,6 +23,11 @@ pub fn init(chat_manager: Weak) -> AFPlugin { .event(ChatEvent::GetRelatedQuestion, get_related_question_handler) .event(ChatEvent::GetAnswerForQuestion, get_answer_handler) .event(ChatEvent::StopStream, stop_stream_handler) + .event(ChatEvent::GetLocalAISetting, get_local_ai_setting_handler) + .event( + ChatEvent::UpdateLocalAISetting, + update_local_ai_setting_handler, + ) .event(ChatEvent::CompleteText, start_complete_text_handler) .event(ChatEvent::StopCompleteText, stop_complete_text_handler) } @@ -49,9 +54,15 @@ pub enum ChatEvent { #[event(input = "ChatMessageIdPB", output = "ChatMessagePB")] GetAnswerForQuestion = 5, + #[event(input = "LocalLLMSettingPB")] + UpdateLocalAISetting = 6, + + #[event(output = "LocalLLMSettingPB")] + GetLocalAISetting = 7, + #[event(input = "CompleteTextPB", output = "CompleteTextTaskPB")] - CompleteText = 6, + CompleteText = 8, #[event(input = "CompleteTextTaskPB")] - StopCompleteText = 7, + StopCompleteText = 9, } diff --git a/frontend/rust-lib/flowy-chat/src/lib.rs b/frontend/rust-lib/flowy-chat/src/lib.rs index 12cd54845e..c0371ef053 100644 --- a/frontend/rust-lib/flowy-chat/src/lib.rs +++ b/frontend/rust-lib/flowy-chat/src/lib.rs @@ -3,7 +3,9 @@ pub mod event_map; mod chat; pub mod chat_manager; +mod chat_service_impl; pub mod entities; +pub mod local_ai; pub mod notification; mod persistence; mod protobuf; diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs b/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs new file mode 100644 index 0000000000..2e26e1b582 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs @@ -0,0 +1,128 @@ +use anyhow::anyhow; +use bytes::Bytes; +use flowy_error::FlowyError; +use flowy_sidecar::core::parser::{DefaultResponseParser, ResponseParser}; +use flowy_sidecar::core::plugin::Plugin; +use flowy_sidecar::error::{RemoteError, SidecarError}; +use serde_json::json; +use serde_json::Value as JsonValue; +use std::sync::Weak; +use tokio_stream::wrappers::ReceiverStream; +use tracing::instrument; + +pub struct ChatPluginOperation { + plugin: Weak, +} + +impl ChatPluginOperation { + pub fn new(plugin: Weak) -> Self { + ChatPluginOperation { plugin } + } + + fn get_plugin(&self) -> Result, SidecarError> { + self + .plugin + .upgrade() + .ok_or_else(|| SidecarError::Internal(anyhow!("Plugin is dropped"))) + } + + async fn send_request( + &self, + method: &str, + params: JsonValue, + ) -> Result { + let plugin = self.get_plugin()?; + let mut request = json!({ "method": method }); + request + .as_object_mut() + .unwrap() + .extend(params.as_object().unwrap().clone()); + plugin.async_request::("handle", &request).await + } + + pub async fn create_chat(&self, chat_id: &str) -> Result<(), SidecarError> { + self + .send_request::("create_chat", json!({ "chat_id": chat_id })) + .await + } + + pub async fn close_chat(&self, chat_id: &str) -> Result<(), SidecarError> { + self + .send_request::("close_chat", json!({ "chat_id": chat_id })) + .await + } + + pub async fn send_message(&self, chat_id: &str, message: &str) -> Result { + self + .send_request::( + "answer", + json!({ "chat_id": chat_id, "params": { "content": message } }), + ) + .await + } + + #[instrument(level = "debug", skip(self), err)] + pub async fn stream_message( + &self, + chat_id: &str, + message: &str, + ) -> Result>, FlowyError> { + let plugin = self + .get_plugin() + .map_err(|err| FlowyError::internal().with_context(err.to_string()))?; + let params = json!({ + "chat_id": chat_id, + "method": "stream_answer", + "params": { "content": message } + }); + plugin + .stream_request::("handle", ¶ms) + .map_err(|err| FlowyError::internal().with_context(err.to_string())) + } + + pub async fn get_related_questions(&self, chat_id: &str) -> Result, SidecarError> { + self + .send_request::( + "related_question", + json!({ "chat_id": chat_id }), + ) + .await + } +} + +pub struct ChatResponseParser; +impl ResponseParser for ChatResponseParser { + type ValueType = String; + + fn parse_json(json: JsonValue) -> Result { + json + .get("data") + .and_then(|data| data.as_str()) + .map(String::from) + .ok_or(RemoteError::ParseResponse(json)) + } +} + +pub struct ChatStreamResponseParser; +impl ResponseParser for ChatStreamResponseParser { + type ValueType = Bytes; + + fn parse_json(json: JsonValue) -> Result { + json + .as_str() + .map(|message| Bytes::from(message.to_string())) + .ok_or(RemoteError::ParseResponse(json)) + } +} + +pub struct ChatRelatedQuestionsResponseParser; +impl ResponseParser for ChatRelatedQuestionsResponseParser { + type ValueType = Vec; + + fn parse_json(json: JsonValue) -> Result { + json + .get("data") + .and_then(|data| data.as_array()).cloned() + .ok_or(RemoteError::ParseResponse(json)) + } +} diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs b/frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs new file mode 100644 index 0000000000..beb0bf75a9 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/local_ai/embedding_plugin.rs @@ -0,0 +1,50 @@ +use anyhow::anyhow; +use flowy_sidecar::core::parser::ResponseParser; +use flowy_sidecar::core::plugin::Plugin; +use flowy_sidecar::error::{RemoteError, SidecarError}; +use serde_json::json; +use serde_json::Value as JsonValue; +use std::sync::Weak; + +pub struct EmbeddingPluginOperation { + plugin: Weak, +} + +impl EmbeddingPluginOperation { + pub fn new(plugin: Weak) -> Self { + EmbeddingPluginOperation { plugin } + } + + pub async fn calculate_similarity( + &self, + message1: &str, + message2: &str, + ) -> Result { + let plugin = self + .plugin + .upgrade() + .ok_or(SidecarError::Internal(anyhow!("Plugin is dropped")))?; + let params = + json!({"method": "calculate_similarity", "params": {"src": message1, "dest": message2}}); + plugin + .async_request::("handle", ¶ms) + .await + } +} + +pub struct SimilarityResponseParser; +impl ResponseParser for SimilarityResponseParser { + type ValueType = f64; + + fn parse_json(json: JsonValue) -> Result { + if json.is_object() { + if let Some(data) = json.get("data") { + if let Some(score) = data.get("score").and_then(|v| v.as_f64()) { + return Ok(score); + } + } + } + + Err(RemoteError::ParseResponse(json)) + } +} diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/llm_chat.rs b/frontend/rust-lib/flowy-chat/src/local_ai/llm_chat.rs new file mode 100644 index 0000000000..ac59507ab7 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/local_ai/llm_chat.rs @@ -0,0 +1,315 @@ +use crate::local_ai::chat_plugin::ChatPluginOperation; +use bytes::Bytes; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_sidecar::core::plugin::{Plugin, PluginId, PluginInfo}; +use flowy_sidecar::error::SidecarError; +use flowy_sidecar::manager::SidecarManager; +use log::error; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use std::sync::{Arc, Weak}; +use std::time::Duration; +use tokio::sync::RwLock; +use tokio::time::timeout; +use tokio_stream::wrappers::ReceiverStream; +use tracing::{info, instrument, trace}; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct LocalLLMSetting { + pub chat_bin_path: String, + pub chat_model_path: String, + pub enabled: bool, +} + +impl LocalLLMSetting { + pub fn validate(&self) -> FlowyResult<()> { + ChatPluginConfig::new(&self.chat_bin_path, &self.chat_model_path)?; + Ok(()) + } + pub fn chat_config(&self) -> FlowyResult { + let config = ChatPluginConfig::new(&self.chat_bin_path, &self.chat_model_path)?; + Ok(config) + } +} + +pub struct LocalChatLLMChat { + sidecar_manager: Arc, + state: RwLock, + state_notify: tokio::sync::broadcast::Sender, + plugin_config: RwLock>, +} + +impl LocalChatLLMChat { + pub fn new(sidecar_manager: Arc) -> Self { + let (state_notify, _) = tokio::sync::broadcast::channel(10); + Self { + sidecar_manager, + state: RwLock::new(LLMState::Loading), + state_notify, + plugin_config: Default::default(), + } + } + + async fn update_state(&self, state: LLMState) { + *self.state.write().await = state.clone(); + let _ = self.state_notify.send(state); + } + + /// Waits for the plugin to be ready. + /// + /// The wait_plugin_ready method is an asynchronous function designed to ensure that the chat + /// plugin is in a ready state before allowing further operations. This is crucial for maintaining + /// the correct sequence of operations and preventing errors that could occur if operations are + /// attempted on an unready plugin. + /// + /// # Returns + /// + /// A `FlowyResult<()>` indicating success or failure. + async fn wait_plugin_ready(&self) -> FlowyResult<()> { + let is_loading = self.state.read().await.is_loading(); + if !is_loading { + return Ok(()); + } + info!("[Chat Plugin] wait for chat plugin to be ready"); + let mut rx = self.state_notify.subscribe(); + let timeout_duration = Duration::from_secs(30); + let result = timeout(timeout_duration, async { + while let Ok(state) = rx.recv().await { + if state.is_ready() { + break; + } + } + }) + .await; + + match result { + Ok(_) => { + trace!("[Chat Plugin] chat plugin is ready"); + Ok(()) + }, + Err(_) => Err( + FlowyError::local_ai().with_context("Timeout while waiting for chat plugin to be ready"), + ), + } + } + + /// Retrieves the chat plugin. + /// + /// # Returns + /// + /// A `FlowyResult>` containing a weak reference to the plugin. + async fn get_chat_plugin(&self) -> FlowyResult> { + let plugin_id = self.state.read().await.plugin_id()?; + let plugin = self.sidecar_manager.get_plugin(plugin_id).await?; + Ok(plugin) + } + + /// Creates a new chat session. + /// + /// # Arguments + /// + /// * `chat_id` - A string slice containing the unique identifier for the chat session. + /// + /// # Returns + /// + /// A `FlowyResult<()>` indicating success or failure. + pub async fn create_chat(&self, chat_id: &str) -> FlowyResult<()> { + trace!("[Chat Plugin] create chat: {}", chat_id); + self.wait_plugin_ready().await?; + + let plugin = self.get_chat_plugin().await?; + let operation = ChatPluginOperation::new(plugin); + operation.create_chat(chat_id).await?; + Ok(()) + } + + /// Closes an existing chat session. + /// + /// # Arguments + /// + /// * `chat_id` - A string slice containing the unique identifier for the chat session to close. + /// + /// # Returns + /// + /// A `FlowyResult<()>` indicating success or failure. + pub async fn close_chat(&self, chat_id: &str) -> FlowyResult<()> { + trace!("[Chat Plugin] close chat: {}", chat_id); + let plugin = self.get_chat_plugin().await?; + let operation = ChatPluginOperation::new(plugin); + operation.close_chat(chat_id).await?; + Ok(()) + } + + /// Asks a question and returns a stream of responses. + /// + /// # Arguments + /// + /// * `chat_id` - A string slice containing the unique identifier for the chat session. + /// * `message` - A string slice containing the question or message to send. + /// + /// # Returns + /// + /// A `FlowyResult>>` containing a stream of responses. + pub async fn ask_question( + &self, + chat_id: &str, + message: &str, + ) -> FlowyResult>> { + trace!("[Chat Plugin] ask question: {}", message); + self.wait_plugin_ready().await?; + let plugin = self.get_chat_plugin().await?; + let operation = ChatPluginOperation::new(plugin); + let stream = operation.stream_message(chat_id, message).await?; + Ok(stream) + } + + /// Generates a complete answer for a given message. + /// + /// # Arguments + /// + /// * `chat_id` - A string slice containing the unique identifier for the chat session. + /// * `message` - A string slice containing the message to generate an answer for. + /// + /// # Returns + /// + /// A `FlowyResult` containing the generated answer. + pub async fn generate_answer(&self, chat_id: &str, message: &str) -> FlowyResult { + let plugin = self.get_chat_plugin().await?; + let operation = ChatPluginOperation::new(plugin); + let answer = operation.send_message(chat_id, message).await?; + Ok(answer) + } + + #[instrument(skip_all, err)] + pub async fn destroy_chat_plugin(&self) -> FlowyResult<()> { + if let Ok(plugin_id) = self.state.read().await.plugin_id() { + if let Err(err) = self.sidecar_manager.remove_plugin(plugin_id).await { + error!("remove plugin failed: {:?}", err); + } + } + + self.update_state(LLMState::Uninitialized).await; + Ok(()) + } + + #[instrument(skip_all, err)] + pub async fn init_chat_plugin(&self, config: ChatPluginConfig) -> FlowyResult<()> { + if self.state.read().await.is_ready() { + if let Some(existing_config) = self.plugin_config.read().await.as_ref() { + if existing_config == &config { + trace!("[Chat Plugin] chat plugin already initialized with the same config"); + return Ok(()); + } else { + trace!( + "[Chat Plugin] existing config: {:?}, new config:{:?}", + existing_config, + config + ); + } + } + } + + // Initialize chat plugin if the config is different + // If the chat_bin_path is different, remove the old plugin + if let Err(err) = self.destroy_chat_plugin().await { + error!("[Chat Plugin] failed to destroy plugin: {:?}", err); + } + self.update_state(LLMState::Loading).await; + + // create new plugin + trace!("[Chat Plugin] create chat plugin: {:?}", config); + let plugin_info = PluginInfo { + name: "chat_plugin".to_string(), + exec_path: config.chat_bin_path.clone(), + }; + let plugin_id = self.sidecar_manager.create_plugin(plugin_info).await?; + + // init plugin + trace!("[Chat Plugin] init chat plugin model: {:?}", plugin_id); + let model_path = config.chat_model_path.clone(); + let plugin = self.sidecar_manager.init_plugin( + plugin_id, + serde_json::json!({ + "absolute_chat_model_path": model_path, + }), + )?; + + info!("[Chat Plugin] {} setup success", plugin); + self.plugin_config.write().await.replace(config); + self.update_state(LLMState::Ready { plugin_id }).await; + Ok(()) + } +} + +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct ChatPluginConfig { + chat_bin_path: PathBuf, + chat_model_path: PathBuf, +} + +impl ChatPluginConfig { + pub fn new(chat_bin: &str, chat_model_path: &str) -> FlowyResult { + let chat_bin_path = PathBuf::from(chat_bin); + if !chat_bin_path.exists() { + return Err(FlowyError::invalid_data().with_context(format!( + "Chat binary path does not exist: {:?}", + chat_bin_path + ))); + } + if !chat_bin_path.is_file() { + return Err(FlowyError::invalid_data().with_context(format!( + "Chat binary path is not a file: {:?}", + chat_bin_path + ))); + } + + // Check if local_model_dir exists and is a directory + let chat_model_path = PathBuf::from(&chat_model_path); + if !chat_model_path.exists() { + return Err( + FlowyError::invalid_data() + .with_context(format!("Local model does not exist: {:?}", chat_model_path)), + ); + } + if !chat_model_path.is_file() { + return Err( + FlowyError::invalid_data() + .with_context(format!("Local model is not a file: {:?}", chat_model_path)), + ); + } + + Ok(Self { + chat_bin_path, + chat_model_path, + }) + } +} + +#[derive(Debug, Clone)] +pub enum LLMState { + Uninitialized, + Loading, + Ready { plugin_id: PluginId }, +} + +impl LLMState { + fn plugin_id(&self) -> FlowyResult { + match self { + LLMState::Ready { plugin_id } => Ok(*plugin_id), + _ => Err(FlowyError::local_ai().with_context("chat plugin is not ready")), + } + } + + fn is_loading(&self) -> bool { + matches!(self, LLMState::Loading) + } + + #[allow(dead_code)] + fn is_uninitialized(&self) -> bool { + matches!(self, LLMState::Uninitialized) + } + + fn is_ready(&self) -> bool { + matches!(self, LLMState::Ready { .. }) + } +} diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/mod.rs b/frontend/rust-lib/flowy-chat/src/local_ai/mod.rs new file mode 100644 index 0000000000..f2f3ae9393 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/src/local_ai/mod.rs @@ -0,0 +1,4 @@ +pub mod chat_plugin; +pub mod llm_chat; + +pub mod embedding_plugin; diff --git a/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs b/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs index 6d9202def0..b7cb6579b7 100644 --- a/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs +++ b/frontend/rust-lib/flowy-chat/src/persistence/chat_message_sql.rs @@ -4,7 +4,8 @@ use flowy_sqlite::{ diesel, insert_into, query_dsl::*, schema::{chat_message_table, chat_message_table::dsl}, - DBConnection, ExpressionMethods, Identifiable, Insertable, QueryResult, Queryable, + DBConnection, ExpressionMethods, Identifiable, Insertable, OptionalExtension, QueryResult, + Queryable, }; #[derive(Queryable, Insertable, Identifiable)] @@ -69,3 +70,14 @@ pub fn select_chat_messages( let messages: Vec = query.load::(&mut *conn)?; Ok(messages) } + +pub fn select_single_message( + mut conn: DBConnection, + message_id_val: i64, +) -> QueryResult> { + let message = dsl::chat_message_table + .filter(chat_message_table::message_id.eq(message_id_val)) + .first::(&mut *conn) + .optional()?; + Ok(message) +} diff --git a/frontend/rust-lib/flowy-chat/src/persistence/chat_sql.rs b/frontend/rust-lib/flowy-chat/src/persistence/chat_sql.rs index 1fd0480c54..9971713afb 100644 --- a/frontend/rust-lib/flowy-chat/src/persistence/chat_sql.rs +++ b/frontend/rust-lib/flowy-chat/src/persistence/chat_sql.rs @@ -1,9 +1,10 @@ +use diesel::sqlite::SqliteConnection; use flowy_sqlite::upsert::excluded; use flowy_sqlite::{ diesel, query_dsl::*, schema::{chat_table, chat_table::dsl}, - DBConnection, ExpressionMethods, Identifiable, Insertable, QueryResult, Queryable, + AsChangeset, DBConnection, ExpressionMethods, Identifiable, Insertable, QueryResult, Queryable, }; #[derive(Clone, Default, Queryable, Insertable, Identifiable)] @@ -13,6 +14,22 @@ pub struct ChatTable { pub chat_id: String, pub created_at: i64, pub name: String, + pub local_model_path: String, + pub local_model_name: String, + pub local_enabled: bool, + pub sync_to_cloud: bool, +} + +#[derive(AsChangeset, Identifiable, Default, Debug)] +#[diesel(table_name = chat_table)] +#[diesel(primary_key(chat_id))] +pub struct ChatTableChangeset { + pub chat_id: String, + pub name: Option, + pub local_model_path: Option, + pub local_model_name: Option, + pub local_enabled: Option, + pub sync_to_cloud: Option, } pub fn insert_chat(mut conn: DBConnection, new_chat: &ChatTable) -> QueryResult { @@ -27,6 +44,16 @@ pub fn insert_chat(mut conn: DBConnection, new_chat: &ChatTable) -> QueryResult< .execute(&mut *conn) } +#[allow(dead_code)] +pub fn update_chat_local_model( + conn: &mut SqliteConnection, + changeset: ChatTableChangeset, +) -> QueryResult { + let filter = dsl::chat_table.filter(chat_table::chat_id.eq(changeset.chat_id.clone())); + let affected_row = diesel::update(filter).set(changeset).execute(conn)?; + Ok(affected_row) +} + #[allow(dead_code)] pub fn read_chat(mut conn: DBConnection, chat_id_val: &str) -> QueryResult { let row = dsl::chat_table diff --git a/frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs b/frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs new file mode 100644 index 0000000000..2730bf96d5 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/tests/chat_test/mod.rs @@ -0,0 +1,41 @@ +use crate::util::LocalAITest; +use tokio_stream::StreamExt; + +#[tokio::test] +async fn load_chat_model_test() { + if let Ok(test) = LocalAITest::new() { + let plugin_id = test.init_chat_plugin().await; + let chat_id = uuid::Uuid::new_v4().to_string(); + let resp = test + .send_chat_message(&chat_id, plugin_id, "hello world") + .await; + eprintln!("chat response: {:?}", resp); + + let embedding_plugin_id = test.init_embedding_plugin().await; + let score = test.calculate_similarity(embedding_plugin_id, &resp, "Hello! How can I help you today? Is there something specific you would like to know or discuss").await; + assert!(score > 0.8); + + // let questions = test.related_question(&chat_id, plugin_id).await; + // assert_eq!(questions.len(), 3); + // eprintln!("related questions: {:?}", questions); + } +} +#[tokio::test] +async fn stream_local_model_test() { + if let Ok(test) = LocalAITest::new() { + let plugin_id = test.init_chat_plugin().await; + let chat_id = uuid::Uuid::new_v4().to_string(); + + let mut resp = test + .stream_chat_message(&chat_id, plugin_id, "hello world") + .await; + let mut list = vec![]; + while let Some(s) = resp.next().await { + list.push(String::from_utf8(s.unwrap().to_vec()).unwrap()); + } + + let answer = list.join(""); + eprintln!("chat response: {:?}", answer); + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + } +} diff --git a/frontend/rust-lib/flowy-chat/tests/main.rs b/frontend/rust-lib/flowy-chat/tests/main.rs new file mode 100644 index 0000000000..8a6b230211 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/tests/main.rs @@ -0,0 +1,2 @@ +pub mod chat_test; +pub mod util; diff --git a/frontend/rust-lib/flowy-chat/tests/util.rs b/frontend/rust-lib/flowy-chat/tests/util.rs new file mode 100644 index 0000000000..5dbf37d8c8 --- /dev/null +++ b/frontend/rust-lib/flowy-chat/tests/util.rs @@ -0,0 +1,171 @@ +use anyhow::Result; +use bytes::Bytes; +use flowy_sidecar::manager::SidecarManager; +use serde_json::json; +use std::path::PathBuf; +use std::sync::Once; +use tokio_stream::wrappers::ReceiverStream; + +use flowy_chat::local_ai::chat_plugin::ChatPluginOperation; +use flowy_chat::local_ai::embedding_plugin::EmbeddingPluginOperation; +use flowy_sidecar::core::plugin::{PluginId, PluginInfo}; +use flowy_sidecar::error::SidecarError; +use tracing_subscriber::fmt::Subscriber; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::EnvFilter; + +pub struct LocalAITest { + config: LocalAIConfiguration, + manager: SidecarManager, +} + +impl LocalAITest { + pub fn new() -> Result { + let config = LocalAIConfiguration::new()?; + let manager = SidecarManager::new(); + + Ok(Self { config, manager }) + } + pub async fn init_chat_plugin(&self) -> PluginId { + let info = PluginInfo { + name: "chat".to_string(), + exec_path: self.config.chat_bin_path.clone(), + }; + let plugin_id = self.manager.create_plugin(info).await.unwrap(); + self + .manager + .init_plugin( + plugin_id, + json!({ + "absolute_chat_model_path":self.config.chat_model_absolute_path(), + }), + ) + .unwrap(); + + plugin_id + } + + pub async fn init_embedding_plugin(&self) -> PluginId { + let info = PluginInfo { + name: "embedding".to_string(), + exec_path: self.config.embedding_bin_path.clone(), + }; + let plugin_id = self.manager.create_plugin(info).await.unwrap(); + let embedding_model_path = self.config.embedding_model_absolute_path(); + self + .manager + .init_plugin( + plugin_id, + json!({ + "absolute_model_path":embedding_model_path, + }), + ) + .unwrap(); + plugin_id + } + + pub async fn send_chat_message( + &self, + chat_id: &str, + plugin_id: PluginId, + message: &str, + ) -> String { + let plugin = self.manager.get_plugin(plugin_id).await.unwrap(); + let operation = ChatPluginOperation::new(plugin); + + + operation.send_message(chat_id, message).await.unwrap() + } + + pub async fn stream_chat_message( + &self, + chat_id: &str, + plugin_id: PluginId, + message: &str, + ) -> ReceiverStream> { + let plugin = self.manager.get_plugin(plugin_id).await.unwrap(); + let operation = ChatPluginOperation::new(plugin); + operation.stream_message(chat_id, message).await.unwrap() + } + + pub async fn related_question( + &self, + chat_id: &str, + plugin_id: PluginId, + ) -> Vec { + let plugin = self.manager.get_plugin(plugin_id).await.unwrap(); + let operation = ChatPluginOperation::new(plugin); + + operation.get_related_questions(chat_id).await.unwrap() + } + + pub async fn calculate_similarity( + &self, + plugin_id: PluginId, + message1: &str, + message2: &str, + ) -> f64 { + let plugin = self.manager.get_plugin(plugin_id).await.unwrap(); + let operation = EmbeddingPluginOperation::new(plugin); + operation + .calculate_similarity(message1, message2) + .await + .unwrap() + } +} + +pub struct LocalAIConfiguration { + model_dir: String, + chat_bin_path: PathBuf, + chat_model_name: String, + embedding_bin_path: PathBuf, + embedding_model_name: String, +} + +impl LocalAIConfiguration { + pub fn new() -> Result { + dotenv::dotenv().ok(); + setup_log(); + + // load from .env + let model_dir = dotenv::var("LOCAL_AI_MODEL_DIR")?; + let chat_bin_path = PathBuf::from(dotenv::var("CHAT_BIN_PATH")?); + let chat_model_name = dotenv::var("LOCAL_AI_CHAT_MODEL_NAME")?; + + let embedding_bin_path = PathBuf::from(dotenv::var("EMBEDDING_BIN_PATH")?); + let embedding_model_name = dotenv::var("LOCAL_AI_EMBEDDING_MODEL_NAME")?; + + Ok(Self { + model_dir, + chat_bin_path, + chat_model_name, + embedding_bin_path, + embedding_model_name, + }) + } + + pub fn chat_model_absolute_path(&self) -> String { + format!("{}/{}", self.model_dir, self.chat_model_name) + } + + pub fn embedding_model_absolute_path(&self) -> String { + format!("{}/{}", self.model_dir, self.embedding_model_name) + } +} + +pub fn setup_log() { + static START: Once = Once::new(); + START.call_once(|| { + let level = "trace"; + let mut filters = vec![]; + filters.push(format!("flowy_sidecar={}", level)); + std::env::set_var("RUST_LOG", filters.join(",")); + + let subscriber = Subscriber::builder() + .with_env_filter(EnvFilter::from_default_env()) + .with_line_number(true) + .with_ansi(true) + .finish(); + subscriber.try_init().unwrap(); + }); +} diff --git a/frontend/rust-lib/flowy-config/src/event_handler.rs b/frontend/rust-lib/flowy-config/src/event_handler.rs index 46cd1262c3..3bd97f8cb5 100644 --- a/frontend/rust-lib/flowy-config/src/event_handler.rs +++ b/frontend/rust-lib/flowy-config/src/event_handler.rs @@ -1,13 +1,13 @@ use std::sync::Weak; use flowy_error::{FlowyError, FlowyResult}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult}; use crate::entities::{KeyPB, KeyValuePB}; pub(crate) async fn set_key_value_handler( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> FlowyResult<()> { let data = data.into_inner(); @@ -25,7 +25,7 @@ pub(crate) async fn set_key_value_handler( } pub(crate) async fn get_key_value_handler( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> DataResult { match store_preferences.upgrade() { @@ -42,7 +42,7 @@ pub(crate) async fn get_key_value_handler( } pub(crate) async fn remove_key_value_handler( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> FlowyResult<()> { match store_preferences.upgrade() { diff --git a/frontend/rust-lib/flowy-config/src/event_map.rs b/frontend/rust-lib/flowy-config/src/event_map.rs index 68c6ceb454..801dbdd75d 100644 --- a/frontend/rust-lib/flowy-config/src/event_map.rs +++ b/frontend/rust-lib/flowy-config/src/event_map.rs @@ -3,12 +3,12 @@ use std::sync::Weak; use strum_macros::Display; use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use lib_dispatch::prelude::AFPlugin; use crate::event_handler::*; -pub fn init(store_preferences: Weak) -> AFPlugin { +pub fn init(store_preferences: Weak) -> AFPlugin { AFPlugin::new() .name(env!("CARGO_PKG_NAME")) .state(store_preferences) diff --git a/frontend/rust-lib/flowy-core/src/config.rs b/frontend/rust-lib/flowy-core/src/config.rs index fd8fbe335f..c910064a0a 100644 --- a/frontend/rust-lib/flowy-core/src/config.rs +++ b/frontend/rust-lib/flowy-core/src/config.rs @@ -9,7 +9,7 @@ use flowy_server_pub::af_cloud_config::AFCloudConfiguration; use flowy_server_pub::supabase_config::SupabaseConfiguration; use flowy_user::services::entities::URL_SAFE_ENGINE; use lib_infra::file_util::copy_dir_recursive; -use lib_infra::util::Platform; +use lib_infra::util::OperatingSystem; use crate::integrate::log::create_log_filter; @@ -94,7 +94,7 @@ impl AppFlowyCoreConfig { }, Some(config) => make_user_data_folder(&custom_application_path, &config.base_url), }; - let log_filter = create_log_filter("info".to_owned(), vec![], Platform::from(&platform)); + let log_filter = create_log_filter("info".to_owned(), vec![], OperatingSystem::from(&platform)); AppFlowyCoreConfig { app_version, @@ -112,7 +112,7 @@ impl AppFlowyCoreConfig { self.log_filter = create_log_filter( level.to_owned(), with_crates, - Platform::from(&self.platform), + OperatingSystem::from(&self.platform), ); self } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs index e195be7a6f..32a31fb274 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs @@ -1,6 +1,7 @@ use flowy_chat::chat_manager::{ChatManager, ChatUserService}; use flowy_chat_pub::cloud::ChatCloudService; use flowy_error::FlowyError; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; use flowy_user::services::authenticate_user::AuthenticateUser; use std::sync::{Arc, Weak}; @@ -11,9 +12,14 @@ impl ChatDepsResolver { pub fn resolve( authenticate_user: Weak, cloud_service: Arc, + store_preferences: Arc, ) -> Arc { let user_service = ChatUserServiceImpl(authenticate_user); - Arc::new(ChatManager::new(cloud_service, user_service)) + Arc::new(ChatManager::new( + cloud_service, + user_service, + store_preferences, + )) } } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index 0550f18f9f..a195faf3b0 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -19,7 +19,7 @@ use flowy_folder::view_operation::{ use flowy_folder::ViewLayout; use flowy_folder_pub::folder_builder::NestedViewBuilder; use flowy_search::folder::indexer::FolderIndexManagerImpl; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user::services::authenticate_user::AuthenticateUser; use lib_dispatch::prelude::ToBytes; use lib_infra::future::FutureResult; @@ -38,7 +38,7 @@ impl FolderDepsResolver { collab_builder: Arc, server_provider: Arc, folder_indexer: Arc, - store_preferences: Arc, + store_preferences: Arc, operation_handlers: FolderOperationHandlers, ) -> Arc { let user: Arc = Arc::new(FolderUserImpl { diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs index 1d580e6cee..823ef63445 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs @@ -4,7 +4,7 @@ use flowy_database2::DatabaseManager; use flowy_error::FlowyResult; use flowy_folder::manager::FolderManager; use flowy_folder_pub::folder_builder::ParentChildViews; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user::services::authenticate_user::AuthenticateUser; use flowy_user::user_manager::UserManager; use flowy_user_pub::workspace_service::UserWorkspaceService; @@ -19,7 +19,7 @@ impl UserDepsResolver { authenticate_user: Arc, collab_builder: Arc, server_provider: Arc, - store_preference: Arc, + store_preference: Arc, database_manager: Arc, folder_manager: Arc, ) -> Arc { diff --git a/frontend/rust-lib/flowy-core/src/integrate/log.rs b/frontend/rust-lib/flowy-core/src/integrate/log.rs index 87f1634e91..f980827428 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/log.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/log.rs @@ -1,4 +1,4 @@ -use lib_infra::util::Platform; +use lib_infra::util::OperatingSystem; use lib_log::stream_log::StreamLogSender; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -8,7 +8,7 @@ use crate::AppFlowyCoreConfig; static INIT_LOG: AtomicBool = AtomicBool::new(false); pub(crate) fn init_log( config: &AppFlowyCoreConfig, - platform: &Platform, + platform: &OperatingSystem, stream_log_sender: Option>, ) { #[cfg(debug_assertions)] @@ -25,11 +25,15 @@ pub(crate) fn init_log( } } -pub fn create_log_filter(level: String, with_crates: Vec, platform: Platform) -> String { +pub fn create_log_filter( + level: String, + with_crates: Vec, + platform: OperatingSystem, +) -> String { let mut level = std::env::var("RUST_LOG").unwrap_or(level); #[cfg(debug_assertions)] - if matches!(platform, Platform::IOS) { + if matches!(platform, OperatingSystem::IOS) { level = "trace".to_string(); } @@ -53,7 +57,8 @@ pub fn create_log_filter(level: String, with_crates: Vec, platform: Plat filters.push(format!("lib_infra={}", level)); filters.push(format!("flowy_search={}", level)); filters.push(format!("flowy_chat={}", level)); - filters.push(format!("flowy_storage={}", level)); + filters.push(format!("flowy_chat={}", level)); + filters.push(format!("flowy_sidecar={}", level)); filters.push(format!("flowy_ai={}", level)); // Enable the frontend logs. DO NOT DISABLE. // These logs are essential for debugging and verifying frontend behavior. diff --git a/frontend/rust-lib/flowy-core/src/integrate/server.rs b/frontend/rust-lib/flowy-core/src/integrate/server.rs index 2959ae7f21..86b85f16af 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/server.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/server.rs @@ -14,7 +14,7 @@ use flowy_server::{AppFlowyEncryption, AppFlowyServer, EncryptionImpl}; use flowy_server_pub::af_cloud_config::AFCloudConfiguration; use flowy_server_pub::supabase_config::SupabaseConfiguration; use flowy_server_pub::AuthenticatorType; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::entities::*; use crate::AppFlowyCoreConfig; @@ -59,7 +59,7 @@ pub struct ServerProvider { providers: RwLock>>, pub(crate) encryption: RwLock>, #[allow(dead_code)] - pub(crate) store_preferences: Weak, + pub(crate) store_preferences: Weak, pub(crate) user_enable_sync: RwLock, /// The authenticator type of the user. @@ -72,7 +72,7 @@ impl ServerProvider { pub fn new( config: AppFlowyCoreConfig, server: Server, - store_preferences: Weak, + store_preferences: Weak, server_user: impl ServerUser + 'static, ) -> Self { let user = Arc::new(server_user); diff --git a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs index 71c5c0891d..b5decb151b 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs @@ -18,8 +18,7 @@ use collab_integrate::collab_builder::{ CollabCloudPluginProvider, CollabPluginProviderContext, CollabPluginProviderType, }; use flowy_chat_pub::cloud::{ - ChatCloudService, ChatMessage, ChatMessageStream, MessageCursor, RepeatedChatMessage, - StreamAnswer, StreamComplete, + ChatCloudService, ChatMessage, MessageCursor, RepeatedChatMessage, StreamAnswer, StreamComplete, }; use flowy_database_pub::cloud::{ CollabDocStateByOid, DatabaseCloudService, DatabaseSnapshot, SummaryRowContent, @@ -552,24 +551,7 @@ impl ChatCloudService for ServerProvider { }) } - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result { - let workspace_id = workspace_id.to_string(); - let chat_id = chat_id.to_string(); - let message = message.to_string(); - let server = self.get_server()?; - server - .chat_service() - .send_chat_message(&workspace_id, &chat_id, &message, message_type) - .await - } - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, @@ -584,7 +566,7 @@ impl ChatCloudService for ServerProvider { FutureResult::new(async move { server? .chat_service() - .send_question(&workspace_id, &chat_id, &message, message_type) + .save_question(&workspace_id, &chat_id, &message, message_type) .await }) } @@ -608,7 +590,7 @@ impl ChatCloudService for ServerProvider { }) } - async fn stream_answer( + async fn ask_question( &self, workspace_id: &str, chat_id: &str, @@ -619,7 +601,7 @@ impl ChatCloudService for ServerProvider { let server = self.get_server()?; server .chat_service() - .stream_answer(&workspace_id, &chat_id, message_id) + .ask_question(&workspace_id, &chat_id, message_id) .await } @@ -658,21 +640,17 @@ impl ChatCloudService for ServerProvider { }) } - fn generate_answer( + async fn generate_answer( &self, workspace_id: &str, chat_id: &str, question_message_id: i64, - ) -> FutureResult { - let workspace_id = workspace_id.to_string(); - let chat_id = chat_id.to_string(); + ) -> Result { let server = self.get_server(); - FutureResult::new(async move { - server? - .chat_service() - .generate_answer(&workspace_id, &chat_id, question_message_id) - .await - }) + server? + .chat_service() + .generate_answer(workspace_id, chat_id, question_message_id) + .await } async fn stream_complete( diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index 4cf5f42751..624f423493 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -16,7 +16,7 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_folder::manager::FolderManager; use flowy_server::af_cloud::define::ServerUser; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_storage::manager::StorageManager; use flowy_user::services::authenticate_user::AuthenticateUser; use flowy_user::services::entities::UserConfig; @@ -25,7 +25,7 @@ use flowy_user::user_manager::UserManager; use lib_dispatch::prelude::*; use lib_dispatch::runtime::AFPluginRuntime; use lib_infra::priority_task::{TaskDispatcher, TaskRunner}; -use lib_infra::util::Platform; +use lib_infra::util::OperatingSystem; use lib_log::stream_log::StreamLogSender; use module::make_plugins; @@ -57,7 +57,7 @@ pub struct AppFlowyCore { pub event_dispatcher: Arc, pub server_provider: Arc, pub task_dispatcher: Arc>, - pub store_preference: Arc, + pub store_preference: Arc, pub search_manager: Arc, pub chat_manager: Arc, pub storage_manager: Arc, @@ -69,7 +69,7 @@ impl AppFlowyCore { runtime: Arc, stream_log_sender: Option>, ) -> Self { - let platform = Platform::from(&config.platform); + let platform = OperatingSystem::from(&config.platform); #[allow(clippy::if_same_then_else)] if cfg!(debug_assertions) { @@ -102,7 +102,7 @@ impl AppFlowyCore { #[instrument(skip(config, runtime))] async fn init(config: AppFlowyCoreConfig, runtime: Arc) -> Self { // Init the key value database - let store_preference = Arc::new(StorePreferences::new(&config.storage_path).unwrap()); + let store_preference = Arc::new(KVStorePreferences::new(&config.storage_path).unwrap()); info!("🔥{:?}", &config); let task_scheduler = TaskDispatcher::new(Duration::from_secs(2)); @@ -175,8 +175,11 @@ impl AppFlowyCore { Arc::downgrade(&storage_manager.storage_service), ); - let chat_manager = - ChatDepsResolver::resolve(Arc::downgrade(&authenticate_user), server_provider.clone()); + let chat_manager = ChatDepsResolver::resolve( + Arc::downgrade(&authenticate_user), + server_provider.clone(), + store_preference.clone(), + ); let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Some(Arc::downgrade( &authenticate_user, diff --git a/frontend/rust-lib/flowy-error/Cargo.toml b/frontend/rust-lib/flowy-error/Cargo.toml index ae0d8bf9cd..1699dadb7d 100644 --- a/frontend/rust-lib/flowy-error/Cargo.toml +++ b/frontend/rust-lib/flowy-error/Cargo.toml @@ -33,7 +33,7 @@ collab-plugins = { workspace = true, optional = true } collab-folder = { workspace = true, optional = true } client-api = { workspace = true, optional = true } tantivy = { version = "0.21.1", optional = true } - +flowy-sidecar = { workspace = true, optional = true } [features] impl_from_dispatch_error = ["lib-dispatch"] @@ -49,6 +49,7 @@ impl_from_collab_folder = ["collab-folder"] impl_from_collab_database = ["collab-database"] impl_from_url = ["url"] impl_from_tantivy = ["tantivy"] +impl_from_sidecar = ["flowy-sidecar"] impl_from_sqlite = ["flowy-sqlite", "r2d2"] impl_from_appflowy_cloud = ["client-api"] diff --git a/frontend/rust-lib/flowy-error/src/code.rs b/frontend/rust-lib/flowy-error/src/code.rs index b013c1fbe5..b6b557b80c 100644 --- a/frontend/rust-lib/flowy-error/src/code.rs +++ b/frontend/rust-lib/flowy-error/src/code.rs @@ -280,6 +280,9 @@ pub enum ErrorCode { #[error("Workspace data not match")] WorkspaceDataNotMatch = 97, + + #[error("Local AI error")] + LocalAIError = 98, } impl ErrorCode { diff --git a/frontend/rust-lib/flowy-error/src/errors.rs b/frontend/rust-lib/flowy-error/src/errors.rs index a54ac046b6..2cd5ef7dd0 100644 --- a/frontend/rust-lib/flowy-error/src/errors.rs +++ b/frontend/rust-lib/flowy-error/src/errors.rs @@ -118,6 +118,7 @@ impl FlowyError { ErrorCode::FolderIndexManagerUnavailable ); static_flowy_error!(workspace_data_not_match, ErrorCode::WorkspaceDataNotMatch); + static_flowy_error!(local_ai, ErrorCode::LocalAIError); } impl std::convert::From for FlowyError { diff --git a/frontend/rust-lib/flowy-error/src/impl_from/mod.rs b/frontend/rust-lib/flowy-error/src/impl_from/mod.rs index b3d0351cd4..769aeacbb4 100644 --- a/frontend/rust-lib/flowy-error/src/impl_from/mod.rs +++ b/frontend/rust-lib/flowy-error/src/impl_from/mod.rs @@ -25,5 +25,7 @@ mod cloud; #[cfg(feature = "impl_from_url")] mod url; +#[cfg(feature = "impl_from_sidecar")] +mod sidecar; #[cfg(feature = "impl_from_tantivy")] mod tantivy; diff --git a/frontend/rust-lib/flowy-error/src/impl_from/sidecar.rs b/frontend/rust-lib/flowy-error/src/impl_from/sidecar.rs new file mode 100644 index 0000000000..719d5becbf --- /dev/null +++ b/frontend/rust-lib/flowy-error/src/impl_from/sidecar.rs @@ -0,0 +1,8 @@ +use crate::{ErrorCode, FlowyError}; +use flowy_sidecar::error::SidecarError; + +impl std::convert::From for FlowyError { + fn from(error: SidecarError) -> Self { + FlowyError::new(ErrorCode::LocalAIError, error) + } +} diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index e053caabb4..4b9520eda0 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -30,7 +30,7 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService}; use flowy_folder_pub::folder_builder::ParentChildViews; use flowy_search_pub::entities::FolderIndexManager; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use parking_lot::RwLock; use std::fmt::{Display, Formatter}; use std::ops::Deref; @@ -51,7 +51,7 @@ pub struct FolderManager { pub(crate) operation_handlers: FolderOperationHandlers, pub cloud_service: Arc, pub(crate) folder_indexer: Arc, - pub(crate) store_preferences: Arc, + pub(crate) store_preferences: Arc, } impl FolderManager { @@ -61,7 +61,7 @@ impl FolderManager { operation_handlers: FolderOperationHandlers, cloud_service: Arc, folder_indexer: Arc, - store_preferences: Arc, + store_preferences: Arc, ) -> FlowyResult { let mutex_folder = Arc::new(MutexFolder::default()); let manager = Self { diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs index 1fff915ad5..d07f53a4a8 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/chat.rs @@ -5,10 +5,10 @@ use client_api::entity::{ RepeatedChatMessage, }; use flowy_chat_pub::cloud::{ - ChatCloudService, ChatMessage, ChatMessageStream, ChatMessageType, StreamAnswer, StreamComplete, + ChatCloudService, ChatMessage, ChatMessageType, StreamAnswer, StreamComplete, }; use flowy_error::FlowyError; -use futures_util::StreamExt; +use futures_util::{StreamExt, TryStreamExt}; use lib_infra::async_trait::async_trait; use lib_infra::future::FutureResult; @@ -46,27 +46,7 @@ where }) } - async fn send_chat_message( - &self, - workspace_id: &str, - chat_id: &str, - message: &str, - message_type: ChatMessageType, - ) -> Result { - let try_get_client = self.inner.try_get_client(); - let params = CreateChatMessageParams { - content: message.to_string(), - message_type, - }; - let stream = try_get_client? - .create_chat_qa_message(workspace_id, chat_id, params) - .await - .map_err(FlowyError::from)?; - - Ok(stream.boxed()) - } - - fn send_question( + fn save_question( &self, workspace_id: &str, chat_id: &str, @@ -83,7 +63,7 @@ where FutureResult::new(async move { let message = try_get_client? - .create_question(&workspace_id, &chat_id, params) + .save_question(&workspace_id, &chat_id, params) .await .map_err(FlowyError::from)?; Ok(message) @@ -107,14 +87,14 @@ where FutureResult::new(async move { let message = try_get_client? - .create_answer(&workspace_id, &chat_id, params) + .save_answer(&workspace_id, &chat_id, params) .await .map_err(FlowyError::from)?; Ok(message) }) } - async fn stream_answer( + async fn ask_question( &self, workspace_id: &str, chat_id: &str, @@ -122,10 +102,25 @@ where ) -> Result { let try_get_client = self.inner.try_get_client(); let stream = try_get_client? - .stream_answer(workspace_id, chat_id, message_id) + .ask_question(workspace_id, chat_id, message_id) + .await + .map_err(FlowyError::from)? + .map_err(FlowyError::from); + Ok(stream.boxed()) + } + + async fn generate_answer( + &self, + workspace_id: &str, + chat_id: &str, + question_message_id: i64, + ) -> Result { + let try_get_client = self.inner.try_get_client(); + let resp = try_get_client? + .generate_answer(workspace_id, chat_id, question_message_id) .await .map_err(FlowyError::from)?; - Ok(stream.boxed()) + Ok(resp) } fn get_chat_messages( @@ -169,25 +164,6 @@ where }) } - fn generate_answer( - &self, - workspace_id: &str, - chat_id: &str, - question_message_id: i64, - ) -> FutureResult { - let workspace_id = workspace_id.to_string(); - let chat_id = chat_id.to_string(); - let try_get_client = self.inner.try_get_client(); - - FutureResult::new(async move { - let resp = try_get_client? - .get_answer(&workspace_id, &chat_id, question_message_id) - .await - .map_err(FlowyError::from)?; - Ok(resp) - }) - } - async fn stream_complete( &self, workspace_id: &str, diff --git a/frontend/rust-lib/flowy-server/src/default_impl.rs b/frontend/rust-lib/flowy-server/src/default_impl.rs index 8a015aeae7..d40100cc15 100644 --- a/frontend/rust-lib/flowy-server/src/default_impl.rs +++ b/frontend/rust-lib/flowy-server/src/default_impl.rs @@ -1,8 +1,6 @@ use client_api::entity::ai_dto::{CompletionType, RepeatedRelatedQuestion}; use client_api::entity::{ChatMessageType, MessageCursor, RepeatedChatMessage}; -use flowy_chat_pub::cloud::{ - ChatCloudService, ChatMessage, ChatMessageStream, StreamAnswer, StreamComplete, -}; +use flowy_chat_pub::cloud::{ChatCloudService, ChatMessage, StreamAnswer, StreamComplete}; use flowy_error::FlowyError; use lib_infra::async_trait::async_trait; use lib_infra::future::FutureResult; @@ -22,17 +20,7 @@ impl ChatCloudService for DefaultChatCloudServiceImpl { }) } - async fn send_chat_message( - &self, - _workspace_id: &str, - _chat_id: &str, - _message: &str, - _message_type: ChatMessageType, - ) -> Result { - Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) - } - - fn send_question( + fn save_question( &self, _workspace_id: &str, _chat_id: &str, @@ -56,7 +44,7 @@ impl ChatCloudService for DefaultChatCloudServiceImpl { }) } - async fn stream_answer( + async fn ask_question( &self, _workspace_id: &str, _chat_id: &str, @@ -88,15 +76,13 @@ impl ChatCloudService for DefaultChatCloudServiceImpl { }) } - fn generate_answer( + async fn generate_answer( &self, _workspace_id: &str, _chat_id: &str, _question_message_id: i64, - ) -> FutureResult { - FutureResult::new(async move { - Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) - }) + ) -> Result { + Err(FlowyError::not_support().with_context("Chat is not supported in local server.")) } async fn stream_complete( diff --git a/frontend/rust-lib/flowy-sidecar/Cargo.toml b/frontend/rust-lib/flowy-sidecar/Cargo.toml new file mode 100644 index 0000000000..0c7ad87141 --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "flowy-sidecar" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = { version = "1.0" } +serde = { version = "1.0", features = ["derive"] } +tokio = { version = "1.0", features = ["full"] } +once_cell = "1.19.0" +thiserror = "1.0" +serde_json = "1.0.117" +tracing.workspace = true +crossbeam-utils = "0.8.20" +log = "0.4.21" +parking_lot.workspace = true +tokio-stream = "0.1.15" +lib-infra.workspace = true + +[features] +verbose = [] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-sidecar/src/core/mod.rs b/frontend/rust-lib/flowy-sidecar/src/core/mod.rs new file mode 100644 index 0000000000..cc28539a86 --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/core/mod.rs @@ -0,0 +1,5 @@ +pub mod parser; +pub mod plugin; +pub mod rpc_loop; +mod rpc_object; +pub mod rpc_peer; diff --git a/frontend/rust-lib/flowy-sidecar/src/core/parser.rs b/frontend/rust-lib/flowy-sidecar/src/core/parser.rs new file mode 100644 index 0000000000..18c6d86fef --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/core/parser.rs @@ -0,0 +1,71 @@ +use crate::core::rpc_object::RpcObject; + +use crate::error::{ReadError, RemoteError}; +use serde_json::{json, Value as JsonValue}; +use std::io::BufRead; + +#[derive(Debug, Default)] +pub struct MessageReader(String); + +impl MessageReader { + /// Attempts to read the next line from the stream and parse it as + /// an RPC object. + /// + /// # Errors + /// + /// This function will return an error if there is an underlying + /// I/O error, if the stream is closed, or if the message is not + /// a valid JSON object. + pub fn next(&mut self, reader: &mut R) -> Result { + self.0.clear(); + let _ = reader.read_line(&mut self.0)?; + if self.0.is_empty() { + Err(ReadError::Disconnect) + } else { + self.parse(&self.0) + } + } + + /// Attempts to parse a &str as an RPC Object. + /// + /// This should not be called directly unless you are writing tests. + #[doc(hidden)] + pub fn parse(&self, s: &str) -> Result { + match serde_json::from_str::(s) { + Ok(val) => { + if !val.is_object() { + Err(ReadError::NotObject(s.to_string())) + } else { + Ok(val.into()) + } + }, + Err(_) => Ok(RpcObject(json!({"message": s.to_string()}))), + } + } +} + +pub type RequestId = u64; +#[derive(Debug, Clone)] +/// An RPC call, which may be either a notification or a request. +pub enum Call { + Message(JsonValue), + /// An id and an RPC Request + Request(RequestId, R), + /// A malformed request: the request contained an id, but could + /// not be parsed. The client will receive an error. + InvalidRequest(RequestId, RemoteError), +} + +pub trait ResponseParser { + type ValueType: Send + Sync + 'static; + fn parse_json(payload: JsonValue) -> Result; +} + +pub struct DefaultResponseParser; +impl ResponseParser for DefaultResponseParser { + type ValueType = (); + + fn parse_json(_payload: JsonValue) -> Result { + Ok(()) + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs b/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs new file mode 100644 index 0000000000..81e7a8139a --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/core/plugin.rs @@ -0,0 +1,205 @@ +use crate::error::SidecarError; +use crate::manager::WeakSidecarState; +use std::fmt::{Display, Formatter}; + +use crate::core::parser::ResponseParser; +use crate::core::rpc_loop::RpcLoop; +use crate::core::rpc_peer::{CloneableCallback, OneShotCallback}; +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value as JsonValue}; +use std::io::BufReader; +use std::path::PathBuf; +use std::process::{Child, Stdio}; +use std::sync::Arc; +use std::thread; +use std::time::Instant; +use tokio_stream::wrappers::ReceiverStream; + +use tracing::{error, info}; + +#[derive( + Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, +)] +pub struct PluginId(pub(crate) i64); + +impl From for PluginId { + fn from(id: i64) -> Self { + PluginId(id) + } +} + +/// The `Peer` trait defines the interface for the opposite side of the RPC channel, +/// designed to be used behind a pointer or as a trait object. +pub trait Peer: Send + Sync + 'static { + /// Clones the peer into a boxed trait object. + fn box_clone(&self) -> Arc; + + /// Sends an RPC notification to the peer with the specified method and parameters. + fn send_rpc_notification(&self, method: &str, params: &JsonValue); + + fn stream_rpc_request(&self, method: &str, params: &JsonValue, f: CloneableCallback); + + fn async_send_rpc_request(&self, method: &str, params: &JsonValue, f: Box); + /// Sends a synchronous RPC request to the peer and waits for the result. + /// Returns the result of the request or an error. + fn send_rpc_request(&self, method: &str, params: &JsonValue) -> Result; + + /// Checks if there is an incoming request pending, intended to reduce latency for bulk operations done in the background. + fn request_is_pending(&self) -> bool; + + /// Schedules a timer to execute the handler's `idle` function after the specified `Instant`. + /// Note: This is not a high-fidelity timer. Regular RPC messages will always take priority over idle tasks. + fn schedule_timer(&self, after: Instant, token: usize); +} + +/// The `Peer` trait object. +pub type RpcPeer = Arc; + +pub struct RpcCtx { + pub peer: RpcPeer, +} + +#[derive(Clone)] +pub struct Plugin { + peer: RpcPeer, + pub(crate) id: PluginId, + pub(crate) name: String, + #[allow(dead_code)] + pub(crate) process: Arc, +} + +impl Display for Plugin { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}, plugin id: {:?}, process id: {}", + self.name, + self.id, + self.process.id() + ) + } +} + +impl Plugin { + pub fn initialize(&self, value: JsonValue) -> Result<(), SidecarError> { + self.peer.send_rpc_request("initialize", &value)?; + Ok(()) + } + + pub fn request(&self, method: &str, params: &JsonValue) -> Result { + self.peer.send_rpc_request(method, params) + } + + pub async fn async_request( + &self, + method: &str, + params: &JsonValue, + ) -> Result { + let (tx, rx) = tokio::sync::oneshot::channel(); + self.peer.async_send_rpc_request( + method, + params, + Box::new(move |result| { + let _ = tx.send(result); + }), + ); + let value = rx.await.map_err(|err| { + SidecarError::Internal(anyhow!("error waiting for async response: {:?}", err)) + })??; + let value = P::parse_json(value)?; + Ok(value) + } + + pub fn stream_request( + &self, + method: &str, + params: &JsonValue, + ) -> Result>, SidecarError> { + let (tx, stream) = tokio::sync::mpsc::channel(100); + let stream = ReceiverStream::new(stream); + let callback = CloneableCallback::new(move |result| match result { + Ok(json) => { + let result = P::parse_json(json).map_err(SidecarError::from); + let _ = tx.blocking_send(result); + }, + Err(err) => { + let _ = tx.blocking_send(Err(err)); + }, + }); + self.peer.stream_rpc_request(method, params, callback); + Ok(stream) + } + + pub fn shutdown(&self) { + match self.peer.send_rpc_request("shutdown", &json!({})) { + Ok(_) => { + info!("shutting down plugin {}", self); + }, + Err(err) => { + error!("error sending shutdown to plugin {}: {:?}", self, err); + }, + } + } +} + +pub struct PluginInfo { + pub name: String, + pub exec_path: PathBuf, +} + +pub(crate) async fn start_plugin_process( + plugin_info: PluginInfo, + id: PluginId, + state: WeakSidecarState, +) -> Result<(), anyhow::Error> { + let (tx, rx) = tokio::sync::oneshot::channel(); + let spawn_result = thread::Builder::new() + .name(format!("<{}> core host thread", &plugin_info.name)) + .spawn(move || { + info!("Load {} plugin", &plugin_info.name); + let child = std::process::Command::new(&plugin_info.exec_path) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn(); + + match child { + Ok(mut child) => { + let child_stdin = child.stdin.take().unwrap(); + let child_stdout = child.stdout.take().unwrap(); + let mut looper = RpcLoop::new(child_stdin); + let peer: RpcPeer = Arc::new(looper.get_raw_peer()); + let name = plugin_info.name.clone(); + peer.send_rpc_notification("ping", &JsonValue::Array(Vec::new())); + + let plugin = Plugin { + peer, + process: Arc::new(child), + name, + id, + }; + + state.plugin_connect(Ok(plugin)); + let _ = tx.send(()); + let mut state = state; + let err = looper.mainloop( + &plugin_info.name, + || BufReader::new(child_stdout), + &mut state, + ); + state.plugin_exit(id, err); + }, + Err(err) => { + let _ = tx.send(()); + state.plugin_connect(Err(err)) + }, + } + }); + + if let Err(err) = spawn_result { + error!("[RPC] thread spawn failed for {:?}, {:?}", id, err); + return Err(err.into()); + } + rx.await?; + Ok(()) +} diff --git a/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs b/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs new file mode 100644 index 0000000000..e0a1f66402 --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/core/rpc_loop.rs @@ -0,0 +1,269 @@ +use crate::core::parser::{Call, MessageReader}; +use crate::core::plugin::RpcCtx; +use crate::core::rpc_object::RpcObject; +use crate::core::rpc_peer::{RawPeer, ResponsePayload, RpcState}; +use crate::error::{ReadError, RemoteError, SidecarError}; +use serde::de::DeserializeOwned; + +use std::io::{BufRead, Write}; +use std::sync::Arc; +use std::thread; +use std::time::Duration; +use tracing::{error, trace}; + +const MAX_IDLE_WAIT: Duration = Duration::from_millis(5); + +pub trait Handler { + type Request: DeserializeOwned; + fn handle_request( + &mut self, + ctx: &RpcCtx, + rpc: Self::Request, + ) -> Result; + #[allow(unused_variables)] + fn idle(&mut self, ctx: &RpcCtx, token: usize) {} +} + +/// A helper type which shuts down the runloop if a panic occurs while +/// handling an RPC. +struct PanicGuard<'a, W: Write + 'static>(&'a RawPeer); + +impl<'a, W: Write + 'static> Drop for PanicGuard<'a, W> { + /// Implements the cleanup behavior when the guard is dropped. + /// + /// This method is automatically called when the `PanicGuard` goes out of scope. + /// It checks if a panic is occurring and, if so, logs an error message and + /// disconnects the peer. + fn drop(&mut self) { + // - If no panic is occurring, this method does nothing. + // - If a panic is detected: + // 1. An error message is logged. + // 2. The `disconnect()` method is called on the peer. + if thread::panicking() { + error!("[RPC] panic guard hit, closing run loop"); + self.0.disconnect(); + } + } +} + +/// A structure holding the state of a main loop for handling RPC's. +pub struct RpcLoop { + reader: MessageReader, + peer: RawPeer, +} + +impl RpcLoop { + /// Creates a new `RpcLoop` with the given output stream (which is used for + /// sending requests and notifications, as well as responses). + pub fn new(writer: W) -> Self { + let rpc_peer = RawPeer(Arc::new(RpcState::new(writer))); + RpcLoop { + reader: MessageReader::default(), + peer: rpc_peer, + } + } + + /// Gets a reference to the peer. + pub fn get_raw_peer(&self) -> RawPeer { + self.peer.clone() + } + + /// Starts the event loop, reading lines from the reader until EOF or an error occurs. + /// + /// Returns `Ok()` if EOF is reached, otherwise returns the underlying `ReadError`. + /// + /// # Note: + /// The reader is provided via a closure to avoid needing `Send`. The main loop runs on a separate I/O thread that calls this closure at startup. + /// Calls to the handler occur on the caller's thread and maintain the order from the channel. Currently, there can only be one outstanding incoming request. + + /// Starts and manages the main event loop for processing RPC messages. + /// + /// This function is the core of the RPC system, handling incoming messages, + /// dispatching requests to the appropriate handler, and managing the overall + /// lifecycle of the RPC communication. + /// + /// # Arguments + /// + /// * `&mut self` - A mutable reference to the `RpcLoop` instance. + /// * `_plugin_name: &str` - The name of the plugin (currently unused in the function body). + /// * `buffer_read_fn: BufferReadFn` - A closure that returns a `BufRead` instance for reading input. + /// * `handler: &mut H` - A mutable reference to the handler implementing the `Handler` trait. + /// + /// # Type Parameters + /// + /// * `R: BufRead` - The type returned by `buffer_read_fn`, must implement `BufRead`. + /// * `BufferReadFn: Send + FnOnce() -> R` - The type of the closure that provides the input reader. + /// * `H: Handler` - The type of the handler, must implement the `Handler` trait. + /// + /// # Returns + /// + /// * `Result<(), ReadError>` - Returns `Ok(())` if the loop exits normally (EOF), + /// or an error if an unrecoverable error occurs. + /// + /// # Behavior + /// + /// 1. Creates a new `RpcCtx` with a clone of the `RawPeer`. + /// 2. Spawns a separate thread for reading input using `crossbeam_utils::thread::scope`. + /// 3. In the reading thread: + /// - Continuously reads and parses JSON messages from the input. + /// - Handles responses by calling `handle_response` on the peer. + /// - Puts other messages into the peer's queue using `put_rpc_object`. + /// 4. In the main thread: + /// - Retrieves messages using `next_read`. + /// - Processes requests by calling the handler's `handle_request` method. + /// - Sends responses back using the peer's `respond` method. + /// 5. Continues looping until an error occurs or the peer is disconnected. + pub fn mainloop( + &mut self, + _plugin_name: &str, + buffer_read_fn: BufferReadFn, + handler: &mut H, + ) -> Result<(), ReadError> + where + R: BufRead, + BufferReadFn: Send + FnOnce() -> R, + H: Handler, + { + // uses `crossbeam_utils::thread::scope` for thread management, + // which offers several advantages over `std::thread`: + // 1. Scoped Threads: Guarantees thread termination when the scope ends, + // preventing resource leaks. + // 2. Simplified Lifetime Management: Allows threads to borrow data from + // their parent stack frame, enabling more ergonomic code. + // 3. Improved Safety: Prevents threads from outliving the data they operate on, + // reducing risks of data races and use-after-free errors. + // 4. Efficiency: Potentially more efficient due to known thread lifetimes, + // leading to better resource management. + // 5. Error Propagation: Simplifies propagating errors from spawned threads + // back to the parent thread. + // 6. Consistency with Rust's Ownership Model: Aligns well with Rust's + // ownership and borrowing rules. + // 7. Automatic Thread Joining: No need for manual thread joining, reducing + // the risk of thread management errors. + let exit = crossbeam_utils::thread::scope(|scope| { + let peer = self.get_raw_peer(); + peer.reset_needs_exit(); + + let ctx = RpcCtx { + peer: Arc::new(peer.clone()), + }; + + // 1. Spawn a new thread for reading data from a stream. + // 2. Continuously read data from the stream. + // 3. Parse the data as JSON. + // 4. Handle the JSON data as either a response or another type of JSON object. + // 5. Manage errors and connection status. + scope.spawn(move |_| { + let mut stream = buffer_read_fn(); + loop { + if self.peer.needs_exit() { + trace!("read loop exit"); + break; + } + let json = match self.reader.next(&mut stream) { + Ok(json) => json, + Err(err) => { + if self.peer.0.is_blocking() { + self.peer.disconnect(); + } + self.peer.put_rpc_object(Err(err)); + break; + }, + }; + if json.is_response() { + let request_id = json.get_id().unwrap(); + match json.into_response() { + Ok(resp) => { + let resp = resp.map_err(SidecarError::from); + self.peer.handle_response(request_id, resp); + }, + Err(msg) => { + error!("[RPC] failed to parse response: {}", msg); + self + .peer + .handle_response(request_id, Err(SidecarError::InvalidResponse)); + }, + } + } else { + self.peer.put_rpc_object(Ok(json)); + } + } + }); + + // Main processing loop + loop { + // `PanicGuard` is a critical safety mechanism in the RPC system. It's designed to detect + // panics that occur during RPC request handling and ensure that the system shuts down + // gracefully, preventing resource leaks and maintaining system integrity. + // + let _guard = PanicGuard(&peer); + let read_result = next_read(&peer, &ctx); + let json = match read_result { + Ok(json) => json, + Err(err) => { + peer.disconnect(); + return err; + }, + }; + + match json.into_rpc::() { + Ok(Call::Request(id, cmd)) => { + // Handle request sent from the client. For example from python executable. + trace!("[RPC] received request: {}", id); + let result = handler.handle_request(&ctx, cmd); + peer.respond(result, id); + }, + Ok(Call::InvalidRequest(id, err)) => { + trace!("[RPC] received invalid request: {}", id); + peer.respond(Err(err), id) + }, + Err(err) => { + error!("[RPC] error parsing message: {:?}", err); + peer.disconnect(); + return ReadError::UnknownRequest(err); + }, + Ok(Call::Message(_msg)) => { + #[cfg(feature = "verbose")] + trace!("[RPC {}]: {}", _plugin_name, _msg); + }, + } + } + }) + .unwrap(); + + if exit.is_disconnect() { + Ok(()) + } else { + Err(exit) + } + } +} + +/// retrieves the next available read result from a peer, performing idle work if no result is +/// immediately available. +fn next_read(peer: &RawPeer, _ctx: &RpcCtx) -> Result +where + W: Write + Send, +{ + loop { + // Continuously checks if there is a result available from the peer using + if let Some(result) = peer.try_get_rx() { + return result; + } + + let time_to_next_timer = match peer.check_timers() { + Some(Ok(_token)) => continue, + Some(Err(duration)) => Some(duration), + None => None, + }; + + // Ensures the function does not block indefinitely by setting a maximum wait time + let idle_timeout = time_to_next_timer + .unwrap_or(MAX_IDLE_WAIT) + .min(MAX_IDLE_WAIT); + + if let Some(result) = peer.get_rx_timeout(idle_timeout) { + return result; + } + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs b/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs new file mode 100644 index 0000000000..7f4e46864c --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/core/rpc_object.rs @@ -0,0 +1,111 @@ +use crate::core::parser::{Call, RequestId}; +use crate::core::rpc_peer::{Response, ResponsePayload}; + +use serde::de::{DeserializeOwned, Error}; +use serde_json::Value; + +#[derive(Debug, Clone)] +pub struct RpcObject(pub Value); + +impl RpcObject { + /// Returns the 'id' of the underlying object, if present. + pub fn get_id(&self) -> Option { + self.0.get("id").and_then(Value::as_u64) + } + + /// Returns the 'method' field of the underlying object, if present. + pub fn get_method(&self) -> Option<&str> { + self.0.get("method").and_then(Value::as_str) + } + + /// Returns `true` if this object looks like an RPC response; + /// that is, if it has an 'id' field and does _not_ have a 'method' + /// field. + pub fn is_response(&self) -> bool { + self.0.get("id").is_some() && self.0.get("method").is_none() + } + + /// Converts a JSON-RPC response into a structured `Response` object. + /// + /// This function validates and parses a JSON-RPC response, ensuring it contains the necessary fields, + /// and then transforms it into a structured `Response` object. The response must contain either a + /// "result" or an "error" field, but not both. If the response contains a "result" field, it may also + /// include streaming data, indicated by a nested "stream" field. + /// + /// # Errors + /// + /// This function will return an error if: + /// - The "id" field is missing. + /// - The response contains both "result" and "error" fields, or neither. + /// - The "stream" field within the "result" is missing "type" or "data" fields. + /// - The "stream" type is invalid (i.e., not "streaming" or "end"). + /// + /// # Returns + /// + /// - `Ok(Ok(ResponsePayload::Json(result)))`: If the response contains a valid "result". + /// - `Ok(Ok(ResponsePayload::Streaming(data)))`: If the response contains streaming data of type "streaming". + /// - `Ok(Ok(ResponsePayload::StreamEnd(json!({}))))`: If the response contains streaming data of type "end". + /// - `Err(String)`: If any validation or parsing errors occur. + ///. + pub fn into_response(mut self) -> Result { + // Ensure 'id' field is present + self + .get_id() + .ok_or_else(|| "Response requires 'id' field.".to_string())?; + + // Ensure the response contains exactly one of 'result' or 'error' + let has_result = self.0.get("result").is_some(); + let has_error = self.0.get("error").is_some(); + if has_result == has_error { + return Err("RPC response must contain exactly one of 'error' or 'result' fields.".into()); + } + + // Handle the 'result' field if present + if let Some(mut result) = self.0.as_object_mut().and_then(|obj| obj.remove("result")) { + if let Some(mut stream) = result.as_object_mut().and_then(|obj| obj.remove("stream")) { + if let Some((has_more, data)) = stream.as_object_mut().and_then(|obj| { + let has_more = obj.remove("has_more")?.as_bool().unwrap_or(false); + let data = obj.remove("data")?; + Some((has_more, data)) + }) { + return match has_more { + true => Ok(Ok(ResponsePayload::Streaming(data))), + false => Ok(Ok(ResponsePayload::StreamEnd(data))), + }; + } else { + return Err("Stream response must contain 'type' and 'data' fields.".into()); + } + } + + Ok(Ok(ResponsePayload::Json(result))) + } else { + // Handle the 'error' field + let error = self.0.as_object_mut().unwrap().remove("error").unwrap(); + Err(format!("Error handling response: {:?}", error)) + } + } + + /// Converts the underlying `Value` into either an RPC notification or request. + pub fn into_rpc(self) -> Result, serde_json::Error> + where + R: DeserializeOwned, + { + let id = self.get_id(); + match id { + Some(id) => match serde_json::from_value::(self.0) { + Ok(resp) => Ok(Call::Request(id, resp)), + Err(err) => Ok(Call::InvalidRequest(id, err.into())), + }, + None => match self.0.get("message").and_then(|value| value.as_str()) { + None => Err(serde_json::Error::missing_field("message")), + Some(s) => Ok(Call::Message(s.to_string().into())), + }, + } + } +} + +impl From for RpcObject { + fn from(v: Value) -> RpcObject { + RpcObject(v) + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs b/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs new file mode 100644 index 0000000000..db53362615 --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/core/rpc_peer.rs @@ -0,0 +1,500 @@ +use crate::core::plugin::{Peer, PluginId}; +use crate::core::rpc_object::RpcObject; +use crate::error::{ReadError, RemoteError, SidecarError}; +use parking_lot::{Condvar, Mutex}; +use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer}; +use serde_json::{json, Value as JsonValue}; +use std::collections::{BTreeMap, BinaryHeap, VecDeque}; +use std::fmt::Display; +use std::io::Write; + +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::{mpsc, Arc}; +use std::time::{Duration, Instant}; +use std::{cmp, io}; +use tokio_stream::Stream; +use tracing::{error, trace, warn}; + +pub struct PluginCommand { + pub plugin_id: PluginId, + pub cmd: T, +} + +impl Serialize for PluginCommand { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut v = serde_json::to_value(&self.cmd).map_err(ser::Error::custom)?; + v["params"]["plugin_id"] = json!(self.plugin_id); + v.serialize(serializer) + } +} + +impl<'de, T: Deserialize<'de>> Deserialize<'de> for PluginCommand { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + struct PluginIdHelper { + plugin_id: PluginId, + } + let v = JsonValue::deserialize(deserializer)?; + let plugin_id = PluginIdHelper::deserialize(&v) + .map_err(de::Error::custom)? + .plugin_id; + let cmd = T::deserialize(v).map_err(de::Error::custom)?; + Ok(PluginCommand { plugin_id, cmd }) + } +} + +pub struct RpcState { + rx_queue: Mutex>>, + rx_cvar: Condvar, + writer: Mutex, + id: AtomicUsize, + pending: Mutex>, + timers: Mutex>, + needs_exit: AtomicBool, + is_blocking: AtomicBool, +} + +impl RpcState { + /// Creates a new `RawPeer` instance. + /// + /// # Arguments + /// + /// * `writer` - An object implementing the `Write` trait, used for sending messages. + /// + /// # Returns + /// + /// A new `RawPeer` instance wrapped in an `Arc`. + pub fn new(writer: W) -> Self { + RpcState { + rx_queue: Mutex::new(VecDeque::new()), + rx_cvar: Condvar::new(), + writer: Mutex::new(writer), + id: AtomicUsize::new(0), + pending: Mutex::new(BTreeMap::new()), + timers: Mutex::new(BinaryHeap::new()), + needs_exit: AtomicBool::new(false), + is_blocking: Default::default(), + } + } + + pub fn is_blocking(&self) -> bool { + self.is_blocking.load(Ordering::Acquire) + } +} + +pub struct RawPeer(pub(crate) Arc>); + +impl Peer for RawPeer { + fn box_clone(&self) -> Arc { + Arc::new((*self).clone()) + } + fn send_rpc_notification(&self, method: &str, params: &JsonValue) { + if let Err(e) = self.send(&json!({ + "method": method, + "params": params, + })) { + error!( + "send error on send_rpc_notification method {}: {}", + method, e + ); + } + } + + fn stream_rpc_request(&self, method: &str, params: &JsonValue, f: CloneableCallback) { + self.send_rpc(method, params, ResponseHandler::StreamCallback(Arc::new(f))); + } + + fn async_send_rpc_request(&self, method: &str, params: &JsonValue, f: Box) { + self.send_rpc(method, params, ResponseHandler::Callback(f)); + } + + fn send_rpc_request(&self, method: &str, params: &JsonValue) -> Result { + let (tx, rx) = mpsc::channel(); + self.0.is_blocking.store(true, Ordering::Release); + self.send_rpc(method, params, ResponseHandler::Chan(tx)); + rx.recv().unwrap_or(Err(SidecarError::PeerDisconnect)) + } + + fn request_is_pending(&self) -> bool { + let queue = self.0.rx_queue.lock(); + !queue.is_empty() + } + + fn schedule_timer(&self, after: Instant, token: usize) { + self.0.timers.lock().push(Timer { + fire_after: after, + token, + }); + } +} + +impl RawPeer { + /// Sends a JSON value to the peer. + /// + /// # Arguments + /// + /// * `json` - A reference to a `JsonValue` to be sent. + /// + /// # Returns + /// + /// A `Result` indicating success or an `io::Error` if the write operation fails. + /// + /// # Notes + /// + /// This function serializes the JSON value, appends a newline, and writes it to the underlying writer. + fn send(&self, json: &JsonValue) -> Result<(), io::Error> { + let mut s = serde_json::to_string(json).unwrap(); + s.push('\n'); + self.0.writer.lock().write_all(s.as_bytes()) + } + + /// Sends a response to a previous RPC request. + /// + /// # Arguments + /// + /// * `result` - The `Response` to be sent. + /// * `id` - The ID of the request being responded to. + /// + /// # Notes + /// + /// This function constructs a JSON response and sends it using the `send` method. + /// It handles both successful results and errors. + pub(crate) fn respond(&self, result: Response, id: u64) { + let mut response = json!({ "id": id }); + match result { + Ok(result) => match result { + ResponsePayload::Json(value) => response["result"] = value, + ResponsePayload::Streaming(_) | ResponsePayload::StreamEnd(_) => { + error!("stream response not supported") + }, + }, + Err(error) => response["error"] = json!(error), + }; + if let Err(e) = self.send(&response) { + error!("[RPC] error {} sending response to RPC {:?}", e, id); + } + } + + /// Sends an RPC request. + /// + /// # Arguments + /// + /// * `method` - The name of the RPC method to be called. + /// * `params` - The parameters for the RPC call. + /// * `response_handler` - A `ResponseHandler` to handle the response. + /// + /// # Notes + /// + /// This function generates a unique ID for the request, stores the response handler, + /// and sends the RPC request. If sending fails, it immediately invokes the response handler with an error. + fn send_rpc(&self, method: &str, params: &JsonValue, response_handler: ResponseHandler) { + trace!("[RPC] call method: {} params: {:?}", method, params); + let id = self.0.id.fetch_add(1, Ordering::Relaxed); + { + let mut pending = self.0.pending.lock(); + pending.insert(id, response_handler); + } + + // Call the ResponseHandler if the send fails. Otherwise, the response will be + // called in handle_response. + if let Err(e) = self.send(&json!({ + "id": id, + "method": method, + "params": params, + })) { + let mut pending = self.0.pending.lock(); + if let Some(rh) = pending.remove(&id) { + rh.invoke(Err(SidecarError::Io(e))); + } + } + } + + /// Processes an incoming response to an RPC request. + /// + /// This function is responsible for handling responses received from the peer, matching them + /// to their corresponding requests, and invoking the appropriate callbacks. It supports both + /// one-time responses and streaming responses. + /// + /// # Arguments + /// + /// * `&self` - A reference to the `RawPeer` instance. + /// * `request_id: u64` - The unique identifier of the request to which this is a response. + /// * `resp: Result` - The response payload or an error. + /// + /// # Behavior + /// + /// 1. Retrieves and removes the response handler for the given `request_id` from the pending requests. + /// 2. Determines if the response is part of a stream. + /// 3. For streaming responses: + /// - If it's not the end of the stream, re-inserts the stream callback for future messages. + /// - If it's the end of the stream, logs this information. + /// 4. Converts the response payload to JSON. + /// 5. Invokes the response handler with the JSON data or error. + /// + /// # Concurrency + /// + /// This function uses mutex locks to ensure thread-safe access to shared data structures. + /// It's designed to be called from multiple threads safely. + /// + /// # Error Handling + /// + /// - If no handler is found for the `request_id`, an error is logged. + /// - If a non-stream response payload is `None`, a warning is logged. + /// - Errors in the response are propagated to the response handler. + pub(crate) fn handle_response( + &self, + request_id: u64, + resp: Result, + ) { + let request_id = request_id as usize; + let handler = { + let mut pending = self.0.pending.lock(); + pending.remove(&request_id) + }; + let is_stream = resp.as_ref().map(|resp| resp.is_stream()).unwrap_or(false); + match handler { + Some(response_handler) => { + if is_stream { + let is_stream_end = resp + .as_ref() + .map(|resp| resp.is_stream_end()) + .unwrap_or(false); + if !is_stream_end { + // when steam is not end, we need to put the stream callback back to pending in order to + // receive the next stream message. + if let Some(callback) = response_handler.get_stream_callback() { + let mut pending = self.0.pending.lock(); + pending.insert(request_id, ResponseHandler::StreamCallback(callback)); + } + } else { + trace!("[RPC] {} stream end", request_id); + } + } + let json = resp.map(|resp| resp.into_json()); + match json { + Ok(Some(json)) => { + response_handler.invoke(Ok(json)); + }, + Ok(None) => { + if !is_stream { + warn!("[RPC] only stream response can be None"); + } + }, + Err(err) => { + response_handler.invoke(Err(err)); + }, + } + }, + None => error!("[RPC] id {}'s handle not found", request_id), + } + } + + /// Get a message from the receive queue if available. + pub(crate) fn try_get_rx(&self) -> Option> { + let mut queue = self.0.rx_queue.lock(); + queue.pop_front() + } + + /// Get a message from the receive queue, waiting for at most `Duration` + /// and returning `None` if no message is available. + pub(crate) fn get_rx_timeout(&self, dur: Duration) -> Option> { + let mut queue = self.0.rx_queue.lock(); + let result = self.0.rx_cvar.wait_for(&mut queue, dur); + if result.timed_out() { + return None; + } + queue.pop_front() + } + + /// Adds a message to the receive queue. The message should only + /// be `None` if the read thread is exiting. + pub(crate) fn put_rpc_object(&self, json: Result) { + let mut queue = self.0.rx_queue.lock(); + queue.push_back(json); + self.0.rx_cvar.notify_one(); + } + + /// Checks the status of the most imminent timer. + /// + /// # Returns + /// + /// - `Some(Ok(usize))`: If the most imminent timer has expired, returns its token. + /// - `Some(Err(Duration))`: If the most imminent timer has not yet expired, returns the time until it expires. + /// - `None`: If no timers are registered. + pub(crate) fn check_timers(&self) -> Option> { + let mut timers = self.0.timers.lock(); + match timers.peek() { + None => return None, + Some(t) => { + let now = Instant::now(); + if t.fire_after > now { + return Some(Err(t.fire_after - now)); + } + }, + } + Some(Ok(timers.pop().unwrap().token)) + } + + /// send disconnect error to pending requests. + pub(crate) fn disconnect(&self) { + trace!("[RPC] disconnecting peer"); + let mut pending = self.0.pending.lock(); + let ids = pending.keys().cloned().collect::>(); + for id in &ids { + let callback = pending.remove(id).unwrap(); + callback.invoke(Err(SidecarError::PeerDisconnect)); + } + self.0.needs_exit.store(true, Ordering::Relaxed); + } + + /// Checks if the RPC system needs to exit. + pub(crate) fn needs_exit(&self) -> bool { + self.0.needs_exit.load(Ordering::Relaxed) + } + + pub(crate) fn reset_needs_exit(&self) { + self.0.needs_exit.store(false, Ordering::SeqCst); + } +} + +impl Clone for RawPeer { + fn clone(&self) -> Self { + RawPeer(self.0.clone()) + } +} + +#[derive(Clone, Debug)] +pub enum ResponsePayload { + Json(JsonValue), + Streaming(JsonValue), + StreamEnd(JsonValue), +} + +impl ResponsePayload { + pub fn empty_json() -> Self { + ResponsePayload::Json(json!({})) + } + + pub fn is_stream(&self) -> bool { + matches!( + self, + ResponsePayload::Streaming(_) | ResponsePayload::StreamEnd(_) + ) + } + + pub fn is_stream_end(&self) -> bool { + matches!(self, ResponsePayload::StreamEnd(_)) + } + + pub fn into_json(self) -> Option { + match self { + ResponsePayload::Json(v) => Some(v), + ResponsePayload::Streaming(v) => Some(v), + ResponsePayload::StreamEnd(_) => None, + } + } +} + +impl Display for ResponsePayload { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ResponsePayload::Json(v) => write!(f, "{}", v), + ResponsePayload::Streaming(_) => write!(f, "stream start"), + ResponsePayload::StreamEnd(_) => write!(f, "stream end"), + } + } +} + +pub type Response = Result; + +pub trait ResponseStream: Stream> + Unpin + Send {} + +impl ResponseStream for T where T: Stream> + Unpin + Send {} + +enum ResponseHandler { + Chan(mpsc::Sender>), + Callback(Box), + StreamCallback(Arc), +} + +impl ResponseHandler { + pub fn get_stream_callback(&self) -> Option> { + match self { + ResponseHandler::StreamCallback(cb) => Some(cb.clone()), + _ => None, + } + } +} + +pub trait OneShotCallback: Send { + fn call(self: Box, result: Result); +} + +impl)> OneShotCallback for F { + fn call(self: Box, result: Result) { + (self)(result) + } +} + +pub trait Callback: Send + Sync { + fn call(&self, result: Result); +} + +impl)> Callback for F { + fn call(&self, result: Result) { + (*self)(result) + } +} + +#[derive(Clone)] +pub struct CloneableCallback { + callback: Arc, +} +impl CloneableCallback { + pub fn new(callback: C) -> Self { + CloneableCallback { + callback: Arc::new(callback), + } + } + + pub fn call(&self, result: Result) { + self.callback.call(result) + } +} + +impl ResponseHandler { + fn invoke(self, result: Result) { + match self { + ResponseHandler::Chan(tx) => { + let _ = tx.send(result); + }, + ResponseHandler::StreamCallback(cb) => { + cb.call(result); + }, + ResponseHandler::Callback(f) => f.call(result), + } + } +} +#[derive(Debug, PartialEq, Eq)] +struct Timer { + fire_after: Instant, + token: usize, +} + +impl Ord for Timer { + fn cmp(&self, other: &Timer) -> cmp::Ordering { + other.fire_after.cmp(&self.fire_after) + } +} + +impl PartialOrd for Timer { + fn partial_cmp(&self, other: &Timer) -> Option { + Some(self.cmp(other)) + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/error.rs b/frontend/rust-lib/flowy-sidecar/src/error.rs new file mode 100644 index 0000000000..fb7f7b6a52 --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/error.rs @@ -0,0 +1,174 @@ +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde_json::{json, Value as JsonValue}; +use std::{fmt, io}; + +/// The error type of `tauri-utils`. +#[derive(Debug, thiserror::Error)] +pub enum SidecarError { + /// An IO error occurred on the underlying communication channel. + #[error(transparent)] + Io(#[from] io::Error), + /// The peer returned an error. + #[error("Remote error: {0}")] + RemoteError(RemoteError), + /// The peer closed the connection. + #[error("Peer closed the connection.")] + PeerDisconnect, + /// The peer sent a response containing the id, but was malformed. + #[error("Invalid response.")] + InvalidResponse, + + #[error(transparent)] + Internal(#[from] anyhow::Error), +} + +#[derive(Debug)] +pub enum ReadError { + /// An error occurred in the underlying stream + Io(io::Error), + /// The message was not valid JSON. + Json(serde_json::Error), + /// The message was not a JSON object. + NotObject(String), + /// The the method and params were not recognized by the handler. + UnknownRequest(serde_json::Error), + /// The peer closed the connection. + Disconnect, +} + +#[derive(Debug, Clone, thiserror::Error)] +pub enum RemoteError { + /// The JSON was valid, but was not a correctly formed request. + /// + /// This Error is used internally, and should not be returned by + /// clients. + #[error("Invalid request: {0:?}")] + InvalidRequest(Option), + + #[error("Invalid response: {0}")] + InvalidResponse(JsonValue), + + #[error("Parse response: {0}")] + ParseResponse(JsonValue), + /// A custom error, defined by the client. + #[error("Custom error: {message}")] + Custom { + code: i64, + message: String, + data: Option, + }, + /// An error that cannot be represented by an error object. + /// + /// This error is intended to accommodate clients that return arbitrary + /// error values. It should not be used for new errors. + #[error("Unknown error: {0}")] + Unknown(JsonValue), +} + +impl ReadError { + /// Returns `true` iff this is the `ReadError::Disconnect` variant. + pub fn is_disconnect(&self) -> bool { + matches!(*self, ReadError::Disconnect) + } +} + +impl fmt::Display for ReadError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ReadError::Io(ref err) => write!(f, "I/O Error: {:?}", err), + ReadError::Json(ref err) => write!(f, "JSON Error: {:?}", err), + ReadError::NotObject(s) => write!(f, "Expected JSON object, found: {}", s), + ReadError::UnknownRequest(ref err) => write!(f, "Unknown request: {:?}", err), + ReadError::Disconnect => write!(f, "Peer closed the connection."), + } + } +} + +impl From for ReadError { + fn from(err: serde_json::Error) -> ReadError { + ReadError::Json(err) + } +} + +impl From for ReadError { + fn from(err: io::Error) -> ReadError { + ReadError::Io(err) + } +} + +impl From for RemoteError { + fn from(err: serde_json::Error) -> RemoteError { + RemoteError::InvalidRequest(Some(json!(err.to_string()))) + } +} + +impl From for SidecarError { + fn from(err: RemoteError) -> SidecarError { + SidecarError::RemoteError(err) + } +} + +#[derive(Deserialize, Serialize)] +struct ErrorHelper { + code: i64, + message: String, + #[serde(skip_serializing_if = "Option::is_none")] + data: Option, +} + +impl<'de> Deserialize<'de> for RemoteError { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let v = JsonValue::deserialize(deserializer)?; + let resp = match ErrorHelper::deserialize(&v) { + Ok(resp) => resp, + Err(_) => return Ok(RemoteError::Unknown(v)), + }; + + Ok(match resp.code { + -32600 => RemoteError::InvalidRequest(resp.data), + _ => RemoteError::Custom { + code: resp.code, + message: resp.message, + data: resp.data, + }, + }) + } +} + +impl Serialize for RemoteError { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let (code, message, data) = match self { + RemoteError::InvalidRequest(ref d) => (-32600, "Invalid request".to_string(), d.clone()), + RemoteError::Custom { + code, + ref message, + ref data, + } => (*code, message.clone(), data.clone()), + RemoteError::Unknown(_) => { + panic!("The 'Unknown' error variant is not intended for client use.") + }, + RemoteError::InvalidResponse(resp) => ( + -1, + "Invalid response".to_string(), + Some(json!(resp.to_string())), + ), + RemoteError::ParseResponse(resp) => ( + -1, + "Invalid response".to_string(), + Some(json!(resp.to_string())), + ), + }; + let err = ErrorHelper { + code, + message, + data, + }; + err.serialize(serializer) + } +} diff --git a/frontend/rust-lib/flowy-sidecar/src/lib.rs b/frontend/rust-lib/flowy-sidecar/src/lib.rs new file mode 100644 index 0000000000..3eabd6918a --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/lib.rs @@ -0,0 +1,3 @@ +pub mod core; +pub mod error; +pub mod manager; diff --git a/frontend/rust-lib/flowy-sidecar/src/manager.rs b/frontend/rust-lib/flowy-sidecar/src/manager.rs new file mode 100644 index 0000000000..1c90982a42 --- /dev/null +++ b/frontend/rust-lib/flowy-sidecar/src/manager.rs @@ -0,0 +1,201 @@ +use crate::core::parser::ResponseParser; +use crate::core::plugin::{start_plugin_process, Plugin, PluginId, PluginInfo, RpcCtx}; +use crate::core::rpc_loop::Handler; +use crate::core::rpc_peer::{PluginCommand, ResponsePayload}; +use crate::error::{ReadError, RemoteError, SidecarError}; +use anyhow::anyhow; +use lib_infra::util::{get_operating_system, OperatingSystem}; +use parking_lot::Mutex; +use serde_json::Value; +use std::io; + +use std::sync::atomic::{AtomicI64, Ordering}; +use std::sync::{Arc, Weak}; +use tracing::{error, info, instrument, trace, warn}; + +pub struct SidecarManager { + state: Arc>, + plugin_id_counter: Arc, + operating_system: OperatingSystem, +} + +impl Default for SidecarManager { + fn default() -> Self { + Self::new() + } +} + +impl SidecarManager { + pub fn new() -> Self { + SidecarManager { + state: Arc::new(Mutex::new(SidecarState { + plugins: Vec::new(), + })), + plugin_id_counter: Arc::new(Default::default()), + operating_system: get_operating_system(), + } + } + + pub async fn create_plugin(&self, plugin_info: PluginInfo) -> Result { + if self.operating_system.is_not_desktop() { + return Err(SidecarError::Internal(anyhow!( + "plugin not supported on this platform" + ))); + } + let plugin_id = PluginId::from(self.plugin_id_counter.fetch_add(1, Ordering::SeqCst)); + let weak_state = WeakSidecarState(Arc::downgrade(&self.state)); + start_plugin_process(plugin_info, plugin_id, weak_state).await?; + Ok(plugin_id) + } + + pub async fn get_plugin(&self, plugin_id: PluginId) -> Result, SidecarError> { + let state = self.state.lock(); + let plugin = state + .plugins + .iter() + .find(|p| p.id == plugin_id) + .ok_or(anyhow!("plugin not found"))?; + Ok(Arc::downgrade(plugin)) + } + + #[instrument(skip(self), err)] + pub async fn remove_plugin(&self, id: PluginId) -> Result<(), SidecarError> { + if self.operating_system.is_not_desktop() { + return Err(SidecarError::Internal(anyhow!( + "plugin not supported on this platform" + ))); + } + + info!("[RPC] removing plugin {:?}", id); + self.state.lock().plugin_disconnect(id, Ok(())); + Ok(()) + } + + pub fn init_plugin(&self, id: PluginId, init_params: Value) -> Result, SidecarError> { + if self.operating_system.is_not_desktop() { + return Err(SidecarError::Internal(anyhow!( + "plugin not supported on this platform" + ))); + } + + let state = self.state.lock(); + let plugin = state + .plugins + .iter() + .find(|p| p.id == id) + .ok_or(anyhow!("plugin not found"))?; + plugin.initialize(init_params)?; + + Ok(plugin.clone()) + } + + pub fn send_request( + &self, + id: PluginId, + method: &str, + request: Value, + ) -> Result { + let state = self.state.lock(); + let plugin = state + .plugins + .iter() + .find(|p| p.id == id) + .ok_or(anyhow!("plugin not found"))?; + let resp = plugin.request(method, &request)?; + let value = P::parse_json(resp)?; + Ok(value) + } + + pub async fn async_send_request( + &self, + id: PluginId, + method: &str, + request: Value, + ) -> Result { + let plugin = self + .state + .lock() + .plugins + .iter() + .find(|p| p.id == id) + .ok_or(anyhow!("plugin not found")) + .cloned()?; + let value = plugin.async_request::

(method, &request).await?; + Ok(value) + } +} + +pub struct SidecarState { + plugins: Vec>, +} + +impl SidecarState { + pub fn plugin_connect(&mut self, plugin: Result) { + match plugin { + Ok(plugin) => { + info!("[RPC] {} connected", plugin); + self.plugins.push(Arc::new(plugin)); + }, + Err(err) => { + warn!("plugin failed to connect: {:?}", err); + }, + } + } + + pub fn plugin_disconnect( + &mut self, + id: PluginId, + error: Result<(), ReadError>, + ) -> Option> { + if let Err(err) = error { + error!("[RPC] plugin {:?} exited with result {:?}", id, err) + } + + let running_idx = self.plugins.iter().position(|p| p.id == id); + match running_idx { + Some(idx) => { + let plugin = self.plugins.remove(idx); + plugin.shutdown(); + Some(plugin) + }, + None => { + warn!("[RPC] plugin {:?} not found", id); + None + }, + } + } +} + +#[derive(Clone)] +pub struct WeakSidecarState(Weak>); + +impl WeakSidecarState { + pub fn upgrade(&self) -> Option>> { + self.0.upgrade() + } + + pub fn plugin_connect(&self, plugin: Result) { + if let Some(state) = self.upgrade() { + state.lock().plugin_connect(plugin) + } + } + + pub fn plugin_exit(&self, plugin: PluginId, error: Result<(), ReadError>) { + if let Some(core) = self.upgrade() { + core.lock().plugin_disconnect(plugin, error); + } + } +} + +impl Handler for WeakSidecarState { + type Request = PluginCommand; + + fn handle_request( + &mut self, + _ctx: &RpcCtx, + rpc: Self::Request, + ) -> Result { + trace!("handling request: {:?}", rpc.cmd); + Ok(ResponsePayload::empty_json()) + } +} diff --git a/frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/down.sql b/frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/down.sql new file mode 100644 index 0000000000..d9a93fe9a1 --- /dev/null +++ b/frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` diff --git a/frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/up.sql b/frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/up.sql new file mode 100644 index 0000000000..2361adeb34 --- /dev/null +++ b/frontend/rust-lib/flowy-sqlite/migrations/2024-06-26-015936_chat_setting/up.sql @@ -0,0 +1,13 @@ +-- Your SQL goes here +ALTER TABLE chat_table ADD COLUMN local_model_path TEXT NOT NULL DEFAULT ''; +ALTER TABLE chat_table ADD COLUMN local_model_name TEXT NOT NULL DEFAULT ''; +ALTER TABLE chat_table ADD COLUMN local_enabled BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE chat_table ADD COLUMN sync_to_cloud BOOLEAN NOT NULL DEFAULT TRUE; + + +CREATE TABLE chat_local_setting_table +( + chat_id TEXT PRIMARY KEY NOT NULL, + local_model_path TEXT NOT NULL, + local_model_name TEXT NOT NULL DEFAULT '' +); \ No newline at end of file diff --git a/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs b/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs index 1ec71688c5..d10da70823 100644 --- a/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs +++ b/frontend/rust-lib/flowy-sqlite/src/kv/kv.rs @@ -11,13 +11,13 @@ use crate::sqlite_impl::{Database, PoolConfig}; const DB_NAME: &str = "cache.db"; -/// [StorePreferences] uses a sqlite database to store key value pairs. +/// [KVStorePreferences] uses a sqlite database to store key value pairs. /// Most of the time, it used to storage AppFlowy configuration. #[derive(Clone)] -pub struct StorePreferences { +pub struct KVStorePreferences { database: Option, } -impl StorePreferences { +impl KVStorePreferences { #[tracing::instrument(level = "trace", err)] pub fn new(root: &str) -> Result { if !Path::new(root).exists() { @@ -138,7 +138,7 @@ mod tests { use serde::{Deserialize, Serialize}; use tempfile::TempDir; - use crate::kv::StorePreferences; + use crate::kv::KVStorePreferences; #[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)] struct Person { @@ -150,7 +150,7 @@ mod tests { fn kv_store_test() { let tempdir = TempDir::new().unwrap(); let path = tempdir.into_path(); - let store = StorePreferences::new(path.to_str().unwrap()).unwrap(); + let store = KVStorePreferences::new(path.to_str().unwrap()).unwrap(); store.set_str("1", "hello".to_string()); assert_eq!(store.get_str("1").unwrap(), "hello"); diff --git a/frontend/rust-lib/flowy-sqlite/src/schema.rs b/frontend/rust-lib/flowy-sqlite/src/schema.rs index c45c329c1d..ee7f1aa546 100644 --- a/frontend/rust-lib/flowy-sqlite/src/schema.rs +++ b/frontend/rust-lib/flowy-sqlite/src/schema.rs @@ -1,5 +1,13 @@ // @generated automatically by Diesel CLI. +diesel::table! { + chat_local_setting_table (chat_id) { + chat_id -> Text, + local_model_path -> Text, + local_model_name -> Text, + } +} + diesel::table! { chat_message_table (message_id) { message_id -> BigInt, @@ -17,6 +25,10 @@ diesel::table! { chat_id -> Text, created_at -> BigInt, name -> Text, + local_model_path -> Text, + local_model_name -> Text, + local_enabled -> Bool, + sync_to_cloud -> Bool, } } @@ -103,6 +115,7 @@ diesel::table! { } diesel::allow_tables_to_appear_in_same_query!( + chat_local_setting_table, chat_message_table, chat_table, collab_snapshot, diff --git a/frontend/rust-lib/flowy-storage/src/uploader.rs b/frontend/rust-lib/flowy-storage/src/uploader.rs index 5469c1d05b..9d6fb0ecb0 100644 --- a/frontend/rust-lib/flowy-storage/src/uploader.rs +++ b/frontend/rust-lib/flowy-storage/src/uploader.rs @@ -242,6 +242,7 @@ impl Display for UploadTask { } } } + impl Eq for UploadTask {} impl PartialEq for UploadTask { diff --git a/frontend/rust-lib/flowy-user/src/event_handler.rs b/frontend/rust-lib/flowy-user/src/event_handler.rs index 337e1aa565..c10bd4484f 100644 --- a/frontend/rust-lib/flowy-user/src/event_handler.rs +++ b/frontend/rust-lib/flowy-user/src/event_handler.rs @@ -1,5 +1,5 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::cloud::UserCloudConfig; use flowy_user_pub::entities::*; use lib_dispatch::prelude::*; @@ -25,8 +25,8 @@ fn upgrade_manager(manager: AFPluginState>) -> FlowyResult>, -) -> FlowyResult> { + store: AFPluginState>, +) -> FlowyResult> { let store = store .upgrade() .ok_or(FlowyError::internal().with_context("The store preferences is already drop"))?; @@ -151,7 +151,7 @@ const APPEARANCE_SETTING_CACHE_KEY: &str = "appearance_settings"; #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_appearance_setting( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> Result<(), FlowyError> { let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -165,7 +165,7 @@ pub async fn set_appearance_setting( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn get_appearance_setting( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let store_preferences = upgrade_store_preferences(store_preferences)?; match store_preferences.get_str(APPEARANCE_SETTING_CACHE_KEY) { @@ -187,7 +187,7 @@ const DATE_TIME_SETTINGS_CACHE_KEY: &str = "date_time_settings"; #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_date_time_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> Result<(), FlowyError> { let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -202,7 +202,7 @@ pub async fn set_date_time_settings( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn get_date_time_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let store_preferences = upgrade_store_preferences(store_preferences)?; match store_preferences.get_str(DATE_TIME_SETTINGS_CACHE_KEY) { @@ -227,7 +227,7 @@ const NOTIFICATION_SETTINGS_CACHE_KEY: &str = "notification_settings"; #[tracing::instrument(level = "debug", skip_all, err)] pub async fn set_notification_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, data: AFPluginData, ) -> Result<(), FlowyError> { let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -238,7 +238,7 @@ pub async fn set_notification_settings( #[tracing::instrument(level = "debug", skip_all, err)] pub async fn get_notification_settings( - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let store_preferences = upgrade_store_preferences(store_preferences)?; match store_preferences.get_str(NOTIFICATION_SETTINGS_CACHE_KEY) { @@ -348,7 +348,7 @@ pub async fn sign_in_with_provider_handler( pub async fn set_encrypt_secret_handler( manager: AFPluginState>, data: AFPluginData, - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> Result<(), FlowyError> { let manager = upgrade_manager(manager)?; let store_preferences = upgrade_store_preferences(store_preferences)?; @@ -408,7 +408,7 @@ pub async fn check_encrypt_secret_handler( pub async fn set_cloud_config_handler( manager: AFPluginState>, data: AFPluginData, - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> Result<(), FlowyError> { let manager = upgrade_manager(manager)?; let session = manager.get_session()?; @@ -468,7 +468,7 @@ pub async fn set_cloud_config_handler( #[tracing::instrument(level = "info", skip_all, err)] pub async fn get_cloud_config_handler( manager: AFPluginState>, - store_preferences: AFPluginState>, + store_preferences: AFPluginState>, ) -> DataResult { let manager = upgrade_manager(manager)?; let session = manager.get_session()?; diff --git a/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs b/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs index 77376e1c6c..172f88209f 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs @@ -1,4 +1,4 @@ -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::session::Session; use serde_json::{json, Value}; use std::sync::Arc; @@ -8,7 +8,7 @@ const MIGRATION_USER_NO_USER_UUID: &str = "migration_user_no_user_uuid"; pub fn migrate_session_with_user_uuid( session_cache_key: &str, - store_preferences: &Arc, + store_preferences: &Arc, ) -> Option { if !store_preferences.get_bool(MIGRATION_USER_NO_USER_UUID) && store_preferences diff --git a/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs b/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs index dc7b9c1b9c..420ffdeda6 100644 --- a/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs +++ b/frontend/rust-lib/flowy-user/src/services/authenticate_user.rs @@ -5,7 +5,7 @@ use crate::services::sqlite_sql::user_sql::vacuum_database; use collab_integrate::CollabKVDB; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; use flowy_user_pub::entities::UserWorkspace; use flowy_user_pub::session::Session; @@ -19,12 +19,12 @@ pub struct AuthenticateUser { pub user_config: UserConfig, pub(crate) database: Arc, pub(crate) user_paths: UserPaths, - store_preferences: Arc, + store_preferences: Arc, session: Arc>>, } impl AuthenticateUser { - pub fn new(user_config: UserConfig, store_preferences: Arc) -> Self { + pub fn new(user_config: UserConfig, store_preferences: Arc) -> Self { let user_paths = UserPaths::new(user_config.storage_path.clone()); let database = Arc::new(UserDB::new(user_paths.clone())); let session = Arc::new(parking_lot::RwLock::new(None)); diff --git a/frontend/rust-lib/flowy-user/src/services/cloud_config.rs b/frontend/rust-lib/flowy-user/src/services/cloud_config.rs index 6772ac7ab5..62ab5a5e72 100644 --- a/frontend/rust-lib/flowy-user/src/services/cloud_config.rs +++ b/frontend/rust-lib/flowy-user/src/services/cloud_config.rs @@ -2,12 +2,12 @@ use std::sync::Arc; use flowy_encrypt::generate_encryption_secret; use flowy_error::FlowyResult; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::cloud::UserCloudConfig; const CLOUD_CONFIG_KEY: &str = "af_user_cloud_config"; -fn generate_cloud_config(uid: i64, store_preference: &Arc) -> UserCloudConfig { +fn generate_cloud_config(uid: i64, store_preference: &Arc) -> UserCloudConfig { let config = UserCloudConfig::new(generate_encryption_secret()); let key = cache_key_for_cloud_config(uid); store_preference.set_object(&key, config.clone()).unwrap(); @@ -16,7 +16,7 @@ fn generate_cloud_config(uid: i64, store_preference: &Arc) -> pub fn save_cloud_config( uid: i64, - store_preference: &Arc, + store_preference: &Arc, config: UserCloudConfig, ) -> FlowyResult<()> { tracing::info!("save user:{} cloud config: {}", uid, config); @@ -31,7 +31,7 @@ fn cache_key_for_cloud_config(uid: i64) -> String { pub fn get_cloud_config( uid: i64, - store_preference: &Arc, + store_preference: &Arc, ) -> Option { let key = cache_key_for_cloud_config(uid); store_preference.get_object::(&key) @@ -39,7 +39,7 @@ pub fn get_cloud_config( pub fn get_or_create_cloud_config( uid: i64, - store_preferences: &Arc, + store_preferences: &Arc, ) -> UserCloudConfig { let key = cache_key_for_cloud_config(uid); store_preferences @@ -47,7 +47,7 @@ pub fn get_or_create_cloud_config( .unwrap_or_else(|| generate_cloud_config(uid, store_preferences)) } -pub fn get_encrypt_secret(uid: i64, store_preference: &Arc) -> Option { +pub fn get_encrypt_secret(uid: i64, store_preference: &Arc) -> Option { let key = cache_key_for_cloud_config(uid); store_preference .get_object::(&key) diff --git a/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs b/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs index f60f07deac..41d9d25a34 100644 --- a/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs +++ b/frontend/rust-lib/flowy-user/src/services/data_import/appflowy_data_import.rs @@ -26,7 +26,7 @@ use flowy_error::FlowyError; use flowy_folder_pub::cloud::gen_view_id; use flowy_folder_pub::entities::{AppFlowyData, ImportData}; use flowy_folder_pub::folder_builder::{ParentChildViews, ViewBuilder}; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_user_pub::cloud::{UserCloudService, UserCollabParams}; use flowy_user_pub::entities::{user_awareness_object_id, Authenticator}; use flowy_user_pub::session::Session; @@ -62,7 +62,7 @@ pub(crate) fn prepare_import(path: &str) -> anyhow::Result { return Err(anyhow!("The path: {} is not exist", path)); } let user_paths = UserPaths::new(path.to_string()); - let other_store_preferences = Arc::new(StorePreferences::new(path)?); + let other_store_preferences = Arc::new(KVStorePreferences::new(path)?); migrate_session_with_user_uuid("appflowy_session_cache", &other_store_preferences); let imported_session = other_store_preferences .get_object::("appflowy_session_cache") diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager.rs index 0f5fd66cde..8d8cb151fd 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager.rs @@ -4,7 +4,7 @@ use collab_user::core::MutexUserAwareness; use flowy_error::{internal_error, ErrorCode, FlowyResult}; use flowy_server_pub::AuthenticatorType; -use flowy_sqlite::kv::StorePreferences; +use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::schema::user_table; use flowy_sqlite::ConnectionPool; use flowy_sqlite::{query_dsl::*, DBConnection, ExpressionMethods}; @@ -48,7 +48,7 @@ use super::manager_user_workspace::save_user_workspace; pub struct UserManager { pub(crate) cloud_services: Arc, - pub(crate) store_preferences: Arc, + pub(crate) store_preferences: Arc, pub(crate) user_awareness: Arc>>, pub(crate) user_status_callback: RwLock>, pub(crate) collab_builder: Weak, @@ -63,7 +63,7 @@ pub struct UserManager { impl UserManager { pub fn new( cloud_services: Arc, - store_preferences: Arc, + store_preferences: Arc, collab_builder: Weak, authenticate_user: Arc, user_workspace_service: Arc, @@ -110,7 +110,7 @@ impl UserManager { } } - pub fn get_store_preferences(&self) -> Weak { + pub fn get_store_preferences(&self) -> Weak { Arc::downgrade(&self.store_preferences) } diff --git a/frontend/rust-lib/lib-infra/Cargo.toml b/frontend/rust-lib/lib-infra/Cargo.toml index 6b902537ee..416df9b04d 100644 --- a/frontend/rust-lib/lib-infra/Cargo.toml +++ b/frontend/rust-lib/lib-infra/Cargo.toml @@ -23,6 +23,7 @@ tracing.workspace = true atomic_refcell = "0.1" allo-isolate = { version = "^0.1", features = ["catch-unwind"], optional = true } futures = "0.3.30" +cfg-if = "1.0.0" [dev-dependencies] rand = "0.8.5" diff --git a/frontend/rust-lib/lib-infra/src/lib.rs b/frontend/rust-lib/lib-infra/src/lib.rs index 18539e49aa..3b46e162fb 100644 --- a/frontend/rust-lib/lib-infra/src/lib.rs +++ b/frontend/rust-lib/lib-infra/src/lib.rs @@ -23,5 +23,6 @@ if_wasm! { pub mod isolate_stream; pub mod priority_task; pub mod ref_map; +pub mod stream_util; pub mod util; pub mod validator_fn; diff --git a/frontend/rust-lib/lib-infra/src/stream_util.rs b/frontend/rust-lib/lib-infra/src/stream_util.rs new file mode 100644 index 0000000000..41c747d26a --- /dev/null +++ b/frontend/rust-lib/lib-infra/src/stream_util.rs @@ -0,0 +1,21 @@ +use futures_core::Stream; +use std::pin::Pin; +use std::task::{Context, Poll}; +use tokio::sync::mpsc; +use tokio::sync::mpsc::{Receiver, Sender}; + +struct BoundedStream { + recv: Receiver, +} +impl Stream for BoundedStream { + type Item = T; + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + Pin::into_inner(self).recv.poll_recv(cx) + } +} + +pub fn mpsc_channel_stream(size: usize) -> (Sender, impl Stream) { + let (tx, rx) = mpsc::channel(size); + let stream = BoundedStream { recv: rx }; + (tx, stream) +} diff --git a/frontend/rust-lib/lib-infra/src/util.rs b/frontend/rust-lib/lib-infra/src/util.rs index 823095a26f..b67646e4be 100644 --- a/frontend/rust-lib/lib-infra/src/util.rs +++ b/frontend/rust-lib/lib-infra/src/util.rs @@ -67,9 +67,8 @@ pub fn md5>(data: T) -> String { let md5 = format!("{:x}", md5::compute(data)); md5 } - #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Platform { +pub enum OperatingSystem { Unknown, Windows, Linux, @@ -78,33 +77,62 @@ pub enum Platform { Android, } -impl Platform { +impl OperatingSystem { pub fn is_not_ios(&self) -> bool { - !matches!(self, Platform::IOS) + !matches!(self, OperatingSystem::IOS) + } + + pub fn is_desktop(&self) -> bool { + matches!( + self, + OperatingSystem::Windows | OperatingSystem::Linux | OperatingSystem::MacOS + ) + } + + pub fn is_not_desktop(&self) -> bool { + !self.is_desktop() } } -impl From for Platform { +impl From for OperatingSystem { fn from(s: String) -> Self { - Platform::from(s.as_str()) + OperatingSystem::from(s.as_str()) } } -impl From<&String> for Platform { +impl From<&String> for OperatingSystem { fn from(s: &String) -> Self { - Platform::from(s.as_str()) + OperatingSystem::from(s.as_str()) } } -impl From<&str> for Platform { +impl From<&str> for OperatingSystem { fn from(s: &str) -> Self { match s { - "windows" => Platform::Windows, - "linux" => Platform::Linux, - "macos" => Platform::MacOS, - "ios" => Platform::IOS, - "android" => Platform::Android, - _ => Platform::Unknown, + "windows" => OperatingSystem::Windows, + "linux" => OperatingSystem::Linux, + "macos" => OperatingSystem::MacOS, + "ios" => OperatingSystem::IOS, + "android" => OperatingSystem::Android, + _ => OperatingSystem::Unknown, } } } + +pub fn get_operating_system() -> OperatingSystem { + cfg_if::cfg_if! { + if #[cfg(target_os = "android")] { + OperatingSystem::Android + } else if #[cfg(target_os = "ios")] { + OperatingSystem::IOS + } else if #[cfg(target_os = "macos")] { + OperatingSystem::MacOS + } else if #[cfg(target_os = "windows")] { + OperatingSystem::Windows + } else if #[cfg(target_os = "linux")] { + OperatingSystem::Linux + } else { + OperatingSystem::Unknown + } + } +} diff --git a/frontend/rust-lib/lib-log/src/lib.rs b/frontend/rust-lib/lib-log/src/lib.rs index a328be254c..a956368883 100644 --- a/frontend/rust-lib/lib-log/src/lib.rs +++ b/frontend/rust-lib/lib-log/src/lib.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, RwLock}; use chrono::Local; use lazy_static::lazy_static; -use lib_infra::util::Platform; +use lib_infra::util::OperatingSystem; use tracing::subscriber::set_global_default; use tracing_appender::rolling::Rotation; use tracing_appender::{non_blocking::WorkerGuard, rolling::RollingFileAppender}; @@ -29,7 +29,7 @@ pub struct Builder { env_filter: String, file_appender: RollingFileAppender, #[allow(dead_code)] - platform: Platform, + platform: OperatingSystem, stream_log_sender: Option>, } @@ -37,7 +37,7 @@ impl Builder { pub fn new( name: &str, directory: &str, - platform: &Platform, + platform: &OperatingSystem, stream_log_sender: Option>, ) -> Self { let file_appender = RollingFileAppender::builder() From 50f5be3e751b2f34e4090396885cb3f1f5eb6992 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 1 Jul 2024 13:26:43 +0800 Subject: [PATCH 03/12] chore: fix rustfmt ci test (#5664) --- frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs | 3 ++- frontend/rust-lib/flowy-chat/tests/util.rs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs b/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs index 2e26e1b582..8287e86c8b 100644 --- a/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs +++ b/frontend/rust-lib/flowy-chat/src/local_ai/chat_plugin.rs @@ -122,7 +122,8 @@ impl ResponseParser for ChatRelatedQuestionsResponseParser { fn parse_json(json: JsonValue) -> Result { json .get("data") - .and_then(|data| data.as_array()).cloned() + .and_then(|data| data.as_array()) + .cloned() .ok_or(RemoteError::ParseResponse(json)) } } diff --git a/frontend/rust-lib/flowy-chat/tests/util.rs b/frontend/rust-lib/flowy-chat/tests/util.rs index 5dbf37d8c8..a1f9e51d1e 100644 --- a/frontend/rust-lib/flowy-chat/tests/util.rs +++ b/frontend/rust-lib/flowy-chat/tests/util.rs @@ -72,7 +72,6 @@ impl LocalAITest { ) -> String { let plugin = self.manager.get_plugin(plugin_id).await.unwrap(); let operation = ChatPluginOperation::new(plugin); - operation.send_message(chat_id, message).await.unwrap() } @@ -95,7 +94,7 @@ impl LocalAITest { ) -> Vec { let plugin = self.manager.get_plugin(plugin_id).await.unwrap(); let operation = ChatPluginOperation::new(plugin); - + operation.get_related_questions(chat_id).await.unwrap() } From c78f23e1c01cb0857f57b57957a62c1863eb6042 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 1 Jul 2024 14:43:57 +0800 Subject: [PATCH 04/12] fix: v0.6.2 issues (#5654) * fix: remove create button in move to menu * fix: add loading indicator when duplicating space * fix: sidebar header expand icon status * fix: text within select tag overflow * fix: callout block icon align issue * feat: sync the space icon when creating a space * fix: duplicated hover views * fix: cover image doesn't update --- .../desktop_grid_select_option_cell.dart | 8 +-- ...desktop_row_detail_select_option_cell.dart | 6 +-- .../widgets/cell_editor/extension.dart | 1 - .../select_option_cell_editor.dart | 12 ++--- .../cell_editor/select_option_text_field.dart | 5 +- .../document/application/document_bloc.dart | 15 ------ .../callout/callout_block_component.dart | 3 +- .../header/document_header_node_widget.dart | 7 ++- .../migration/editor_migration.dart | 7 ++- .../application/sidebar/space/space_bloc.dart | 43 +++++++-------- .../workspace/application/view/view_ext.dart | 6 +-- .../workspace/workspace_service.dart | 5 ++ .../menu/sidebar/move_to/move_page_menu.dart | 1 + .../home/menu/sidebar/sidebar.dart | 14 ++++- .../menu/sidebar/space/shared_widget.dart | 12 +++-- .../sidebar/space/sidebar_space_header.dart | 1 + .../sidebar/space/sidebar_space_menu.dart | 27 ++++++---- .../home/menu/view/view_item.dart | 53 +++++++++++-------- .../event-integration-test/src/chat_event.rs | 1 + .../src/database_event.rs | 3 ++ .../src/document/document_event.rs | 1 + .../src/document_event.rs | 1 + .../src/folder_event.rs | 2 + .../tests/folder/local_test/script.rs | 1 + .../flowy-folder/src/entities/view.rs | 7 ++- 25 files changed, 143 insertions(+), 99 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_grid/desktop_grid_select_option_cell.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_grid/desktop_grid_select_option_cell.dart index 45b43efcec..ee283d6ccc 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_grid/desktop_grid_select_option_cell.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_grid/desktop_grid_select_option_cell.dart @@ -1,8 +1,8 @@ -import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; -import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'; -import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart'; import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart'; +import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; +import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart'; import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart'; +import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; @@ -56,7 +56,7 @@ class DesktopGridSelectOptionCellSkin extends IEditableSelectOptionCellSkin { child: SelectOptionTag( option: option, padding: const EdgeInsets.symmetric( - vertical: 1, + vertical: 4, horizontal: 8, ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_select_option_cell.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_select_option_cell.dart index 0e8c6fdffa..31dc63abe4 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_select_option_cell.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_select_option_cell.dart @@ -1,8 +1,8 @@ import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'; -import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart'; import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_bloc.dart'; +import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart'; import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart'; +import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -67,7 +67,7 @@ class DesktopRowDetailSelectOptionCellSkin return SelectOptionTag( option: option, padding: const EdgeInsets.symmetric( - vertical: 1, + vertical: 4, horizontal: 8, ), ); diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/extension.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/extension.dart index d4d93d4f4b..a92fba5e24 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/extension.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/extension.dart @@ -96,7 +96,6 @@ class SelectOptionTag extends StatelessWidget { ); return Container( - height: 20, padding: onRemove == null ? padding : padding.copyWith(right: 2.0), decoration: BoxDecoration( color: optionColor, diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_cell_editor.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_cell_editor.dart index a2653a5389..8fdb99769a 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_cell_editor.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_cell_editor.dart @@ -1,10 +1,6 @@ import 'dart:collection'; import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_editor_bloc.dart'; @@ -14,12 +10,14 @@ import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../grid/presentation/layout/sizes.dart'; import '../../grid/presentation/widgets/common/type_option_separator.dart'; import '../field/type_option_editor/select/select_option_editor.dart'; - import 'extension.dart'; import 'select_option_text_field.dart'; @@ -476,11 +474,11 @@ class SelectOptionTagCell extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric( horizontal: 6.0, - vertical: 4.0, ), child: SelectOptionTag( option: option, - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: + const EdgeInsets.symmetric(horizontal: 8, vertical: 4), ), ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_text_field.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_text_field.dart index f16500f601..2a4b8daa37 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_text_field.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_text_field.dart @@ -132,7 +132,10 @@ class _SelectOptionTextFieldState extends State { (option) => SelectOptionTag( option: option, onRemove: (option) => widget.onRemove(option), - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1), + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), ), ) .toList(); diff --git a/frontend/appflowy_flutter/lib/plugins/document/application/document_bloc.dart b/frontend/appflowy_flutter/lib/plugins/document/application/document_bloc.dart index 121582e1f3..a50c7cac2d 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/application/document_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/application/document_bloc.dart @@ -8,7 +8,6 @@ import 'package:appflowy/plugins/document/application/document_data_pb_extension import 'package:appflowy/plugins/document/application/document_listener.dart'; import 'package:appflowy/plugins/document/application/document_service.dart'; import 'package:appflowy/plugins/document/application/editor_transaction_adapter.dart'; -import 'package:appflowy/plugins/document/presentation/editor_plugins/migration/editor_migration.dart'; import 'package:appflowy/plugins/trash/application/trash_service.dart'; import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/startup/startup.dart'; @@ -19,7 +18,6 @@ import 'package:appflowy/util/color_to_hex_string.dart'; import 'package:appflowy/util/debounce.dart'; import 'package:appflowy/util/throttle.dart'; import 'package:appflowy/workspace/application/view/view_listener.dart'; -import 'package:appflowy/workspace/application/view/view_service.dart'; import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; @@ -118,11 +116,6 @@ class DocumentBloc extends Bloc { final result = await _fetchDocumentState(); _onViewChanged(); _onDocumentChanged(); - result.onSuccess((s) { - if (s != null) { - _migrateCover(s); - } - }); final newState = await result.fold( (s) async { final userProfilePB = @@ -390,14 +383,6 @@ class DocumentBloc extends Bloc { metadata: jsonEncode(metadata.toJson()), ); } - - // from version 0.5.5, the cover is stored in the view.ext - Future _migrateCover(EditorState editorState) async { - final view = await ViewBackendService.getView(documentId); - view.onSuccess((s) { - return EditorMigration.migrateCoverIfNeeded(s, editorState); - }); - } } @freezed diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/callout/callout_block_component.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/callout/callout_block_component.dart index e025dd6d27..a7bfe2da41 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/callout/callout_block_component.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/callout/callout_block_component.dart @@ -196,6 +196,7 @@ class _CalloutBlockComponentWidgetState ), // force to refresh the popover state title: '', emoji: emoji, + emojiSize: 16.0, onSubmitted: (emoji, controller) { setEmoji(emoji); controller?.close(); @@ -204,7 +205,7 @@ class _CalloutBlockComponentWidgetState ), Flexible( child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 6.0), child: buildCalloutBlockComponent(context, textDirection), ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart index aa15ea7419..40e4d54855 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/header/document_header_node_widget.dart @@ -91,6 +91,7 @@ class _DocumentCoverWidgetState extends State { String viewIcon = ''; PageStyleCover? cover; + late ViewPB view; late final ViewListener viewListener; @override @@ -99,6 +100,7 @@ class _DocumentCoverWidgetState extends State { final value = widget.view.icon.value; viewIcon = value.isNotEmpty ? value : icon ?? ''; cover = widget.view.cover; + view = widget.view; widget.node.addListener(_reload); viewListener = ViewListener( viewId: widget.view.id, @@ -107,6 +109,7 @@ class _DocumentCoverWidgetState extends State { setState(() { viewIcon = p0.icon.value; cover = p0.cover; + view = p0; }); }, ); @@ -137,7 +140,7 @@ class _DocumentCoverWidgetState extends State { ), if (hasCover) DocumentCover( - view: widget.view, + view: view, editorState: widget.editorState, node: widget.node, coverType: coverType, @@ -204,7 +207,7 @@ class _DocumentCoverWidgetState extends State { // compatible with version > 0.5.5. EditorMigration.migrateCoverIfNeeded( widget.view, - widget.editorState, + attributes, overwrite: true, ); } diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/migration/editor_migration.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/migration/editor_migration.dart index 664e2143b6..545fe9dd4a 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/migration/editor_migration.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/migration/editor_migration.dart @@ -164,18 +164,17 @@ class EditorMigration { // Now, the cover is stored in the view.ext. static void migrateCoverIfNeeded( ViewPB view, - EditorState editorState, { + Attributes attributes, { bool overwrite = false, }) async { if (view.extra.isNotEmpty && !overwrite) { return; } - final root = editorState.document.root; final coverType = CoverType.fromString( - root.attributes[DocumentHeaderBlockKeys.coverType], + attributes[DocumentHeaderBlockKeys.coverType], ); - final coverDetails = root.attributes[DocumentHeaderBlockKeys.coverDetails]; + final coverDetails = attributes[DocumentHeaderBlockKeys.coverDetails]; Map extra = {}; diff --git a/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart index f6a2226e6a..611908cb1a 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart @@ -297,11 +297,16 @@ class SpaceBloc extends Bloc { if (currentSpace == null) { return; } + emit(state.copyWith(isDuplicatingSpace: true)); + final newSpace = await _duplicateSpace(currentSpace); // open the duplicated space if (newSpace != null) { + add(const SpaceEvent.didReceiveSpaceUpdate()); add(SpaceEvent.open(newSpace)); } + + emit(state.copyWith(isDuplicatingSpace: false)); }, ); }, @@ -346,25 +351,22 @@ class SpaceBloc extends Bloc { SpacePermission.private => ViewSectionPB.Private, }; + final extra = { + ViewExtKeys.isSpaceKey: true, + ViewExtKeys.spaceIconKey: icon, + ViewExtKeys.spaceIconColorKey: iconColor, + ViewExtKeys.spacePermissionKey: permission.index, + ViewExtKeys.spaceCreatedAtKey: DateTime.now().millisecondsSinceEpoch, + }; final result = await _workspaceService.createView( name: name, viewSection: section, - setAsCurrent: false, + setAsCurrent: true, viewId: viewId, + extra: jsonEncode(extra), ); return await result.fold((space) async { Log.info('Space created: $space'); - final extra = { - ViewExtKeys.isSpaceKey: true, - ViewExtKeys.spaceIconKey: icon, - ViewExtKeys.spaceIconColorKey: iconColor, - ViewExtKeys.spacePermissionKey: permission.index, - ViewExtKeys.spaceCreatedAtKey: DateTime.now().millisecondsSinceEpoch, - }; - await ViewBackendService.updateView( - viewId: space.id, - extra: jsonEncode(extra), - ); return space; }, (error) { Log.error('Failed to create space: $error'); @@ -620,19 +622,17 @@ class SpaceBloc extends Bloc { } for (final view in space.childViews) { - unawaited( - ViewBackendService.duplicate( - view: view, - openAfterDuplicate: true, - includeChildren: true, - parentViewId: newSpace.id, - suffix: '', - ), + await ViewBackendService.duplicate( + view: view, + openAfterDuplicate: true, + includeChildren: true, + parentViewId: newSpace.id, + suffix: '', ); } Log.info('Space duplicated: $newSpace'); - add(const SpaceEvent.didReceiveSpaceUpdate()); + return newSpace; } } @@ -688,6 +688,7 @@ class SpaceState with _$SpaceState { @Default(null) ViewPB? lastCreatedPage, FlowyResult? createPageResult, @Default(false) bool shouldShowUpgradeDialog, + @Default(false) bool isDuplicatingSpace, }) = _SpaceState; factory SpaceState.initial() => const SpaceState(); diff --git a/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart b/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart index cfb1690e5e..888f91897a 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart @@ -133,13 +133,13 @@ extension ViewExtension on ViewPB { } } - FlowySvg get spaceIconSvg { + FlowySvg? get spaceIconSvg { try { final ext = jsonDecode(extra); final icon = ext[ViewExtKeys.spaceIconKey]; final color = ext[ViewExtKeys.spaceIconColorKey]; if (icon == null || color == null) { - return const FlowySvg(FlowySvgs.space_icon_s, blendMode: null); + return null; } return FlowySvg( FlowySvgData('assets/flowy_icons/16x/$icon.svg'), @@ -147,7 +147,7 @@ extension ViewExtension on ViewPB { blendMode: BlendMode.srcOut, ); } catch (e) { - return const FlowySvg(FlowySvgs.space_icon_s, blendMode: null); + return null; } } diff --git a/frontend/appflowy_flutter/lib/workspace/application/workspace/workspace_service.dart b/frontend/appflowy_flutter/lib/workspace/application/workspace/workspace_service.dart index 8da9ad4854..067767a9e1 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/workspace/workspace_service.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/workspace/workspace_service.dart @@ -19,6 +19,7 @@ class WorkspaceService { ViewLayoutPB? layout, bool? setAsCurrent, String? viewId, + String? extra, }) { final payload = CreateViewPayloadPB.create() ..parentViewId = workspaceId @@ -42,6 +43,10 @@ class WorkspaceService { payload.viewId = viewId; } + if (extra != null) { + payload.extra = extra; + } + return FolderEventCreateView(payload).send(); } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart index 36352864e8..4225f81ad2 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart @@ -117,6 +117,7 @@ class _MovePageMenuState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ SpacePopup( + showCreateButton: false, child: CurrentSpace( space: space, ), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart index a47d9db862..f2abaecc1d 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/blank/blank.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart'; import 'package:appflowy/shared/feature_flags.dart'; import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart'; @@ -38,6 +39,8 @@ import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +Loading? _duplicateSpaceLoading; + /// Home Sidebar is the left side bar of the home page. /// /// in the sidebar, we have: @@ -136,7 +139,8 @@ class HomeSideBar extends StatelessWidget { ), BlocListener( listenWhen: (p, c) => - p.lastCreatedPage?.id != c.lastCreatedPage?.id, + p.lastCreatedPage?.id != c.lastCreatedPage?.id || + p.isDuplicatingSpace != c.isDuplicatingSpace, listener: (context, state) { final page = state.lastCreatedPage; if (page == null || page.id.isEmpty) { @@ -153,6 +157,14 @@ class HomeSideBar extends StatelessWidget { ), ); } + + if (state.isDuplicatingSpace) { + _duplicateSpaceLoading ??= Loading(context); + _duplicateSpaceLoading?.start(); + } else if (_duplicateSpaceLoading != null) { + _duplicateSpaceLoading?.stop(); + _duplicateSpaceLoading = null; + } }, ), BlocListener( diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart index 1ae08c0abd..42168abc9e 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart @@ -277,9 +277,11 @@ class DeleteSpacePopup extends StatelessWidget { class SpacePopup extends StatelessWidget { const SpacePopup({ super.key, + required this.showCreateButton, required this.child, }); + final bool showCreateButton; final Widget child; @override @@ -293,7 +295,9 @@ class SpacePopup extends StatelessWidget { offset: const Offset(0, 4), popupBuilder: (_) => BlocProvider.value( value: context.read(), - child: const SidebarSpaceMenu(), + child: SidebarSpaceMenu( + showCreateButton: showCreateButton, + ), ), child: FlowyButton( useIntrinsicWidth: true, @@ -333,8 +337,10 @@ class CurrentSpace extends StatelessWidget { ), ), const HSpace(4.0), - const FlowySvg( - FlowySvgs.workspace_drop_down_menu_show_s, + FlowySvg( + context.read().state.isExpanded + ? FlowySvgs.workspace_drop_down_menu_show_s + : FlowySvgs.workspace_drop_down_menu_hide_s, ), ], ); diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart index 1818280908..9adcdb6822 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart @@ -89,6 +89,7 @@ class _SidebarSpaceHeaderState extends State { bottom: 3, right: isHovered.value || onEditing ? 88 : 0, child: SpacePopup( + showCreateButton: true, child: _buildChild(), ), ), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart index 6db5f54d81..9ff798ee5d 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart @@ -14,7 +14,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class SidebarSpaceMenu extends StatelessWidget { - const SidebarSpaceMenu({super.key}); + const SidebarSpaceMenu({ + super.key, + required this.showCreateButton, + }); + + final bool showCreateButton; @override Widget build(BuildContext context) { @@ -32,16 +37,18 @@ class SidebarSpaceMenu extends StatelessWidget { isSelected: state.currentSpace?.id == space.id, ), ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 8.0), - child: Divider( - height: 0.5, + if (showCreateButton) ...[ + const Padding( + padding: EdgeInsets.symmetric(vertical: 8.0), + child: Divider( + height: 0.5, + ), ), - ), - const SizedBox( - height: HomeSpaceViewSizes.viewHeight, - child: _CreateSpaceButton(), - ), + const SizedBox( + height: HomeSpaceViewSizes.viewHeight, + child: _CreateSpaceButton(), + ), + ], ], ); }, diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_item.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_item.dart index 860a9e3e81..9145c9ac78 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_item.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_item.dart @@ -257,26 +257,33 @@ class _InnerViewItemState extends State { @override Widget build(BuildContext context) { - Widget child = SingleInnerViewItem( - view: widget.view, - parentView: widget.parentView, - level: widget.level, - showActions: widget.showActions, - spaceType: widget.spaceType, - onSelected: widget.onSelected, - onTertiarySelected: widget.onTertiarySelected, - isExpanded: widget.isExpanded, - isDraggable: widget.isDraggable, - leftPadding: widget.leftPadding, - isFeedback: widget.isFeedback, - height: widget.height, - isPlaceholder: widget.isPlaceholder, - isHovered: widget.isHovered, - leftIconBuilder: widget.leftIconBuilder, - rightIconsBuilder: widget.rightIconsBuilder, - extendBuilder: widget.extendBuilder, - disableSelectedStatus: widget.disableSelectedStatus, - shouldIgnoreView: widget.shouldIgnoreView, + Widget child = ValueListenableBuilder( + valueListenable: getIt().notifier, + builder: (context, value, _) { + final isSelected = value?.id == widget.view.id; + return SingleInnerViewItem( + view: widget.view, + parentView: widget.parentView, + level: widget.level, + showActions: widget.showActions, + spaceType: widget.spaceType, + onSelected: widget.onSelected, + onTertiarySelected: widget.onTertiarySelected, + isExpanded: widget.isExpanded, + isDraggable: widget.isDraggable, + leftPadding: widget.leftPadding, + isFeedback: widget.isFeedback, + height: widget.height, + isPlaceholder: widget.isPlaceholder, + isHovered: widget.isHovered, + leftIconBuilder: widget.leftIconBuilder, + rightIconsBuilder: widget.rightIconsBuilder, + extendBuilder: widget.extendBuilder, + disableSelectedStatus: widget.disableSelectedStatus, + shouldIgnoreView: widget.shouldIgnoreView, + isSelected: isSelected, + ); + }, ); // if the view is expanded and has child views, render its child views @@ -403,6 +410,7 @@ class SingleInnerViewItem extends StatefulWidget { required this.extendBuilder, required this.disableSelectedStatus, required this.shouldIgnoreView, + required this.isSelected, }); final ViewPB view; @@ -430,6 +438,7 @@ class SingleInnerViewItem extends StatefulWidget { final List Function(ViewPB view)? extendBuilder; final bool Function(ViewPB view)? shouldIgnoreView; + final bool isSelected; @override State createState() => _SingleInnerViewItemState(); @@ -441,8 +450,8 @@ class _SingleInnerViewItemState extends State { @override Widget build(BuildContext context) { - var isSelected = - getIt().latestOpenView?.id == widget.view.id; + var isSelected = widget.isSelected; + if (widget.disableSelectedStatus == true) { isSelected = false; } diff --git a/frontend/rust-lib/event-integration-test/src/chat_event.rs b/frontend/rust-lib/event-integration-test/src/chat_event.rs index a02fc6805f..2371820f84 100644 --- a/frontend/rust-lib/event-integration-test/src/chat_event.rs +++ b/frontend/rust-lib/event-integration-test/src/chat_event.rs @@ -22,6 +22,7 @@ impl EventIntegrationTest { index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(self.clone()) .event(FolderEvent::CreateView) diff --git a/frontend/rust-lib/event-integration-test/src/database_event.rs b/frontend/rust-lib/event-integration-test/src/database_event.rs index 4b6968ec06..b16f9d5ab5 100644 --- a/frontend/rust-lib/event-integration-test/src/database_event.rs +++ b/frontend/rust-lib/event-integration-test/src/database_event.rs @@ -46,6 +46,7 @@ impl EventIntegrationTest { index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(self.clone()) .event(FolderEvent::CreateView) @@ -78,6 +79,7 @@ impl EventIntegrationTest { index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(self.clone()) .event(FolderEvent::CreateView) @@ -105,6 +107,7 @@ impl EventIntegrationTest { index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(self.clone()) .event(FolderEvent::CreateView) diff --git a/frontend/rust-lib/event-integration-test/src/document/document_event.rs b/frontend/rust-lib/event-integration-test/src/document/document_event.rs index 8595ac056b..4203dcc88c 100644 --- a/frontend/rust-lib/event-integration-test/src/document/document_event.rs +++ b/frontend/rust-lib/event-integration-test/src/document/document_event.rs @@ -66,6 +66,7 @@ impl DocumentEventTest { index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(core.clone()) .event(FolderEvent::CreateView) diff --git a/frontend/rust-lib/event-integration-test/src/document_event.rs b/frontend/rust-lib/event-integration-test/src/document_event.rs index 8374bc9de3..6194e10ab7 100644 --- a/frontend/rust-lib/event-integration-test/src/document_event.rs +++ b/frontend/rust-lib/event-integration-test/src/document_event.rs @@ -43,6 +43,7 @@ impl EventIntegrationTest { index: None, section: None, view_id: None, + extra: None, }; let view = EventBuilder::new(self.clone()) .event(FolderEvent::CreateView) diff --git a/frontend/rust-lib/event-integration-test/src/folder_event.rs b/frontend/rust-lib/event-integration-test/src/folder_event.rs index 0a13eb7f5b..be218fa89d 100644 --- a/frontend/rust-lib/event-integration-test/src/folder_event.rs +++ b/frontend/rust-lib/event-integration-test/src/folder_event.rs @@ -238,6 +238,7 @@ impl EventIntegrationTest { index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(self.clone()) .event(FolderEvent::CreateView) @@ -302,6 +303,7 @@ impl ViewTest { index: None, section: None, view_id: None, + extra: None, }; let view = EventBuilder::new(sdk.clone()) diff --git a/frontend/rust-lib/event-integration-test/tests/folder/local_test/script.rs b/frontend/rust-lib/event-integration-test/tests/folder/local_test/script.rs index 0ebbd64efa..49fbc01384 100644 --- a/frontend/rust-lib/event-integration-test/tests/folder/local_test/script.rs +++ b/frontend/rust-lib/event-integration-test/tests/folder/local_test/script.rs @@ -253,6 +253,7 @@ pub async fn create_view( index: None, section: None, view_id: None, + extra: None, }; EventBuilder::new(sdk.clone()) .event(CreateView) diff --git a/frontend/rust-lib/flowy-folder/src/entities/view.rs b/frontend/rust-lib/flowy-folder/src/entities/view.rs index 79654602e8..3a919e8ec4 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/view.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/view.rs @@ -261,6 +261,11 @@ pub struct CreateViewPayloadPB { #[pb(index = 11, one_of)] pub view_id: Option, + + // The extra data of the view. + // Refer to the extra field in the collab + #[pb(index = 12, one_of)] + pub extra: Option, } #[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone, Default)] @@ -335,7 +340,7 @@ impl TryInto for CreateViewPayloadPB { index: self.index, section: self.section, icon: None, - extra: None, + extra: self.extra, }) } } From 2b8dca209e6f3dc82e0be7cb6e6af234b957d783 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 1 Jul 2024 14:44:08 +0800 Subject: [PATCH 05/12] feat: sync the documents and databases after batch importing documents and databases (#5644) * feat: support batch import * feat: support batch import database * chore: revert launch.json * chore: fix rust ci * fix: rust ci --- .../settings/share/import_service.dart | 49 ++++---- .../menu/sidebar/import/import_panel.dart | 69 +++++------ .../src/folder_event.rs | 5 +- .../tests/folder/local_test/import_test.rs | 32 +++--- .../src/deps_resolve/folder_deps.rs | 16 +-- .../rust-lib/flowy-database2/src/manager.rs | 25 ++-- .../src/services/share/csv/import.rs | 2 + .../rust-lib/flowy-document/src/manager.rs | 19 ++-- .../flowy-folder/src/entities/import.rs | 105 +++++++++++------ .../flowy-folder/src/event_handler.rs | 9 +- .../rust-lib/flowy-folder/src/event_map.rs | 2 +- frontend/rust-lib/flowy-folder/src/manager.rs | 107 ++++++++++++++---- .../rust-lib/flowy-folder/src/share/import.rs | 10 +- .../flowy-folder/src/view_operation.rs | 5 +- 14 files changed, 291 insertions(+), 164 deletions(-) diff --git a/frontend/appflowy_flutter/lib/workspace/application/settings/share/import_service.dart b/frontend/appflowy_flutter/lib/workspace/application/settings/share/import_service.dart index 34ea16e52f..aafcf86c5d 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/settings/share/import_service.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/settings/share/import_service.dart @@ -4,34 +4,29 @@ import 'package:appflowy_backend/protobuf/flowy-folder/import.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart'; import 'package:appflowy_result/appflowy_result.dart'; -class ImportBackendService { - static Future> importData( - List data, - String name, - String parentViewId, - ImportTypePB importType, - ) async { - final payload = ImportPB.create() - ..data = data - ..parentViewId = parentViewId - ..viewLayout = importType.toLayout() - ..name = name - ..importType = importType; - return FolderEventImportData(payload).send(); - } +class ImportPayload { + ImportPayload({ + required this.name, + required this.data, + required this.layout, + }); + + final String name; + final List data; + final ViewLayoutPB layout; } -extension on ImportTypePB { - ViewLayoutPB toLayout() { - switch (this) { - case ImportTypePB.HistoryDocument: - return ViewLayoutPB.Document; - case ImportTypePB.HistoryDatabase || - ImportTypePB.CSV || - ImportTypePB.RawDatabase: - return ViewLayoutPB.Grid; - default: - throw UnimplementedError('Unsupported import type $this'); - } +class ImportBackendService { + static Future> importPages( + String parentViewId, + List values, + ) async { + final request = ImportPayloadPB( + parentViewId: parentViewId, + values: values, + syncAfterCreate: true, + ); + + return FolderEventImportData(request).send(); } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/import/import_panel.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/import/import_panel.dart index 6277d83fd9..a888a071e3 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/import/import_panel.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/import/import_panel.dart @@ -7,8 +7,6 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/migration/ import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/workspace/application/settings/share/import_service.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/import/import_type.dart'; -import 'package:appflowy/workspace/presentation/home/toast.dart'; -import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; import 'package:appflowy_editor/appflowy_editor.dart' hide Log; import 'package:easy_localization/easy_localization.dart'; @@ -153,6 +151,8 @@ class _ImportPanelState extends State { showLoading.value = true; + final importValues = []; + for (final file in result.files) { final path = file.path; if (path == null) { @@ -166,59 +166,52 @@ class _ImportPanelState extends State { case ImportType.historyDocument: final bytes = _documentDataFrom(importType, data); if (bytes != null) { - final result = await ImportBackendService.importData( - bytes, - name, - parentViewId, - ImportTypePB.HistoryDocument, + importValues.add( + ImportValuePayloadPB.create() + ..name = name + ..data = bytes + ..viewLayout = ViewLayoutPB.Document + ..importType = ImportTypePB.HistoryDocument, ); - result.onFailure((error) { - showSnackBarMessage(context, error.msg); - Log.error('Failed to import markdown $error'); - }); } break; case ImportType.historyDatabase: - final result = await ImportBackendService.importData( - utf8.encode(data), - name, - parentViewId, - ImportTypePB.HistoryDatabase, + importValues.add( + ImportValuePayloadPB.create() + ..name = name + ..data = utf8.encode(data) + ..viewLayout = ViewLayoutPB.Grid + ..importType = ImportTypePB.HistoryDatabase, ); - result.onFailure((error) { - showSnackBarMessage(context, error.msg); - Log.error('Failed to import history database $error'); - }); break; case ImportType.databaseRawData: - final result = await ImportBackendService.importData( - utf8.encode(data), - name, - parentViewId, - ImportTypePB.RawDatabase, + importValues.add( + ImportValuePayloadPB.create() + ..name = name + ..data = utf8.encode(data) + ..viewLayout = ViewLayoutPB.Grid + ..importType = ImportTypePB.RawDatabase, ); - result.onFailure((error) { - showSnackBarMessage(context, error.msg); - Log.error('Failed to import database raw data $error'); - }); break; case ImportType.databaseCSV: - final result = await ImportBackendService.importData( - utf8.encode(data), - name, - parentViewId, - ImportTypePB.CSV, + importValues.add( + ImportValuePayloadPB.create() + ..name = name + ..data = utf8.encode(data) + ..viewLayout = ViewLayoutPB.Grid + ..importType = ImportTypePB.CSV, ); - result.onFailure((error) { - showSnackBarMessage(context, error.msg); - Log.error('Failed to import CSV $error'); - }); break; default: assert(false, 'Unsupported Type $importType'); } } + await ImportBackendService.importPages( + parentViewId, + importValues, + ); + showLoading.value = false; widget.importCallback(importType, '', null); } diff --git a/frontend/rust-lib/event-integration-test/src/folder_event.rs b/frontend/rust-lib/event-integration-test/src/folder_event.rs index be218fa89d..4c07a19862 100644 --- a/frontend/rust-lib/event-integration-test/src/folder_event.rs +++ b/frontend/rust-lib/event-integration-test/src/folder_event.rs @@ -259,13 +259,14 @@ impl EventIntegrationTest { .parse::() } - pub async fn import_data(&self, data: ImportPB) -> ViewPB { + pub async fn import_data(&self, data: ImportPayloadPB) -> Vec { EventBuilder::new(self.clone()) .event(FolderEvent::ImportData) .payload(data) .async_send() .await - .parse::() + .parse::() + .items } pub async fn get_view_ancestors(&self, view_id: &str) -> Vec { diff --git a/frontend/rust-lib/event-integration-test/tests/folder/local_test/import_test.rs b/frontend/rust-lib/event-integration-test/tests/folder/local_test/import_test.rs index a93a232921..995be5bb89 100644 --- a/frontend/rust-lib/event-integration-test/tests/folder/local_test/import_test.rs +++ b/frontend/rust-lib/event-integration-test/tests/folder/local_test/import_test.rs @@ -1,7 +1,7 @@ use crate::util::unzip; use event_integration_test::EventIntegrationTest; use flowy_core::DEFAULT_NAME; -use flowy_folder::entities::{ImportPB, ImportTypePB, ViewLayoutPB}; +use flowy_folder::entities::{ImportPayloadPB, ImportTypePB, ImportValuePayloadPB, ViewLayoutPB}; #[tokio::test] async fn import_492_row_csv_file_test() { @@ -16,8 +16,9 @@ async fn import_492_row_csv_file_test() { let workspace_id = test.get_current_workspace().await.id; let import_data = gen_import_data(file_name, csv_string, workspace_id); - let view = test.import_data(import_data).await; - let database = test.get_database(&view.id).await; + let views = test.import_data(import_data).await; + let view_id = views[0].clone().id; + let database = test.get_database(&view_id).await; assert_eq!(database.rows.len(), 492); drop(cleaner); } @@ -35,21 +36,24 @@ async fn import_10240_row_csv_file_test() { let workspace_id = test.get_current_workspace().await.id; let import_data = gen_import_data(file_name, csv_string, workspace_id); - let view = test.import_data(import_data).await; - let database = test.get_database(&view.id).await; + let views = test.import_data(import_data).await; + let view_id = views[0].clone().id; + let database = test.get_database(&view_id).await; assert_eq!(database.rows.len(), 10240); drop(cleaner); } -fn gen_import_data(file_name: String, csv_string: String, workspace_id: String) -> ImportPB { - let import_data = ImportPB { +fn gen_import_data(file_name: String, csv_string: String, workspace_id: String) -> ImportPayloadPB { + ImportPayloadPB { parent_view_id: workspace_id.clone(), - name: file_name, - data: Some(csv_string.as_bytes().to_vec()), - file_path: None, - view_layout: ViewLayoutPB::Grid, - import_type: ImportTypePB::CSV, - }; - import_data + sync_after_create: false, + values: vec![ImportValuePayloadPB { + name: file_name, + data: Some(csv_string.as_bytes().to_vec()), + file_path: None, + view_layout: ViewLayoutPB::Grid, + import_type: ImportTypePB::CSV, + }], + } } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index a195faf3b0..e1f53a55e9 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -1,4 +1,5 @@ use bytes::Bytes; +use collab_entity::EncodedCollab; use collab_integrate::collab_builder::AppFlowyCollabBuilder; use collab_integrate::CollabKVDB; use flowy_chat::chat_manager::ChatManager; @@ -229,15 +230,15 @@ impl FolderOperationHandler for DocumentFolderOperation { _name: &str, _import_type: ImportType, bytes: Vec, - ) -> FutureResult<(), FlowyError> { + ) -> FutureResult { let view_id = view_id.to_string(); let manager = self.0.clone(); FutureResult::new(async move { let data = DocumentDataPB::try_from(Bytes::from(bytes))?; - manager + let encoded_collab = manager .create_document(uid, &view_id, Some(data.into())) .await?; - Ok(()) + Ok(encoded_collab) }) } @@ -392,7 +393,7 @@ impl FolderOperationHandler for DatabaseFolderOperation { _name: &str, import_type: ImportType, bytes: Vec, - ) -> FutureResult<(), FlowyError> { + ) -> FutureResult { let database_manager = self.0.clone(); let view_id = view_id.to_string(); let format = match import_type { @@ -406,11 +407,10 @@ impl FolderOperationHandler for DatabaseFolderOperation { String::from_utf8(bytes).map_err(|err| FlowyError::internal().with_context(err)) }) .await??; - - database_manager + let result = database_manager .import_csv(view_id, content, format) .await?; - Ok(()) + Ok(result.encoded_collab) }) } @@ -531,7 +531,7 @@ impl FolderOperationHandler for ChatFolderOperation { _name: &str, _import_type: ImportType, _bytes: Vec, - ) -> FutureResult<(), FlowyError> { + ) -> FutureResult { FutureResult::new(async move { Err(FlowyError::not_support()) }) } diff --git a/frontend/rust-lib/flowy-database2/src/manager.rs b/frontend/rust-lib/flowy-database2/src/manager.rs index 06ca2753da..58ccec904d 100644 --- a/frontend/rust-lib/flowy-database2/src/manager.rs +++ b/frontend/rust-lib/flowy-database2/src/manager.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::sync::{Arc, Weak}; use collab::core::collab::{DataSource, MutexCollab}; -use collab_database::database::DatabaseData; +use collab_database::database::{DatabaseData, MutexDatabase}; use collab_database::error::DatabaseError; use collab_database::rows::RowId; use collab_database::views::{CreateDatabaseParams, CreateViewParams, DatabaseLayout}; @@ -309,10 +309,13 @@ impl DatabaseManager { Ok(()) } - pub async fn create_database_with_params(&self, params: CreateDatabaseParams) -> FlowyResult<()> { + pub async fn create_database_with_params( + &self, + params: CreateDatabaseParams, + ) -> FlowyResult> { let wdb = self.get_database_indexer().await?; - let _ = wdb.create_database(params)?; - Ok(()) + let database = wdb.create_database(params)?; + Ok(database) } /// A linked view is a view that is linked to existing database. @@ -362,11 +365,19 @@ impl DatabaseManager { return Err(FlowyError::internal().with_context("The number of rows exceeds the limit")); } + let view_id = params.inline_view_id.clone(); + let database_id = params.database_id.clone(); + let database = self.create_database_with_params(params).await?; + let encoded_collab = database + .lock() + .get_collab() + .lock() + .encode_collab_v1(|collab| CollabType::Database.validate_require_data(collab))?; let result = ImportResult { - database_id: params.database_id.clone(), - view_id: params.inline_view_id.clone(), + database_id, + view_id, + encoded_collab, }; - self.create_database_with_params(params).await?; Ok(result) } diff --git a/frontend/rust-lib/flowy-database2/src/services/share/csv/import.rs b/frontend/rust-lib/flowy-database2/src/services/share/csv/import.rs index dd1f0c1f6b..531401ea87 100644 --- a/frontend/rust-lib/flowy-database2/src/services/share/csv/import.rs +++ b/frontend/rust-lib/flowy-database2/src/services/share/csv/import.rs @@ -5,6 +5,7 @@ use collab_database::fields::Field; use collab_database::rows::{new_cell_builder, Cell, CreateRowParams}; use collab_database::views::{CreateDatabaseParams, CreateViewParams, DatabaseLayout}; +use collab_entity::EncodedCollab; use flowy_error::{FlowyError, FlowyResult}; use crate::entities::FieldType; @@ -166,6 +167,7 @@ impl FieldsRows { pub struct ImportResult { pub database_id: String, pub view_id: String, + pub encoded_collab: EncodedCollab, } #[cfg(test)] diff --git a/frontend/rust-lib/flowy-document/src/manager.rs b/frontend/rust-lib/flowy-document/src/manager.rs index 5511a61725..b83afdfb21 100644 --- a/frontend/rust-lib/flowy-document/src/manager.rs +++ b/frontend/rust-lib/flowy-document/src/manager.rs @@ -110,25 +110,30 @@ impl DocumentManager { uid: i64, doc_id: &str, data: Option, - ) -> FlowyResult<()> { + ) -> FlowyResult { if self.is_doc_exist(doc_id).await.unwrap_or(false) { Err(FlowyError::new( ErrorCode::RecordAlreadyExists, format!("document {} already exists", doc_id), )) } else { - let doc_state = doc_state_from_document_data( + let encoded_collab = doc_state_from_document_data( doc_id, data.unwrap_or_else(|| default_document_data(doc_id)), ) - .await? - .doc_state - .to_vec(); + .await?; + let doc_state = encoded_collab.doc_state.to_vec(); let collab = self - .collab_for_document(uid, doc_id, DataSource::DocStateV1(doc_state), false) + .collab_for_document( + uid, + doc_id, + DataSource::DocStateV1(doc_state.clone()), + false, + ) .await?; collab.lock().flush(); - Ok(()) + + Ok(encoded_collab) } } diff --git a/frontend/rust-lib/flowy-folder/src/entities/import.rs b/frontend/rust-lib/flowy-folder/src/entities/import.rs index 363ad2b2c2..b2982fcd5f 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/import.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/import.rs @@ -1,6 +1,7 @@ use crate::entities::parser::empty_str::NotEmptyStr; use crate::entities::ViewLayoutPB; -use crate::share::{ImportParams, ImportType}; +use crate::share::{ImportParams, ImportType, ImportValue}; +use collab_entity::CollabType; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::FlowyError; @@ -23,6 +24,17 @@ impl From for ImportType { } } +impl From for CollabType { + fn from(import_type: ImportType) -> Self { + match import_type { + ImportType::HistoryDocument => CollabType::Document, + ImportType::HistoryDatabase => CollabType::Database, + ImportType::RawDatabase => CollabType::Database, + ImportType::CSV => CollabType::Database, + } + } +} + impl Default for ImportTypePB { fn default() -> Self { Self::HistoryDocument @@ -30,27 +42,43 @@ impl Default for ImportTypePB { } #[derive(Clone, Debug, ProtoBuf, Default)] -pub struct ImportPB { +pub struct ImportValuePayloadPB { + // the name of the import page + #[pb(index = 1)] + pub name: String, + + // the data of the import page + // if the data is empty, the file_path must be provided + #[pb(index = 2, one_of)] + pub data: Option>, + + // the file path of the import page + // if the file_path is empty, the data must be provided + #[pb(index = 3, one_of)] + pub file_path: Option, + + // the layout of the import page + #[pb(index = 4)] + pub view_layout: ViewLayoutPB, + + // the type of the import page + #[pb(index = 5)] + pub import_type: ImportTypePB, +} + +#[derive(Clone, Debug, ProtoBuf, Default)] +pub struct ImportPayloadPB { #[pb(index = 1)] pub parent_view_id: String, #[pb(index = 2)] - pub name: String, + pub values: Vec, - #[pb(index = 3, one_of)] - pub data: Option>, - - #[pb(index = 4, one_of)] - pub file_path: Option, - - #[pb(index = 5)] - pub view_layout: ViewLayoutPB, - - #[pb(index = 6)] - pub import_type: ImportTypePB, + #[pb(index = 3)] + pub sync_after_create: bool, } -impl TryInto for ImportPB { +impl TryInto for ImportPayloadPB { type Error = FlowyError; fn try_into(self) -> Result { @@ -58,28 +86,39 @@ impl TryInto for ImportPB { .map_err(|_| FlowyError::invalid_view_id())? .0; - let name = if self.name.is_empty() { - "Untitled".to_string() - } else { - self.name - }; + let mut values = Vec::new(); - let file_path = match self.file_path { - None => None, - Some(file_path) => Some( - NotEmptyStr::parse(file_path) - .map_err(|_| FlowyError::invalid_data().with_context("The import file path is empty"))? - .0, - ), - }; + for value in self.values { + let name = if value.name.is_empty() { + "Untitled".to_string() + } else { + value.name + }; + + let file_path = match value.file_path { + None => None, + Some(file_path) => Some( + NotEmptyStr::parse(file_path) + .map_err(|_| FlowyError::invalid_data().with_context("The import file path is empty"))? + .0, + ), + }; + + let params = ImportValue { + name, + data: value.data, + file_path, + view_layout: value.view_layout.into(), + import_type: value.import_type.into(), + }; + + values.push(params); + } Ok(ImportParams { parent_view_id, - name, - data: self.data, - file_path, - view_layout: self.view_layout.into(), - import_type: self.import_type.into(), + values, + sync_after_create: self.sync_after_create, }) } } diff --git a/frontend/rust-lib/flowy-folder/src/event_handler.rs b/frontend/rust-lib/flowy-folder/src/event_handler.rs index 03b71fd2a9..c22fdeacca 100644 --- a/frontend/rust-lib/flowy-folder/src/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/event_handler.rs @@ -363,14 +363,13 @@ pub(crate) async fn delete_my_trash_handler( #[tracing::instrument(level = "debug", skip(data, folder), err)] pub(crate) async fn import_data_handler( - data: AFPluginData, + data: AFPluginData, folder: AFPluginState>, -) -> DataResult { +) -> DataResult { let folder = upgrade_folder(folder)?; let params: ImportParams = data.into_inner().try_into()?; - let view = folder.import(params).await?; - let view_pb = view_pb_without_child_views(view); - data_result_ok(view_pb) + let views = folder.import(params).await?; + data_result_ok(views) } #[tracing::instrument(level = "debug", skip(folder), err)] diff --git a/frontend/rust-lib/flowy-folder/src/event_map.rs b/frontend/rust-lib/flowy-folder/src/event_map.rs index aa8bf551a4..a09c304ec8 100644 --- a/frontend/rust-lib/flowy-folder/src/event_map.rs +++ b/frontend/rust-lib/flowy-folder/src/event_map.rs @@ -132,7 +132,7 @@ pub enum FolderEvent { #[event()] PermanentlyDeleteAllTrashItem = 27, - #[event(input = "ImportPB", output = "ViewPB")] + #[event(input = "ImportPayloadPB", output = "RepeatedViewPB")] ImportData = 30, #[event(input = "WorkspaceIdPB", output = "RepeatedFolderSnapshotPB")] diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 4b9520eda0..6ebf619689 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -12,13 +12,13 @@ use crate::manager_observer::{ use crate::notification::{ send_notification, send_workspace_setting_notification, FolderNotification, }; -use crate::share::ImportParams; +use crate::share::{ImportParams, ImportValue}; use crate::util::{ folder_not_init_error, insert_parent_child_views, workspace_data_not_sync_error, }; use crate::view_operation::{create_view, FolderOperationHandler, FolderOperationHandlers}; use collab::core::collab::{DataSource, MutexCollab}; -use collab_entity::CollabType; +use collab_entity::{CollabType, EncodedCollab}; use collab_folder::error::FolderError; use collab_folder::{ Folder, FolderNotify, Section, SectionItem, TrashInfo, UserId, View, ViewLayout, ViewUpdate, @@ -26,8 +26,8 @@ use collab_folder::{ }; use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig}; use collab_integrate::CollabKVDB; -use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService}; +use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; +use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService, FolderCollabParams}; use flowy_folder_pub::folder_builder::ParentChildViews; use flowy_search_pub::entities::FolderIndexManager; use flowy_sqlite::kv::KVStorePreferences; @@ -1035,38 +1035,50 @@ impl FolderManager { Ok(()) } - pub(crate) async fn import(&self, import_data: ImportParams) -> FlowyResult { - let workspace_id = self.user.workspace_id()?; + /// Imports a single file to the folder and returns the encoded collab for immediate cloud sync. + pub(crate) async fn import_single_file( + &self, + parent_view_id: String, + import_data: ImportValue, + ) -> FlowyResult<(View, Option)> { + // Ensure either data or file_path is provided if import_data.data.is_none() && import_data.file_path.is_none() { return Err(FlowyError::new( ErrorCode::InvalidParams, - "data or file_path is required", + "Either data or file_path is required", )); } let handler = self.get_handler(&import_data.view_layout)?; let view_id = gen_view_id().to_string(); let uid = self.user.user_id()?; + let mut encoded_collab: Option = None; + + // Import data from bytes if available if let Some(data) = import_data.data { - handler - .import_from_bytes( - uid, - &view_id, - &import_data.name, - import_data.import_type, - data, - ) - .await?; + encoded_collab = Some( + handler + .import_from_bytes( + uid, + &view_id, + &import_data.name, + import_data.import_type, + data, + ) + .await?, + ); } + // Import data from file path if available if let Some(file_path) = import_data.file_path { + // TODO(Lucas): return the collab handler .import_from_file_path(&view_id, &import_data.name, file_path) .await?; } let params = CreateViewParams { - parent_view_id: import_data.parent_view_id, + parent_view_id, name: import_data.name, desc: "".to_string(), layout: import_data.view_layout.clone().into(), @@ -1081,18 +1093,75 @@ impl FolderManager { }; let view = create_view(self.user.user_id()?, params, import_data.view_layout); + + // Insert the new view into the folder self.with_folder( || (), |folder| { folder.insert_view(view.clone(), None); }, ); + + Ok((view, encoded_collab)) + } + + /// Import function to handle the import of data. + pub(crate) async fn import(&self, import_data: ImportParams) -> FlowyResult { + let workspace_id = self.user.workspace_id()?; + + // Initialize an empty vector to store the objects + let sync_after_create = import_data.sync_after_create; + let mut objects = vec![]; + let mut views = vec![]; + + // Iterate over the values in the import data + for data in import_data.values { + let collab_type = data.import_type.clone().into(); + + // Import a single file and get the view and encoded collab data + let (view, encoded_collab) = self + .import_single_file(import_data.parent_view_id.clone(), data) + .await?; + let object_id = view.id.clone(); + + views.push(view_pb_without_child_views(view)); + + if sync_after_create { + if let Some(encoded_collab) = encoded_collab { + // Try to encode the collaboration data to bytes + let encode_collab_v1 = encoded_collab.encode_to_bytes().map_err(internal_error); + + // If the view can't be encoded, skip it and don't block the whole import process + match encode_collab_v1 { + Ok(encode_collab_v1) => objects.push(FolderCollabParams { + object_id, + encoded_collab_v1: encode_collab_v1, + collab_type, + }), + Err(e) => { + error!("import error {}", e) + }, + } + } + } + } + + // Sync the view to the cloud + if sync_after_create { + self + .cloud_service + .batch_create_folder_collab_objects(&workspace_id, objects) + .await?; + } + + // Notify that the parent view has changed notify_parent_view_did_change( &workspace_id, self.mutex_folder.clone(), - vec![view.parent_view_id.clone()], + vec![import_data.parent_view_id], ); - Ok(view) + + Ok(RepeatedViewPB { items: views }) } /// Update the view with the provided view_id using the specified function. diff --git a/frontend/rust-lib/flowy-folder/src/share/import.rs b/frontend/rust-lib/flowy-folder/src/share/import.rs index 531461a232..c94edfa528 100644 --- a/frontend/rust-lib/flowy-folder/src/share/import.rs +++ b/frontend/rust-lib/flowy-folder/src/share/import.rs @@ -9,11 +9,17 @@ pub enum ImportType { } #[derive(Clone, Debug)] -pub struct ImportParams { - pub parent_view_id: String, +pub struct ImportValue { pub name: String, pub data: Option>, pub file_path: Option, pub view_layout: ViewLayout, pub import_type: ImportType, } + +#[derive(Clone, Debug)] +pub struct ImportParams { + pub parent_view_id: String, + pub values: Vec, + pub sync_after_create: bool, +} diff --git a/frontend/rust-lib/flowy-folder/src/view_operation.rs b/frontend/rust-lib/flowy-folder/src/view_operation.rs index 43aede739f..969092c58b 100644 --- a/frontend/rust-lib/flowy-folder/src/view_operation.rs +++ b/frontend/rust-lib/flowy-folder/src/view_operation.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use bytes::Bytes; +use collab_entity::EncodedCollab; pub use collab_folder::View; use collab_folder::ViewLayout; use tokio::sync::RwLock; @@ -78,6 +79,8 @@ pub trait FolderOperationHandler { ) -> FutureResult<(), FlowyError>; /// Create a view by importing data + /// + /// The return value fn import_from_bytes( &self, uid: i64, @@ -85,7 +88,7 @@ pub trait FolderOperationHandler { name: &str, import_type: ImportType, bytes: Vec, - ) -> FutureResult<(), FlowyError>; + ) -> FutureResult; /// Create a view by importing data from a file fn import_from_file_path( From 46896b5a2b52d594eb26ed6c3ec6c9c79ca6ddcf Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Mon, 1 Jul 2024 22:49:24 +0800 Subject: [PATCH 06/12] chore: remove appflowy_web project (#5671) * chore: remove appflowy_web project * chore: remove ci --- .github/workflows/web_ci.yaml | 83 - frontend/Makefile.toml | 1 - frontend/appflowy_tauri/src-tauri/Cargo.lock | 7 + frontend/appflowy_web/.eslintignore | 7 - frontend/appflowy_web/.eslintrc.cjs | 73 - frontend/appflowy_web/.gitignore | 29 - frontend/appflowy_web/.prettierignore | 19 - frontend/appflowy_web/.prettierrc.cjs | 20 - frontend/appflowy_web/README.md | 45 - frontend/appflowy_web/index.html | 13 - frontend/appflowy_web/package.json | 41 - frontend/appflowy_web/pnpm-lock.yaml | 2133 ------- frontend/appflowy_web/public/vite.svg | 1 - frontend/appflowy_web/src/@types/global.d.ts | 15 - frontend/appflowy_web/src/App.css | 42 - frontend/appflowy_web/src/App.tsx | 58 - frontend/appflowy_web/src/application/app.ts | 35 - .../appflowy_web/src/application/event_bus.ts | 34 - .../src/application/notification.ts | 17 - frontend/appflowy_web/src/assets/react.svg | 1 - frontend/appflowy_web/src/index.css | 68 - frontend/appflowy_web/src/main.tsx | 10 - .../src/services/backend/index.ts | 5 - frontend/appflowy_web/src/vite-env.d.ts | 1 - frontend/appflowy_web/tsconfig.json | 31 - frontend/appflowy_web/tsconfig.node.json | 10 - frontend/appflowy_web/vite.config.ts | 15 - frontend/appflowy_web/wasm-libs/Cargo.lock | 5283 ----------------- frontend/appflowy_web/wasm-libs/Cargo.toml | 76 - .../wasm-libs/af-persistence/Cargo.toml | 20 - .../wasm-libs/af-persistence/src/error.rs | 30 - .../wasm-libs/af-persistence/src/lib.rs | 2 - .../wasm-libs/af-persistence/src/store.rs | 192 - .../appflowy_web/wasm-libs/af-user/Cargo.toml | 28 - .../appflowy_web/wasm-libs/af-user/Flowy.toml | 3 - .../appflowy_web/wasm-libs/af-user/build.rs | 17 - .../af-user/src/authenticate_user.rs | 20 - .../wasm-libs/af-user/src/define.rs | 9 - .../wasm-libs/af-user/src/entities/auth.rs | 68 - .../wasm-libs/af-user/src/entities/mod.rs | 5 - .../wasm-libs/af-user/src/entities/user.rs | 73 - .../wasm-libs/af-user/src/event_handler.rs | 48 - .../wasm-libs/af-user/src/event_map.rs | 29 - .../appflowy_web/wasm-libs/af-user/src/lib.rs | 7 - .../wasm-libs/af-user/src/manager.rs | 205 - .../wasm-libs/af-user/src/protobuf/auth.rs | 689 --- .../af-user/src/protobuf/event_map.rs | 95 - .../wasm-libs/af-user/src/protobuf/mod.rs | 12 - .../wasm-libs/af-user/src/protobuf/user.rs | 661 --- .../appflowy_web/wasm-libs/af-wasm/Cargo.toml | 58 - .../wasm-libs/af-wasm/src/core.rs | 89 - .../af-wasm/src/deps_resolve/document_deps.rs | 19 - .../af-wasm/src/deps_resolve/folder_deps.rs | 20 - .../wasm-libs/af-wasm/src/deps_resolve/mod.rs | 2 - .../wasm-libs/af-wasm/src/integrate/mod.rs | 1 - .../wasm-libs/af-wasm/src/integrate/server.rs | 126 - .../appflowy_web/wasm-libs/af-wasm/src/lib.rs | 170 - .../wasm-libs/af-wasm/src/notification.rs | 19 - .../wasm-libs/af-wasm/tests/main.rs | 4 - .../af-wasm/tests/user/event_test.rs | 10 - .../wasm-libs/af-wasm/tests/user/mod.rs | 1 - .../af-wasm/tests/util/event_builder.rs | 132 - .../wasm-libs/af-wasm/tests/util/mod.rs | 2 - .../wasm-libs/af-wasm/tests/util/tester.rs | 105 - .../wasm-libs/rust-toolchain.toml | 2 - frontend/appflowy_web/wasm-libs/rustfmt.toml | 12 - .../build-tool/flowy-codegen/src/lib.rs | 11 - frontend/scripts/makefile/web.toml | 10 - .../scripts/tool/update_client_api_rev.sh | 2 +- frontend/scripts/tool/update_collab_rev.sh | 2 +- 70 files changed, 9 insertions(+), 11174 deletions(-) delete mode 100644 .github/workflows/web_ci.yaml delete mode 100644 frontend/appflowy_web/.eslintignore delete mode 100644 frontend/appflowy_web/.eslintrc.cjs delete mode 100644 frontend/appflowy_web/.gitignore delete mode 100644 frontend/appflowy_web/.prettierignore delete mode 100644 frontend/appflowy_web/.prettierrc.cjs delete mode 100644 frontend/appflowy_web/README.md delete mode 100644 frontend/appflowy_web/index.html delete mode 100644 frontend/appflowy_web/package.json delete mode 100644 frontend/appflowy_web/pnpm-lock.yaml delete mode 100644 frontend/appflowy_web/public/vite.svg delete mode 100644 frontend/appflowy_web/src/@types/global.d.ts delete mode 100644 frontend/appflowy_web/src/App.css delete mode 100644 frontend/appflowy_web/src/App.tsx delete mode 100644 frontend/appflowy_web/src/application/app.ts delete mode 100644 frontend/appflowy_web/src/application/event_bus.ts delete mode 100644 frontend/appflowy_web/src/application/notification.ts delete mode 100644 frontend/appflowy_web/src/assets/react.svg delete mode 100644 frontend/appflowy_web/src/index.css delete mode 100644 frontend/appflowy_web/src/main.tsx delete mode 100644 frontend/appflowy_web/src/services/backend/index.ts delete mode 100644 frontend/appflowy_web/src/vite-env.d.ts delete mode 100644 frontend/appflowy_web/tsconfig.json delete mode 100644 frontend/appflowy_web/tsconfig.node.json delete mode 100644 frontend/appflowy_web/vite.config.ts delete mode 100644 frontend/appflowy_web/wasm-libs/Cargo.lock delete mode 100644 frontend/appflowy_web/wasm-libs/Cargo.toml delete mode 100644 frontend/appflowy_web/wasm-libs/af-persistence/Cargo.toml delete mode 100644 frontend/appflowy_web/wasm-libs/af-persistence/src/error.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-persistence/src/lib.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-persistence/src/store.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/Cargo.toml delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/Flowy.toml delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/build.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/authenticate_user.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/define.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/entities/auth.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/entities/mod.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/entities/user.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/event_handler.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/event_map.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/lib.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/manager.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/protobuf/auth.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/protobuf/event_map.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/protobuf/mod.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-user/src/protobuf/user.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/Cargo.toml delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/core.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/document_deps.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/folder_deps.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/mod.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/mod.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/server.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/lib.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/src/notification.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/tests/main.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/tests/user/event_test.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/tests/user/mod.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/tests/util/event_builder.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/tests/util/mod.rs delete mode 100644 frontend/appflowy_web/wasm-libs/af-wasm/tests/util/tester.rs delete mode 100644 frontend/appflowy_web/wasm-libs/rust-toolchain.toml delete mode 100644 frontend/appflowy_web/wasm-libs/rustfmt.toml diff --git a/.github/workflows/web_ci.yaml b/.github/workflows/web_ci.yaml deleted file mode 100644 index 9c568e1916..0000000000 --- a/.github/workflows/web_ci.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: WEB-CI - -on: - workflow_dispatch: - inputs: - build: - description: 'Build the web app' - required: true - default: 'true' - -env: - CARGO_TERM_COLOR: always - NODE_VERSION: "18.16.0" - PNPM_VERSION: "8.5.0" - RUST_TOOLCHAIN: "1.77.2" - CARGO_MAKE_VERSION: "0.36.6" - -jobs: - web-build: - if: github.event.pull_request.draft != true - strategy: - fail-fast: false - matrix: - platform: [ ubuntu-latest ] - - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v4 - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Cache Rust Dependencies - uses: Swatinem/rust-cache@v2 - with: - key: rust-dependencies-${{ runner.os }} - workspaces: | - frontend/rust-lib - frontend/appflowy_web/appflowy_wasm - - # TODO: Can combine caching deps and node_modules in one - # See Glob patterns: https://github.com/actions/toolkit/tree/main/packages/glob - - name: Cache Node.js dependencies - uses: actions/cache@v4 - with: - path: ~/.npm - key: npm-${{ runner.os }} - - - name: Cache node_modules - uses: actions/cache@v4 - with: - path: frontend/appflowy_web/node_modules - key: node-modules-${{ runner.os }} - - - name: Install Rust toolchain - id: rust_toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.RUST_TOOLCHAIN }} - override: true - profile: minimal - - - name: Install wasm-pack - run: cargo install wasm-pack - - - uses: taiki-e/install-action@v2 - with: - tool: cargo-make@${{ env.CARGO_MAKE_VERSION }} - - - name: install dependencies - if: matrix.platform == 'ubuntu-latest' - working-directory: frontend - run: | - sudo apt-get update - npm install -g pnpm@${{ env.PNPM_VERSION }} - cargo make install_web_protobuf - - - name: Build - working-directory: frontend/appflowy_web - run: | - pnpm install - pnpm run build_release_wasm diff --git a/frontend/Makefile.toml b/frontend/Makefile.toml index d214c6c604..49871b75bd 100644 --- a/frontend/Makefile.toml +++ b/frontend/Makefile.toml @@ -50,7 +50,6 @@ APP_ENVIRONMENT = "local" FLUTTER_FLOWY_SDK_PATH = "appflowy_flutter/packages/appflowy_backend" TAURI_BACKEND_SERVICE_PATH = "appflowy_tauri/src/services/backend" WEB_BACKEND_SERVICE_PATH = "appflowy_web/src/services/backend" -WEB_LIB_PATH = "appflowy_web/wasm-libs/af-wasm" TAURI_APP_BACKEND_SERVICE_PATH = "appflowy_web_app/src/application/services/tauri-services/backend" # Test default config TEST_CRATE_TYPE = "cdylib" diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index e85feb9663..477d103909 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -1846,6 +1846,7 @@ name = "flowy-chat" version = "0.1.0" dependencies = [ "allo-isolate", + "anyhow", "bytes", "dashmap", "flowy-chat-pub", @@ -1859,9 +1860,13 @@ dependencies = [ "lib-dispatch", "lib-infra", "log", + "parking_lot 0.12.1", "protobuf", + "serde", + "serde_json", "strum_macros 0.21.1", "tokio", + "tokio-stream", "tracing", "uuid", "validator", @@ -2131,6 +2136,7 @@ dependencies = [ "fancy-regex 0.11.0", "flowy-codegen", "flowy-derive", + "flowy-sidecar", "flowy-sqlite", "lib-dispatch", "protobuf", @@ -2446,6 +2452,7 @@ dependencies = [ "anyhow", "base64 0.21.5", "chrono", + "client-api", "collab", "collab-entity", "flowy-error", diff --git a/frontend/appflowy_web/.eslintignore b/frontend/appflowy_web/.eslintignore deleted file mode 100644 index e0ff674834..0000000000 --- a/frontend/appflowy_web/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -src/services -src/styles -node_modules/ -dist/ -src-tauri/ -.eslintrc.cjs -tsconfig.json \ No newline at end of file diff --git a/frontend/appflowy_web/.eslintrc.cjs b/frontend/appflowy_web/.eslintrc.cjs deleted file mode 100644 index a1160f0bd3..0000000000 --- a/frontend/appflowy_web/.eslintrc.cjs +++ /dev/null @@ -1,73 +0,0 @@ -module.exports = { - // https://eslint.org/docs/latest/use/configure/configuration-files - env: { - browser: true, - es6: true, - node: true, - }, - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], - parser: '@typescript-eslint/parser', - parserOptions: { - project: 'tsconfig.json', - sourceType: 'module', - tsconfigRootDir: __dirname, - extraFileExtensions: ['.json'], - }, - plugins: ['@typescript-eslint', "react-hooks"], - rules: { - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "error", - '@typescript-eslint/adjacent-overload-signatures': 'error', - '@typescript-eslint/no-empty-function': 'error', - '@typescript-eslint/no-empty-interface': 'error', - '@typescript-eslint/no-floating-promises': 'error', - '@typescript-eslint/await-thenable': 'error', - '@typescript-eslint/no-namespace': 'error', - '@typescript-eslint/no-unnecessary-type-assertion': 'error', - '@typescript-eslint/no-redeclare': 'error', - '@typescript-eslint/prefer-for-of': 'error', - '@typescript-eslint/triple-slash-reference': 'error', - '@typescript-eslint/unified-signatures': 'error', - 'no-shadow': 'off', - '@typescript-eslint/no-shadow': 'off', - 'constructor-super': 'error', - eqeqeq: ['error', 'always'], - 'no-cond-assign': 'error', - 'no-duplicate-case': 'error', - 'no-duplicate-imports': 'error', - 'no-empty': [ - 'error', - { - allowEmptyCatch: true, - }, - ], - 'no-invalid-this': 'error', - 'no-new-wrappers': 'error', - 'no-param-reassign': 'error', - 'no-sequences': 'error', - 'no-throw-literal': 'error', - 'no-unsafe-finally': 'error', - 'no-unused-labels': 'error', - 'no-var': 'error', - 'no-void': 'off', - 'prefer-const': 'error', - 'prefer-spread': 'off', - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_', - } - ], - 'padding-line-between-statements': [ - "error", - { blankLine: "always", prev: ["const", "let", "var"], next: "*"}, - { blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}, - { blankLine: "always", prev: "import", next: "*" }, - { blankLine: "any", prev: "import", next: "import" }, - { blankLine: "always", prev: "block-like", next: "*" }, - { blankLine: "always", prev: "block", next: "*" }, - - ] - }, - ignorePatterns: ['src/**/*.test.ts', '**/__tests__/**/*.json', 'package.json'] -}; diff --git a/frontend/appflowy_web/.gitignore b/frontend/appflowy_web/.gitignore deleted file mode 100644 index d347429756..0000000000 --- a/frontend/appflowy_web/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -wasm-libs/**/target -**/src/services/backend/models/ -**/src/services/backend/events/ -**/src/appflowy_app/i18n/translations/ diff --git a/frontend/appflowy_web/.prettierignore b/frontend/appflowy_web/.prettierignore deleted file mode 100644 index d515c1c2f2..0000000000 --- a/frontend/appflowy_web/.prettierignore +++ /dev/null @@ -1,19 +0,0 @@ -.DS_Store -node_modules -/build -/public -/.svelte-kit -/package -/.vscode -.env -.env.* -!.env.example - -# rust and generated ts code -/src-tauri -/src/services - -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/frontend/appflowy_web/.prettierrc.cjs b/frontend/appflowy_web/.prettierrc.cjs deleted file mode 100644 index f283db53a2..0000000000 --- a/frontend/appflowy_web/.prettierrc.cjs +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - arrowParens: 'always', - bracketSpacing: true, - endOfLine: 'lf', - htmlWhitespaceSensitivity: 'css', - insertPragma: false, - jsxBracketSameLine: false, - jsxSingleQuote: true, - printWidth: 121, - plugins: [require('prettier-plugin-tailwindcss')], - proseWrap: 'preserve', - quoteProps: 'as-needed', - requirePragma: false, - semi: true, - singleQuote: true, - tabWidth: 2, - trailingComma: 'es5', - useTabs: false, - vueIndentScriptAndStyle: false, -}; diff --git a/frontend/appflowy_web/README.md b/frontend/appflowy_web/README.md deleted file mode 100644 index b92a4c4960..0000000000 --- a/frontend/appflowy_web/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# AppFlowy Web Project - -## Installation - -```bash -cd appflowy-web - -# Install dependencies -rm -rf node_modules && pnpm install -``` - -## Running the app - -```bash -# development -pnpm run dev - -# production mode -pnpm run build - -# generate wasm -pnpm run wasm -``` - - - -## Run tests in Chrome - -> Before executing the test, you need to install the [Chrome Driver](https://chromedriver.chromium.org/downloads). If -> you are using a Mac, you can easily install it using Homebrew. -> -> ```shell -> brew install chromedriver -> ``` - - -Go to `frontend/appflowy_web/wasm-libs` and run: -```shell -wasm-pack test --chrome -``` - -Run tests in headless Chrome -```shell -wasm-pack test --headless --chrome -``` \ No newline at end of file diff --git a/frontend/appflowy_web/index.html b/frontend/appflowy_web/index.html deleted file mode 100644 index e4b78eae12..0000000000 --- a/frontend/appflowy_web/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + React + TS - - -

- - - diff --git a/frontend/appflowy_web/package.json b/frontend/appflowy_web/package.json deleted file mode 100644 index faafdba154..0000000000 --- a/frontend/appflowy_web/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "appflowy_web", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "build_release_wasm": "cd wasm-libs/af-wasm && wasm-pack build", - "build_dev_wasm": "cd wasm-libs/af-wasm && wasm-pack build --features=\"localhost_dev\"", - "dev": "pnpm run build_dev_wasm && vite", - "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "clean": "cargo make --cwd .. web_clean", - "test": "cargo test && wasm-pack test --headless", - "preview": "vite preview" - }, - "dependencies": { - "events": "^3.3.0", - "google-protobuf": "^3.21.2", - "protoc-gen-ts": "^0.8.5", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "ts-results": "^3.3.0", - "uuid": "^9.0.1" - }, - "devDependencies": { - "@types/events": "^3.0.3", - "@types/node": "^20.10.6", - "@types/react": "^18.2.43", - "@types/react-dom": "^18.2.17", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "@vitejs/plugin-react": "^4.2.1", - "eslint": "^8.55.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.5", - "typescript": "^5.2.2", - "vite": "^5.0.8", - "vite-plugin-wasm": "^3.3.0", - "rimraf": "^5.0.5" - } -} diff --git a/frontend/appflowy_web/pnpm-lock.yaml b/frontend/appflowy_web/pnpm-lock.yaml deleted file mode 100644 index 3c23a1ff65..0000000000 --- a/frontend/appflowy_web/pnpm-lock.yaml +++ /dev/null @@ -1,2133 +0,0 @@ -lockfileVersion: '6.0' - -dependencies: - events: - specifier: ^3.3.0 - version: 3.3.0 - google-protobuf: - specifier: ^3.21.2 - version: 3.21.2 - protoc-gen-ts: - specifier: ^0.8.5 - version: 0.8.7 - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - ts-results: - specifier: ^3.3.0 - version: 3.3.0 - uuid: - specifier: ^9.0.1 - version: 9.0.1 - -devDependencies: - '@types/events': - specifier: ^3.0.3 - version: 3.0.3 - '@types/node': - specifier: ^20.10.6 - version: 20.10.6 - '@types/react': - specifier: ^18.2.43 - version: 18.2.43 - '@types/react-dom': - specifier: ^18.2.17 - version: 18.2.17 - '@typescript-eslint/eslint-plugin': - specifier: ^6.14.0 - version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.2.2) - '@typescript-eslint/parser': - specifier: ^6.14.0 - version: 6.14.0(eslint@8.55.0)(typescript@5.2.2) - '@vitejs/plugin-react': - specifier: ^4.2.1 - version: 4.2.1(vite@5.0.8) - eslint: - specifier: ^8.55.0 - version: 8.55.0 - eslint-plugin-react-hooks: - specifier: ^4.6.0 - version: 4.6.0(eslint@8.55.0) - eslint-plugin-react-refresh: - specifier: ^0.4.5 - version: 0.4.5(eslint@8.55.0) - rimraf: - specifier: ^5.0.5 - version: 5.0.5 - typescript: - specifier: ^5.2.2 - version: 5.2.2 - vite: - specifier: ^5.0.8 - version: 5.0.8(@types/node@20.10.6) - vite-plugin-wasm: - specifier: ^3.3.0 - version: 3.3.0(vite@5.0.8) - -packages: - - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - dev: true - - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 - dev: true - - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 - dev: true - - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/core@7.23.7: - resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) - '@babel/helpers': 7.23.7 - '@babel/parser': 7.23.6 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 - convert-source-map: 2.0.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 - jsesc: 2.5.2 - dev: true - - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.2 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.6 - dev: true - - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - dev: true - - /@babel/helpers@7.23.7: - resolution: {integrity: sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - - /@babel/parser@7.23.6: - resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@babel/plugin-transform-react-jsx-self@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/plugin-transform-react-jsx-source@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - dev: true - - /@babel/template@7.22.15: - resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 - dev: true - - /@babel/traverse@7.23.7: - resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/types@7.23.6: - resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - dev: true - - /@esbuild/aix-ppc64@0.19.11: - resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm64@0.19.11: - resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.19.11: - resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.19.11: - resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.19.11: - resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.19.11: - resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.19.11: - resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.19.11: - resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.19.11: - resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.19.11: - resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.19.11: - resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.19.11: - resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.19.11: - resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.19.11: - resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.19.11: - resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.19.11: - resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.19.11: - resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.19.11: - resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.19.11: - resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.19.11: - resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.19.11: - resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.19.11: - resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.19.11: - resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@eslint-community/eslint-utils@4.4.0(eslint@8.55.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 - dependencies: - eslint: 8.55.0 - eslint-visitor-keys: 3.4.3 - dev: true - - /@eslint-community/regexpp@4.10.0: - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.0 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@eslint/js@8.55.0: - resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@humanwhocodes/config-array@0.11.13: - resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 2.0.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true - - /@humanwhocodes/object-schema@2.0.1: - resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} - dev: true - - /@isaacs/cliui@8.0.2: - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - dependencies: - string-width: 5.1.2 - string-width-cjs: /string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: /strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: true - - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.20 - dev: true - - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - - /@jridgewell/trace-mapping@0.3.20: - resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.16.0 - dev: true - - /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-android-arm-eabi@4.9.2: - resolution: {integrity: sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-android-arm64@4.9.2: - resolution: {integrity: sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg==} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-arm64@4.9.2: - resolution: {integrity: sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-darwin-x64@4.9.2: - resolution: {integrity: sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm-gnueabihf@4.9.2: - resolution: {integrity: sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ==} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-gnu@4.9.2: - resolution: {integrity: sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-arm64-musl@4.9.2: - resolution: {integrity: sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-riscv64-gnu@4.9.2: - resolution: {integrity: sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw==} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-gnu@4.9.2: - resolution: {integrity: sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-linux-x64-musl@4.9.2: - resolution: {integrity: sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-arm64-msvc@4.9.2: - resolution: {integrity: sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-ia32-msvc@4.9.2: - resolution: {integrity: sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ==} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rollup/rollup-win32-x64-msvc@4.9.2: - resolution: {integrity: sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@types/babel__core@7.20.5: - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 - '@types/babel__generator': 7.6.8 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.5 - dev: true - - /@types/babel__generator@7.6.8: - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 - dev: true - - /@types/babel__traverse@7.20.5: - resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} - dependencies: - '@babel/types': 7.23.6 - dev: true - - /@types/events@3.0.3: - resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} - dev: true - - /@types/json-schema@7.0.15: - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true - - /@types/node@20.10.6: - resolution: {integrity: sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==} - dependencies: - undici-types: 5.26.5 - dev: true - - /@types/prop-types@15.7.11: - resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} - dev: true - - /@types/react-dom@18.2.17: - resolution: {integrity: sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==} - dependencies: - '@types/react': 18.2.43 - dev: true - - /@types/react@18.2.43: - resolution: {integrity: sha512-nvOV01ZdBdd/KW6FahSbcNplt2jCJfyWdTos61RYHV+FVv5L/g9AOX1bmbVcWcLFL8+KHQfh1zVIQrud6ihyQA==} - dependencies: - '@types/prop-types': 15.7.11 - '@types/scheduler': 0.16.8 - csstype: 3.1.3 - dev: true - - /@types/scheduler@0.16.8: - resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} - dev: true - - /@types/semver@7.5.6: - resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} - dev: true - - /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.2.2): - resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.14.0 - debug: 4.3.4 - eslint: 8.55.0 - graphemer: 1.4.0 - ignore: 5.3.0 - natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) - typescript: 5.2.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.2.2): - resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.14.0 - debug: 4.3.4 - eslint: 8.55.0 - typescript: 5.2.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/scope-manager@6.14.0: - resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==} - engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/visitor-keys': 6.14.0 - dev: true - - /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.2.2): - resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.2.2) - debug: 4.3.4 - eslint: 8.55.0 - ts-api-utils: 1.0.3(typescript@5.2.2) - typescript: 5.2.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/types@6.14.0: - resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==} - engines: {node: ^16.0.0 || >=18.0.0} - dev: true - - /@typescript-eslint/typescript-estree@6.14.0(typescript@5.2.2): - resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/visitor-keys': 6.14.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) - typescript: 5.2.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.2.2): - resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.14.0 - '@typescript-eslint/types': 6.14.0 - '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.2.2) - eslint: 8.55.0 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /@typescript-eslint/visitor-keys@6.14.0: - resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==} - engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 6.14.0 - eslint-visitor-keys: 3.4.3 - dev: true - - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true - - /@vitejs/plugin-react@4.2.1(vite@5.0.8): - resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 - dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-transform-react-jsx-self': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-react-jsx-source': 7.23.3(@babel/core@7.23.7) - '@types/babel__core': 7.20.5 - react-refresh: 0.14.0 - vite: 5.0.8(@types/node@20.10.6) - transitivePeerDependencies: - - supports-color - dev: true - - /acorn-jsx@5.3.2(acorn@8.11.3): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.11.3 - dev: true - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - 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 - dev: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} - engines: {node: '>=12'} - dev: true - - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /browserslist@4.22.2: - resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001572 - electron-to-chromium: 1.4.620 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.22.2) - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /caniuse-lite@1.0.30001572: - resolution: {integrity: sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==} - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true - - /electron-to-chromium@1.4.620: - resolution: {integrity: sha512-a2fcSHOHrqBJsPNXtf6ZCEZpXrFCcbK1FBxfX3txoqWzNgtEDG1f3M59M98iwxhRW4iMKESnSjbJ310/rkrp0g==} - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - - /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true - - /esbuild@0.19.11: - resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.11 - '@esbuild/android-arm': 0.19.11 - '@esbuild/android-arm64': 0.19.11 - '@esbuild/android-x64': 0.19.11 - '@esbuild/darwin-arm64': 0.19.11 - '@esbuild/darwin-x64': 0.19.11 - '@esbuild/freebsd-arm64': 0.19.11 - '@esbuild/freebsd-x64': 0.19.11 - '@esbuild/linux-arm': 0.19.11 - '@esbuild/linux-arm64': 0.19.11 - '@esbuild/linux-ia32': 0.19.11 - '@esbuild/linux-loong64': 0.19.11 - '@esbuild/linux-mips64el': 0.19.11 - '@esbuild/linux-ppc64': 0.19.11 - '@esbuild/linux-riscv64': 0.19.11 - '@esbuild/linux-s390x': 0.19.11 - '@esbuild/linux-x64': 0.19.11 - '@esbuild/netbsd-x64': 0.19.11 - '@esbuild/openbsd-x64': 0.19.11 - '@esbuild/sunos-x64': 0.19.11 - '@esbuild/win32-arm64': 0.19.11 - '@esbuild/win32-ia32': 0.19.11 - '@esbuild/win32-x64': 0.19.11 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /eslint-plugin-react-hooks@4.6.0(eslint@8.55.0): - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - dependencies: - eslint: 8.55.0 - dev: true - - /eslint-plugin-react-refresh@0.4.5(eslint@8.55.0): - resolution: {integrity: sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==} - peerDependencies: - eslint: '>=7' - dependencies: - eslint: 8.55.0 - dev: true - - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - - /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} - dev: true - - /eslint@8.55.0: - resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.55.0 - '@humanwhocodes/config-array': 0.11.13 - '@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.24.0 - graphemer: 1.4.0 - ignore: 5.3.0 - 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.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 3.4.3 - dev: true - - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - dev: false - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - 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 - dev: true - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.16.0: - resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} - dependencies: - reusify: 1.0.4 - dev: true - - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.2.0 - dev: true - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: true - - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flatted: 3.2.9 - keyv: 4.5.4 - rimraf: 3.0.2 - dev: true - - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} - dev: true - - /foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} - engines: {node: '>=14'} - dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.1.0 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@10.3.10: - resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.3 - minipass: 7.0.4 - path-scurry: 1.10.1 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - 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 - dev: true - - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true - - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.0 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - - /google-protobuf@3.21.2: - resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==} - dev: false - - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /ignore@5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} - engines: {node: '>= 4'} - dev: true - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true - - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - dependencies: - json-buffer: 3.0.1 - dev: true - - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - dependencies: - js-tokens: 4.0.0 - dev: false - - /lru-cache@10.2.0: - resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} - engines: {node: 14 || >=16.14} - dev: true - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minipass@7.0.4: - resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} - engines: {node: '>=16 || 14 >=14.17'} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} - dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - dev: true - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - lru-cache: 10.2.0 - minipass: 7.0.4 - dev: true - - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /postcss@8.4.32: - resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.0.2 - dev: true - - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /protoc-gen-ts@0.8.7: - resolution: {integrity: sha512-jr4VJey2J9LVYCV7EVyVe53g1VMw28cCmYJhBe5e3YX5wiyiDwgxWxeDf9oTqAe4P1bN/YGAkW2jhlH8LohwiQ==} - hasBin: true - dev: false - - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true - - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - dev: false - - /react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} - engines: {node: '>=0.10.0'} - dev: true - - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - dependencies: - loose-envify: 1.4.0 - dev: false - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - - /rimraf@5.0.5: - resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} - engines: {node: '>=14'} - hasBin: true - dependencies: - glob: 10.3.10 - dev: true - - /rollup@4.9.2: - resolution: {integrity: sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.9.2 - '@rollup/rollup-android-arm64': 4.9.2 - '@rollup/rollup-darwin-arm64': 4.9.2 - '@rollup/rollup-darwin-x64': 4.9.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.9.2 - '@rollup/rollup-linux-arm64-gnu': 4.9.2 - '@rollup/rollup-linux-arm64-musl': 4.9.2 - '@rollup/rollup-linux-riscv64-gnu': 4.9.2 - '@rollup/rollup-linux-x64-gnu': 4.9.2 - '@rollup/rollup-linux-x64-musl': 4.9.2 - '@rollup/rollup-win32-arm64-msvc': 4.9.2 - '@rollup/rollup-win32-ia32-msvc': 4.9.2 - '@rollup/rollup-win32-x64-msvc': 4.9.2 - fsevents: 2.3.3 - dev: true - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - dependencies: - loose-envify: 1.4.0 - dev: false - - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true - - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - dev: true - - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true - - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - dev: true - - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - dependencies: - ansi-regex: 6.0.1 - dev: true - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - - /ts-api-utils@1.0.3(typescript@5.2.2): - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} - peerDependencies: - typescript: '>=4.2.0' - dependencies: - typescript: 5.2.2 - dev: true - - /ts-results@3.3.0: - resolution: {integrity: sha512-FWqxGX2NHp5oCyaMd96o2y2uMQmSu8Dey6kvyuFdRJ2AzfmWo3kWa4UsPlCGlfQ/qu03m09ZZtppMoY8EMHuiA==} - dev: false - - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - - /typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /update-browserslist-db@1.0.13(browserslist@4.22.2): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.22.2 - escalade: 3.1.1 - picocolors: 1.0.0 - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.1 - dev: true - - /uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - dev: false - - /vite-plugin-wasm@3.3.0(vite@5.0.8): - resolution: {integrity: sha512-tVhz6w+W9MVsOCHzxo6SSMSswCeIw4HTrXEi6qL3IRzATl83jl09JVO1djBqPSwfjgnpVHNLYcaMbaDX5WB/pg==} - peerDependencies: - vite: ^2 || ^3 || ^4 || ^5 - dependencies: - vite: 5.0.8(@types/node@20.10.6) - dev: true - - /vite@5.0.8(@types/node@20.10.6): - resolution: {integrity: sha512-jYMALd8aeqR3yS9xlHd0OzQJndS9fH5ylVgWdB+pxTwxLKdO1pgC5Dlb398BUxpfaBxa4M9oT7j1g503Gaj5IQ==} - 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: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 20.10.6 - esbuild: 0.19.11 - postcss: 8.4.32 - rollup: 4.9.2 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - dev: true - - /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true diff --git a/frontend/appflowy_web/public/vite.svg b/frontend/appflowy_web/public/vite.svg deleted file mode 100644 index e7b8dfb1b2..0000000000 --- a/frontend/appflowy_web/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/appflowy_web/src/@types/global.d.ts b/frontend/appflowy_web/src/@types/global.d.ts deleted file mode 100644 index 6b17142a09..0000000000 --- a/frontend/appflowy_web/src/@types/global.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface NotifyArgs { - source: string; - ty: number; - id: string; - payload?: Unit8Array; - error?: Unit8Array; -} - -declare global { - interface Window { - onFlowyNotify: (eventName: string, args: NotifyArgs) => void; - } -} - -export {}; diff --git a/frontend/appflowy_web/src/App.css b/frontend/appflowy_web/src/App.css deleted file mode 100644 index b9d355df2a..0000000000 --- a/frontend/appflowy_web/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/frontend/appflowy_web/src/App.tsx b/frontend/appflowy_web/src/App.tsx deleted file mode 100644 index 6acdc9a892..0000000000 --- a/frontend/appflowy_web/src/App.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import reactLogo from "./assets/react.svg"; -import viteLogo from "/vite.svg"; -import "./App.css"; -import { useEffect } from "react"; -import { initApp } from "@/application/app.ts"; -import { subscribeNotification } from "@/application/notification.ts"; -import { NotifyArgs } from "./@types/global"; -import { init_tracing_log, init_wasm_core } from "../wasm-libs/af-wasm/pkg"; -import { v4 as uuidv4 } from 'uuid'; -import {AddUserPB, UserWasmEventAddUser} from "@/services/backend/events/user"; - -init_tracing_log(); -// FIXME: handle the promise that init_wasm_core returns -init_wasm_core(); - -function App() { - useEffect(() => { - initApp(); - return subscribeNotification((event: NotifyArgs) => { - console.log(event); - }); - }, []); - - const handleClick = async () => { - let email = `${uuidv4()}@example.com`; - let password = "AppFlowy!2024"; - const payload = AddUserPB.fromObject({email: email, password: password }) - let result = await UserWasmEventAddUser(payload); - if (!result.ok) { - - } - }; - - return ( - <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- - ); -} - -export default App; diff --git a/frontend/appflowy_web/src/application/app.ts b/frontend/appflowy_web/src/application/app.ts deleted file mode 100644 index 918d5583b1..0000000000 --- a/frontend/appflowy_web/src/application/app.ts +++ /dev/null @@ -1,35 +0,0 @@ - - -import { initEventBus } from "./event_bus.ts"; -import {async_event, register_listener} from "../../wasm-libs/af-wasm/pkg"; - -export function initApp() { - initEventBus(); - register_listener(); -} - -type InvokeArgs = Record; - -export async function invoke(cmd: string, args?: InvokeArgs): Promise { - switch (cmd) { - case "invoke_request": - const request = args?.request as { ty?: unknown, payload?: unknown } | undefined; - if (!request || typeof request !== 'object') { - throw new Error("Invalid or missing 'request' argument in 'invoke_request'"); - } - - const { ty, payload } = request; - - if (typeof ty !== 'string') { - throw new Error("Invalid 'ty' in request for 'invoke_request'"); - } - - if (!(payload instanceof Array)) { - throw new Error("Invalid 'payload' in request for 'invoke_request'"); - } - - return async_event(ty, new Uint8Array(payload)); - default: - throw new Error(`Unknown command: ${cmd}`); - } -} diff --git a/frontend/appflowy_web/src/application/event_bus.ts b/frontend/appflowy_web/src/application/event_bus.ts deleted file mode 100644 index 6a3e95804f..0000000000 --- a/frontend/appflowy_web/src/application/event_bus.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { EventEmitter } from "events"; -import { NotifyArgs } from "../@types/global"; - -const AF_NOTIFICATION = "af-notification"; - -let eventEmitter: EventEmitter; -export function getEventEmitterInstance() { - if (!eventEmitter) { - eventEmitter = new EventEmitter(); - } - return eventEmitter; -} - -export function initEventBus() { - window.onFlowyNotify = (eventName: string, args: NotifyArgs) => { - notify(eventName, args); - }; -} - -export function notify(_eventName: string, args: NotifyArgs) { - const eventEmitter = getEventEmitterInstance(); - eventEmitter.emit(AF_NOTIFICATION, args); -} - -export function onNotify(callback: (args: NotifyArgs) => void) { - const eventEmitter = getEventEmitterInstance(); - eventEmitter.on(AF_NOTIFICATION, callback); - return offNotify; -} - -export function offNotify() { - const eventEmitter = getEventEmitterInstance(); - eventEmitter.removeAllListeners(AF_NOTIFICATION); -} diff --git a/frontend/appflowy_web/src/application/notification.ts b/frontend/appflowy_web/src/application/notification.ts deleted file mode 100644 index aa9b0188e9..0000000000 --- a/frontend/appflowy_web/src/application/notification.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NotifyArgs } from "../@types/global"; -import { onNotify } from "./event_bus.ts"; - -export function subscribeNotification( - callback: (args: NotifyArgs) => void, - options?: { id?: string } -) { - return onNotify((payload) => { - const { id } = payload; - - if (options?.id !== undefined && id !== options.id) { - return; - } - - callback(payload); - }); -} diff --git a/frontend/appflowy_web/src/assets/react.svg b/frontend/appflowy_web/src/assets/react.svg deleted file mode 100644 index 6c87de9bb3..0000000000 --- a/frontend/appflowy_web/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/appflowy_web/src/index.css b/frontend/appflowy_web/src/index.css deleted file mode 100644 index 6119ad9a8f..0000000000 --- a/frontend/appflowy_web/src/index.css +++ /dev/null @@ -1,68 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/frontend/appflowy_web/src/main.tsx b/frontend/appflowy_web/src/main.tsx deleted file mode 100644 index 3d7150da80..0000000000 --- a/frontend/appflowy_web/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' -import './index.css' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/frontend/appflowy_web/src/services/backend/index.ts b/frontend/appflowy_web/src/services/backend/index.ts deleted file mode 100644 index d01244a3b1..0000000000 --- a/frontend/appflowy_web/src/services/backend/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./models/af-user"; -export * from "./models/flowy-error"; -export * from "./models/flowy-folder"; -export * from "./models/flowy-document"; -export * from "./models/flowy-notification"; \ No newline at end of file diff --git a/frontend/appflowy_web/src/vite-env.d.ts b/frontend/appflowy_web/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a0..0000000000 --- a/frontend/appflowy_web/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/frontend/appflowy_web/tsconfig.json b/frontend/appflowy_web/tsconfig.json deleted file mode 100644 index 67609fa96f..0000000000 --- a/frontend/appflowy_web/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "typeRoots": ["./node_modules/@types", "./src/@types"], - - "baseUrl": "./", - "paths": { - "@/*": ["src/*"], - } - }, - "include": ["src", "vite.config.ts"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/frontend/appflowy_web/tsconfig.node.json b/frontend/appflowy_web/tsconfig.node.json deleted file mode 100644 index 42872c59f5..0000000000 --- a/frontend/appflowy_web/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/frontend/appflowy_web/vite.config.ts b/frontend/appflowy_web/vite.config.ts deleted file mode 100644 index 49a8c2b3ad..0000000000 --- a/frontend/appflowy_web/vite.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import wasm from "vite-plugin-wasm"; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), wasm()], - resolve: { - alias: [ - { find: 'src/', replacement: `${__dirname}/src/` }, - { find: '@/', replacement: `${__dirname}/src/` }, - { find: '$app/', replacement: `${__dirname}/src/application/` }, - ], - }, -}) diff --git a/frontend/appflowy_web/wasm-libs/Cargo.lock b/frontend/appflowy_web/wasm-libs/Cargo.lock deleted file mode 100644 index ecde57219d..0000000000 --- a/frontend/appflowy_web/wasm-libs/Cargo.lock +++ /dev/null @@ -1,5283 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "accessory" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850bb534b9dc04744fbbb71d30ad6d25a7e4cf6dc33e223c81ef3a92ebab4e0b" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" -dependencies = [ - "cfg-if 1.0.0", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "af-persistence" -version = "0.1.0" -dependencies = [ - "anyhow", - "flowy-error", - "futures-util", - "indexed_db_futures", - "js-sys", - "serde", - "serde_json", - "thiserror", - "tokio", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "af-user" -version = "0.1.0" -dependencies = [ - "af-persistence", - "anyhow", - "bytes", - "collab", - "collab-entity", - "collab-integrate", - "collab-user", - "flowy-codegen", - "flowy-derive", - "flowy-error", - "flowy-user-pub", - "lib-dispatch", - "lib-infra", - "protobuf", - "strum_macros 0.25.3", - "tokio", - "tracing", - "wasm-bindgen-futures", -] - -[[package]] -name = "af-wasm" -version = "0.1.0" -dependencies = [ - "af-persistence", - "af-user", - "anyhow", - "collab", - "collab-integrate", - "console_error_panic_hook", - "flowy-document", - "flowy-error", - "flowy-folder", - "flowy-notification", - "flowy-server", - "flowy-server-pub", - "flowy-user-pub", - "js-sys", - "lazy_static", - "lib-dispatch", - "lib-infra", - "parking_lot 0.12.1", - "serde", - "serde-wasm-bindgen", - "tokio", - "tokio-stream", - "tracing", - "tracing-core", - "tracing-wasm", - "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test", - "web-sys", - "wee_alloc", -] - -[[package]] -name = "again" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05802a5ad4d172eaf796f7047b42d0af9db513585d16d4169660a21613d34b93" -dependencies = [ - "log", - "rand 0.7.3", - "wasm-timer", -] - -[[package]] -name = "ahash" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" -dependencies = [ - "cfg-if 1.0.0", - "getrandom 0.2.12", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "app-error" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "bincode", - "getrandom 0.2.12", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "tokio", - "tsify", - "url", - "uuid", - "wasm-bindgen", -] - -[[package]] -name = "appflowy-ai-client" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "bytes", - "futures", - "serde", - "serde_json", - "serde_repr", - "thiserror", -] - -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "async-trait" -version = "0.1.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "atomic_refcell" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindgen" -version = "0.65.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.48", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "brotli" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bstr" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "jobserver", - "libc", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.0", -] - -[[package]] -name = "chrono-tz" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d7b79e99bfaa0d47da0687c43aa3b7381938a62ad3a6498599039321f660b7" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf 0.11.2", -] - -[[package]] -name = "chrono-tz-build" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" -dependencies = [ - "parse-zoneinfo", - "phf 0.11.2", - "phf_codegen 0.11.2", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "client-api" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "again", - "anyhow", - "app-error", - "async-trait", - "bincode", - "brotli", - "bytes", - "chrono", - "client-api-entity", - "client-websocket", - "collab", - "collab-rt-entity", - "collab-rt-protocol", - "futures", - "futures-core", - "futures-util", - "getrandom 0.2.12", - "gotrue", - "infra", - "mime", - "parking_lot 0.12.1", - "percent-encoding", - "pin-project", - "prost", - "reqwest", - "scraper 0.17.1", - "semver", - "serde", - "serde_json", - "serde_repr", - "serde_urlencoded", - "shared-entity", - "thiserror", - "tokio", - "tokio-retry", - "tokio-stream", - "tokio-util", - "tracing", - "url", - "uuid", - "wasm-bindgen-futures", - "yrs", -] - -[[package]] -name = "client-api-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "collab-entity", - "collab-rt-entity", - "database-entity", - "gotrue-entity", - "shared-entity", -] - -[[package]] -name = "client-websocket" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "futures-channel", - "futures-util", - "http", - "httparse", - "js-sys", - "percent-encoding", - "thiserror", - "tokio", - "tokio-tungstenite", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "cmd_lib" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f4cbdcab51ca635c5b19c85ece4072ea42e0d2360242826a6fc96fb11f0d40" -dependencies = [ - "cmd_lib_macros", - "env_logger", - "faccess", - "lazy_static", - "log", - "os_pipe", -] - -[[package]] -name = "cmd_lib_macros" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae881960f7e2a409f91ef0b1c09558cf293031a1d6e8b45f908311f2a43f5fdf" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "collab" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" -dependencies = [ - "anyhow", - "async-trait", - "bincode", - "bytes", - "chrono", - "js-sys", - "parking_lot 0.12.1", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "tokio", - "tokio-stream", - "tracing", - "unicode-segmentation", - "web-sys", - "yrs", -] - -[[package]] -name = "collab-document" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" -dependencies = [ - "anyhow", - "collab", - "collab-entity", - "getrandom 0.2.12", - "nanoid", - "parking_lot 0.12.1", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "collab-entity" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" -dependencies = [ - "anyhow", - "bytes", - "collab", - "getrandom 0.2.12", - "serde", - "serde_json", - "serde_repr", - "uuid", -] - -[[package]] -name = "collab-folder" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" -dependencies = [ - "anyhow", - "chrono", - "collab", - "collab-entity", - "getrandom 0.2.12", - "parking_lot 0.12.1", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "collab-integrate" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "collab", - "collab-entity", - "collab-plugins", - "futures", - "lib-infra", - "parking_lot 0.12.1", - "serde", - "serde_json", - "tokio", - "tracing", -] - -[[package]] -name = "collab-plugins" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" -dependencies = [ - "anyhow", - "async-stream", - "async-trait", - "bincode", - "bytes", - "chrono", - "collab", - "collab-entity", - "futures", - "futures-util", - "getrandom 0.2.12", - "indexed_db_futures", - "js-sys", - "lazy_static", - "parking_lot 0.12.1", - "rocksdb", - "serde", - "serde_json", - "similar 2.4.0", - "smallvec", - "thiserror", - "tokio", - "tokio-retry", - "tokio-stream", - "tracing", - "tracing-wasm", - "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yrs", -] - -[[package]] -name = "collab-rt-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "bincode", - "bytes", - "chrono", - "client-websocket", - "collab", - "collab-entity", - "collab-rt-protocol", - "database-entity", - "prost", - "prost-build", - "protoc-bin-vendored", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "tokio-tungstenite", - "yrs", -] - -[[package]] -name = "collab-rt-protocol" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "async-trait", - "bincode", - "collab", - "collab-entity", - "serde", - "thiserror", - "tokio", - "tracing", - "yrs", -] - -[[package]] -name = "collab-user" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" -dependencies = [ - "anyhow", - "collab", - "collab-entity", - "getrandom 0.2.12", - "parking_lot 0.12.1", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "console" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "regex", - "terminal_size", - "unicode-width", - "winapi", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "cookie" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6" -dependencies = [ - "cookie", - "idna 0.3.0", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf 0.11.2", - "smallvec", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.48", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if 1.0.0", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "data-encoding" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" - -[[package]] -name = "database-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "app-error", - "appflowy-ai-client", - "bincode", - "chrono", - "collab-entity", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "tracing", - "uuid", - "validator", -] - -[[package]] -name = "delegate-display" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a85201f233142ac819bbf6226e36d0b5e129a47bd325084674261c82d4cd66" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "deunicode" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" - -[[package]] -name = "diesel" -version = "2.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62c6fcf842f17f8c78ecf7c81d75c5ce84436b41ee07e03f490fbb5f5a8731d8" -dependencies = [ - "chrono", - "diesel_derives", - "libsqlite3-sys", - "r2d2", - "serde_json", - "time", -] - -[[package]] -name = "diesel_derives" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" -dependencies = [ - "diesel_table_macro_syntax", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "diesel_migrations" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac" -dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" -dependencies = [ - "syn 2.0.48", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dyn-clone" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" - -[[package]] -name = "ego-tree" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "faccess" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5" -dependencies = [ - "bitflags 1.3.2", - "libc", - "winapi", -] - -[[package]] -name = "fancy-regex" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0678ab2d46fa5195aaf59ad034c083d351377d4af57f3e073c074d0da3e3c766" -dependencies = [ - "bit-set", - "regex", -] - -[[package]] -name = "fancy-regex" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" -dependencies = [ - "bit-set", - "regex", -] - -[[package]] -name = "fancy_constructor" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -dependencies = [ - "getrandom 0.2.12", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "flowy-ast" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "flowy-chat-pub" -version = "0.1.0" -dependencies = [ - "bytes", - "client-api", - "flowy-error", - "futures", - "lib-infra", -] - -[[package]] -name = "flowy-codegen" -version = "0.1.0" -dependencies = [ - "cmd_lib", - "console", - "fancy-regex 0.10.0", - "flowy-ast", - "itertools", - "lazy_static", - "log", - "phf 0.8.0", - "protoc-bin-vendored", - "protoc-rust", - "quote", - "serde", - "serde_json", - "similar 1.3.0", - "syn 1.0.109", - "tera", - "toml 0.5.11", - "walkdir", -] - -[[package]] -name = "flowy-database-pub" -version = "0.1.0" -dependencies = [ - "anyhow", - "client-api", - "collab", - "collab-entity", - "lib-infra", -] - -[[package]] -name = "flowy-derive" -version = "0.1.0" -dependencies = [ - "dashmap", - "flowy-ast", - "flowy-codegen", - "lazy_static", - "proc-macro2", - "quote", - "serde_json", - "syn 1.0.109", - "walkdir", -] - -[[package]] -name = "flowy-document" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "collab", - "collab-document", - "collab-entity", - "collab-integrate", - "collab-plugins", - "dashmap", - "flowy-codegen", - "flowy-derive", - "flowy-document-pub", - "flowy-error", - "flowy-notification", - "flowy-storage-pub", - "futures", - "getrandom 0.2.12", - "indexmap", - "lib-dispatch", - "lib-infra", - "nanoid", - "parking_lot 0.12.1", - "protobuf", - "scraper 0.18.1", - "serde", - "serde_json", - "strum_macros 0.21.1", - "tokio", - "tokio-stream", - "tracing", - "uuid", - "validator", -] - -[[package]] -name = "flowy-document-pub" -version = "0.1.0" -dependencies = [ - "anyhow", - "collab", - "collab-document", - "flowy-error", - "lib-infra", -] - -[[package]] -name = "flowy-encrypt" -version = "0.1.0" -dependencies = [ - "aes-gcm", - "anyhow", - "base64 0.21.7", - "getrandom 0.2.12", - "hmac", - "pbkdf2 0.12.2", - "rand 0.8.5", - "sha2", -] - -[[package]] -name = "flowy-error" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "client-api", - "collab-document", - "collab-folder", - "collab-plugins", - "fancy-regex 0.11.0", - "flowy-codegen", - "flowy-derive", - "flowy-sqlite", - "lib-dispatch", - "protobuf", - "r2d2", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "tokio", - "url", - "validator", -] - -[[package]] -name = "flowy-folder" -version = "0.1.0" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "collab", - "collab-document", - "collab-entity", - "collab-folder", - "collab-integrate", - "collab-plugins", - "flowy-codegen", - "flowy-derive", - "flowy-error", - "flowy-folder-pub", - "flowy-notification", - "flowy-search-pub", - "flowy-sqlite", - "lazy_static", - "lib-dispatch", - "lib-infra", - "nanoid", - "parking_lot 0.12.1", - "protobuf", - "serde", - "serde_json", - "strum_macros 0.21.1", - "tokio", - "tokio-stream", - "tracing", - "unicode-segmentation", - "uuid", - "validator", -] - -[[package]] -name = "flowy-folder-pub" -version = "0.1.0" -dependencies = [ - "anyhow", - "collab", - "collab-entity", - "collab-folder", - "lib-infra", - "uuid", -] - -[[package]] -name = "flowy-notification" -version = "0.1.0" -dependencies = [ - "bytes", - "dashmap", - "flowy-codegen", - "flowy-derive", - "lazy_static", - "lib-dispatch", - "protobuf", - "serde", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "flowy-search-pub" -version = "0.1.0" -dependencies = [ - "client-api", - "collab", - "collab-folder", - "flowy-error", - "futures", - "lib-infra", -] - -[[package]] -name = "flowy-server" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "chrono", - "client-api", - "collab", - "collab-document", - "collab-entity", - "collab-folder", - "collab-plugins", - "flowy-chat-pub", - "flowy-database-pub", - "flowy-document-pub", - "flowy-encrypt", - "flowy-error", - "flowy-folder-pub", - "flowy-search-pub", - "flowy-server-pub", - "flowy-storage", - "flowy-storage-pub", - "flowy-user-pub", - "futures", - "futures-util", - "hex", - "hyper", - "lazy_static", - "lib-dispatch", - "lib-infra", - "mime_guess", - "parking_lot 0.12.1", - "postgrest", - "rand 0.8.5", - "reqwest", - "semver", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-retry", - "tokio-stream", - "tokio-util", - "tracing", - "url", - "uuid", - "yrs", -] - -[[package]] -name = "flowy-server-pub" -version = "0.1.0" -dependencies = [ - "flowy-error", - "serde", - "serde_repr", -] - -[[package]] -name = "flowy-sqlite" -version = "0.1.0" -dependencies = [ - "anyhow", - "diesel", - "diesel_derives", - "diesel_migrations", - "libsqlite3-sys", - "parking_lot 0.12.1", - "r2d2", - "scheduled-thread-pool", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "flowy-storage" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "chrono", - "flowy-error", - "flowy-sqlite", - "flowy-storage-pub", - "fxhash", - "lib-infra", - "mime_guess", - "serde", - "serde_json", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "flowy-storage-pub" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "bytes", - "client-api-entity", - "flowy-error", - "lib-infra", - "mime", - "mime_guess", - "serde", - "serde_json", - "tokio", -] - -[[package]] -name = "flowy-user-pub" -version = "0.1.0" -dependencies = [ - "anyhow", - "base64 0.21.7", - "chrono", - "collab", - "collab-entity", - "flowy-error", - "flowy-folder-pub", - "lib-infra", - "serde", - "serde_json", - "serde_repr", - "tokio", - "tokio-stream", - "tracing", - "uuid", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags 1.3.2", - "ignore", - "walkdir", -] - -[[package]] -name = "gloo-utils" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gotrue" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "futures-util", - "getrandom 0.2.12", - "gotrue-entity", - "infra", - "reqwest", - "serde", - "serde_json", - "tokio", - "tracing", -] - -[[package]] -name = "gotrue-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "app-error", - "chrono", - "jsonwebtoken", - "lazy_static", - "serde", - "serde_json", -] - -[[package]] -name = "h2" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "http" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http", - "hyper", - "rustls", - "tokio", - "tokio-rustls", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "if_chain" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" - -[[package]] -name = "ignore" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexed_db_futures" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc2083760572ee02385ab8b7c02c20925d2dd1f97a1a25a8737a238608f1152" -dependencies = [ - "accessory", - "cfg-if 1.0.0", - "delegate-display", - "fancy_constructor", - "js-sys", - "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown", - "serde", -] - -[[package]] -name = "infra" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "bytes", - "reqwest", - "serde", - "serde_json", - "tokio", - "tracing", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "is-terminal" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "jobserver" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "lib-dispatch" -version = "0.1.0" -dependencies = [ - "bincode", - "bytes", - "derivative", - "dyn-clone", - "futures", - "futures-channel", - "futures-core", - "futures-util", - "getrandom 0.2.12", - "nanoid", - "parking_lot 0.12.1", - "pin-project", - "protobuf", - "serde", - "serde_json", - "serde_repr", - "thread-id", - "tokio", - "tracing", - "validator", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "lib-infra" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "atomic_refcell", - "bytes", - "cfg-if 1.0.0", - "chrono", - "futures", - "futures-core", - "md5", - "pin-project", - "tempfile", - "tokio", - "tracing", - "validator", - "walkdir", - "zip", -] - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if 1.0.0", - "windows-sys 0.48.0", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "librocksdb-sys" -version = "0.11.0+8.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" -dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", - "zstd-sys", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "macroific" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05c00ac596022625d01047c421a0d97d7f09a18e429187b341c201cb631b9dd" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "macroific_macro", -] - -[[package]] -name = "macroific_attr_parse" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd94d5da95b30ae6e10621ad02340909346ad91661f3f8c0f2b62345e46a2f67" -dependencies = [ - "cfg-if 1.0.0", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "macroific_core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13198c120864097a565ccb3ff947672d969932b7975ebd4085732c9f09435e55" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "macroific_macro" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c9853143cbed7f1e41dc39fee95f9b361bec65c8dc2a01bf609be01b61f5ae" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" - -[[package]] -name = "migrations_internals" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" -dependencies = [ - "serde", - "toml 0.7.8", -] - -[[package]] -name = "migrations_macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "nanoid" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" -dependencies = [ - "rand 0.8.5", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" -dependencies = [ - "bitflags 2.4.2", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.2.1+3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "os_pipe" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall 0.4.1", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" -dependencies = [ - "regex", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pest" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd6ab1236bbdb3a49027e920e693192ebfe8913f6d60e294de57463a493cfde" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "pest_meta" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ff62f5259e53b78d1af898941cdcdccfae7385cf7d793a6e55de5d05bb4b7d" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" - -[[package]] -name = "polyval" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "postgrest" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a966c650b47a064e7082170b4be74fca08c088d893244fc4b70123e3c1f3ee7" -dependencies = [ - "reqwest", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" -dependencies = [ - "proc-macro2", - "syn 2.0.48", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.48", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "prost-types" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" -dependencies = [ - "prost", -] - -[[package]] -name = "protobuf" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" - -[[package]] -name = "protobuf-codegen" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6" -dependencies = [ - "protobuf", -] - -[[package]] -name = "protoc" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0218039c514f9e14a5060742ecd50427f8ac4f85a6dc58f2ddb806e318c55ee" -dependencies = [ - "log", - "which", -] - -[[package]] -name = "protoc-bin-vendored" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005ca8623e5633e298ad1f917d8be0a44bcf406bf3cde3b80e63003e49a3f27d" -dependencies = [ - "protoc-bin-vendored-linux-aarch_64", - "protoc-bin-vendored-linux-ppcle_64", - "protoc-bin-vendored-linux-x86_32", - "protoc-bin-vendored-linux-x86_64", - "protoc-bin-vendored-macos-x86_64", - "protoc-bin-vendored-win32", -] - -[[package]] -name = "protoc-bin-vendored-linux-aarch_64" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb9fc9cce84c8694b6ea01cc6296617b288b703719b725b8c9c65f7c5874435" - -[[package]] -name = "protoc-bin-vendored-linux-ppcle_64" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d2a07dcf7173a04d49974930ccbfb7fd4d74df30ecfc8762cf2f895a094516" - -[[package]] -name = "protoc-bin-vendored-linux-x86_32" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54fef0b04fcacba64d1d80eed74a20356d96847da8497a59b0a0a436c9165b0" - -[[package]] -name = "protoc-bin-vendored-linux-x86_64" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8782f2ce7d43a9a5c74ea4936f001e9e8442205c244f7a3d4286bd4c37bc924" - -[[package]] -name = "protoc-bin-vendored-macos-x86_64" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5de656c7ee83f08e0ae5b81792ccfdc1d04e7876b1d9a38e6876a9e09e02537" - -[[package]] -name = "protoc-bin-vendored-win32" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9653c3ed92974e34c5a6e0a510864dab979760481714c172e0a34e437cb98804" - -[[package]] -name = "protoc-rust" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f8a182bb17c485f20bdc4274a8c39000a61024cfe461c799b50fec77267838" -dependencies = [ - "protobuf", - "protobuf-codegen", - "protoc", - "tempfile", -] - -[[package]] -name = "psl-types" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" - -[[package]] -name = "publicsuffix" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" -dependencies = [ - "idna 0.3.0", - "psl-types", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot 0.12.1", - "scheduled-thread-pool", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.12", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "cookie", - "cookie_store", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "mime_guess", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-rustls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots", - "winreg", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom 0.2.12", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.48.0", -] - -[[package]] -name = "rocksdb" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" -dependencies = [ - "libc", - "librocksdb-sys", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring 0.17.7", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot 0.12.1", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scraper" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c" -dependencies = [ - "ahash", - "cssparser", - "ego-tree", - "getopts", - "html5ever", - "once_cell", - "selectors", - "smallvec", - "tendril", -] - -[[package]] -name = "scraper" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585480e3719b311b78a573db1c9d9c4c1f8010c2dee4cc59c2efe58ea4dbc3e1" -dependencies = [ - "ahash", - "cssparser", - "ego-tree", - "getopts", - "html5ever", - "once_cell", - "selectors", - "tendril", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" -dependencies = [ - "bitflags 2.4.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "new_debug_unreachable", - "phf 0.10.1", - "phf_codegen 0.10.0", - "precomputed-hash", - "servo_arc", - "smallvec", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "serde_derive_internals" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "serde_json" -version = "1.0.111" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "serde_spanned" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "servo_arc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared-entity" -version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9884d93aa2805013f36a79c1757174a0b5063065#9884d93aa2805013f36a79c1757174a0b5063065" -dependencies = [ - "anyhow", - "app-error", - "appflowy-ai-client", - "bytes", - "chrono", - "collab-entity", - "database-entity", - "futures", - "gotrue-entity", - "log", - "pin-project", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "thiserror", - "uuid", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "similar" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad1d488a557b235fc46dae55512ffbfc429d2482b08b4d9435ab07384ca8aec" - -[[package]] -name = "similar" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "slug" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" -dependencies = [ - "deunicode", - "wasm-bindgen", -] - -[[package]] -name = "smallstr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b1aefdf380735ff8ded0b15f31aab05daf1f70216c01c02a12926badd1df9d" -dependencies = [ - "smallvec", -] - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.1", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.48", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "redox_syscall 0.4.1", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "tera" -version = "1.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8" -dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static", - "percent-encoding", - "pest", - "pest_derive", - "rand 0.8.5", - "regex", - "serde", - "serde_json", - "slug", - "unic-segment", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "thread-id" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" -dependencies = [ - "libc", - "redox_syscall 0.1.57", - "winapi", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if 1.0.0", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" -dependencies = [ - "deranged", - "itoa", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" -dependencies = [ - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot 0.12.1", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-retry" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" -dependencies = [ - "pin-project", - "rand 0.8.5", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "native-tls", - "tokio", - "tokio-native-tls", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - -[[package]] -name = "tracing-wasm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" -dependencies = [ - "tracing", - "tracing-subscriber", - "wasm-bindgen", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tsify" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b26cf145f2f3b9ff84e182c448eaf05468e247f148cf3d2a7d67d78ff023a0" -dependencies = [ - "gloo-utils", - "serde", - "serde_json", - "tsify-macros", - "wasm-bindgen", -] - -[[package]] -name = "tsify-macros" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a94b0f0954b3e59bfc2c246b4c8574390d94a4ad4ad246aaf2fb07d7dfd3b47" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.48", -] - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "native-tls", - "rand 0.8.5", - "sha1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "ucd-trie" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna 0.5.0", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "uuid" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" -dependencies = [ - "getrandom 0.2.12", - "serde", - "sha1_smol", - "wasm-bindgen", -] - -[[package]] -name = "validator" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" -dependencies = [ - "idna 0.4.0", - "lazy_static", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] - -[[package]] -name = "validator_derive" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af" -dependencies = [ - "if_chain", - "lazy_static", - "proc-macro-error", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", - "validator_types", -] - -[[package]] -name = "validator_types" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" -dependencies = [ - "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" - -[[package]] -name = "wasm-bindgen-test" -version = "0.3.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139bd73305d50e1c1c4333210c0db43d989395b64a237bd35c10ef3832a7f70c" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70072aebfe5da66d2716002c729a14e4aec4da0e23cc2ea66323dac541c93928" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "wasm-streams" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" - -[[package]] -name = "wee_alloc" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "memory_units", - "winapi", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if 1.0.0", - "windows-sys 0.48.0", -] - -[[package]] -name = "yrs" -version = "0.18.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da227d69095141c331d9b60c11496d0a3c6505cd9f8e200898b197219e8e394f" -dependencies = [ - "arc-swap", - "atomic_refcell", - "fastrand", - "serde", - "serde_json", - "smallstr", - "smallvec", - "thiserror", -] - -[[package]] -name = "zerocopy" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" -dependencies = [ - "cc", - "pkg-config", -] - -[[patch.unused]] -name = "collab-database" -version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6febf0397e66ebf0a281980a2e7602d7af00c975#6febf0397e66ebf0a281980a2e7602d7af00c975" diff --git a/frontend/appflowy_web/wasm-libs/Cargo.toml b/frontend/appflowy_web/wasm-libs/Cargo.toml deleted file mode 100644 index a3578b9cb3..0000000000 --- a/frontend/appflowy_web/wasm-libs/Cargo.toml +++ /dev/null @@ -1,76 +0,0 @@ -[workspace] -members = ["af-wasm", "af-user", "af-persistence"] -resolver = "2" - -[workspace.dependencies] -af-user = { path = "af-user" } -af-persistence = { path = "af-persistence" } -lib-dispatch = { path = "../../rust-lib/lib-dispatch" } -parking_lot = { version = "0.12.1" } -tracing = { version = "0.1.22" } -serde = { version = "1.0.194", features = ["derive"] } -serde_json = "1.0" -collab-integrate = { path = "../../rust-lib/collab-integrate" } -flowy-notification = { path = "../../rust-lib/flowy-notification" } -flowy-user-pub = { path = "../../rust-lib/flowy-user-pub" } -flowy-server = { path = "../../rust-lib/flowy-server" } -flowy-server-pub = { path = "../../rust-lib/flowy-server-pub" } -flowy-error = { path = "../../rust-lib/flowy-error" } -flowy-derive = { path = "../../rust-lib/build-tool/flowy-derive" } -flowy-codegen = { path = "../../rust-lib/build-tool/flowy-codegen" } -flowy-document = { path = "../../rust-lib/flowy-document" } -flowy-folder = { path = "../../rust-lib/flowy-folder" } -lib-infra = { path = "../../rust-lib/lib-infra" } -bytes = { version = "1.5" } -protobuf = { version = "2.28.0" } -thiserror = "1.0" -anyhow = "1.0" -futures-util = "0.3" -uuid = { version = "1.5", features = ["serde", "v4", "v5"] } -tokio-stream = "0.1" -tokio = { version = "1.35", features = ["sync"] } -wasm-bindgen-futures = "0.4.40" -serde-wasm-bindgen = "0.4" -# Please use the following script to update collab. -# Working directory: frontend -# -# To update the commit ID, run: -# scripts/tool/update_collab_rev.sh new_rev_id -# -# To switch to the local path, run: -# scripts/tool/update_collab_source.sh -# ⚠️⚠️⚠️️ -collab = { version = "0.2" } -collab-entity = { version = "0.2" } -collab-folder = { version = "0.2" } -collab-document = { version = "0.2" } -collab-database = { version = "0.2" } -collab-plugins = { version = "0.2" } -collab-user = { version = "0.2" } -yrs = "0.18.8" - -# Please using the following command to update the revision id -# Current directory: frontend -# Run the script: -# scripts/tool/update_client_api_rev.sh new_rev_id -# ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9884d93aa2805013f36a79c1757174a0b5063065" } - -[profile.dev] -opt-level = 0 -lto = false -codegen-units = 16 - -[profile.release] -lto = true -opt-level = 3 -codegen-units = 1 - -[patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/appflowy_web/wasm-libs/af-persistence/Cargo.toml b/frontend/appflowy_web/wasm-libs/af-persistence/Cargo.toml deleted file mode 100644 index 14825ef54a..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-persistence/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "af-persistence" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -indexed_db_futures = { version = "0.4" } -js-sys = "0.3" -wasm-bindgen = "0.2" -web-sys = { version = "0.3", features = ["console", "Window"] } -tokio = { version = "1.26.0", features = ["sync", "rt"] } -flowy-error.workspace = true -thiserror.workspace = true -anyhow.workspace = true -serde.workspace = true -serde_json.workspace = true -futures-util.workspace = true -wasm-bindgen-futures.workspace = true diff --git a/frontend/appflowy_web/wasm-libs/af-persistence/src/error.rs b/frontend/appflowy_web/wasm-libs/af-persistence/src/error.rs deleted file mode 100644 index 1a6ad08d9a..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-persistence/src/error.rs +++ /dev/null @@ -1,30 +0,0 @@ -use flowy_error::FlowyError; -use web_sys::DomException; - -#[derive(Debug, thiserror::Error)] -pub enum PersistenceError { - #[error(transparent)] - Internal(#[from] anyhow::Error), - - #[error(transparent)] - SerdeError(#[from] serde_json::Error), - - #[error("{0}")] - RecordNotFound(String), -} - -impl From for PersistenceError { - fn from(value: DomException) -> Self { - PersistenceError::Internal(anyhow::anyhow!("DOMException: {:?}", value)) - } -} - -impl From for FlowyError { - fn from(value: PersistenceError) -> Self { - match value { - PersistenceError::Internal(value) => FlowyError::internal().with_context(value), - PersistenceError::SerdeError(value) => FlowyError::serde().with_context(value), - PersistenceError::RecordNotFound(value) => FlowyError::record_not_found().with_context(value), - } - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-persistence/src/lib.rs b/frontend/appflowy_web/wasm-libs/af-persistence/src/lib.rs deleted file mode 100644 index 4f89971020..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-persistence/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod error; -pub mod store; diff --git a/frontend/appflowy_web/wasm-libs/af-persistence/src/store.rs b/frontend/appflowy_web/wasm-libs/af-persistence/src/store.rs deleted file mode 100644 index 92335e32b3..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-persistence/src/store.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::error::PersistenceError; -use anyhow::anyhow; -use futures_util::future::LocalBoxFuture; -use indexed_db_futures::idb_object_store::IdbObjectStore; -use indexed_db_futures::idb_transaction::{IdbTransaction, IdbTransactionResult}; -use indexed_db_futures::prelude::IdbOpenDbRequestLike; -use indexed_db_futures::{IdbDatabase, IdbQuerySource, IdbVersionChangeEvent}; -use js_sys::Uint8Array; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::future::Future; -use std::sync::Arc; -use tokio::sync::RwLock; -use wasm_bindgen::JsValue; -use web_sys::IdbTransactionMode; - -pub trait IndexddbStore { - fn get<'a, T>(&'a self, key: &'a str) -> LocalBoxFuture, PersistenceError>> - where - T: serde::de::DeserializeOwned + Sync; - fn set<'a, T>(&'a self, key: &'a str, value: T) -> LocalBoxFuture> - where - T: serde::Serialize + Sync + 'a; - fn remove<'a>(&'a self, key: &'a str) -> LocalBoxFuture>; -} - -const APPFLOWY_STORE: &str = "appflowy_store"; -pub struct AppFlowyWASMStore { - db: Arc>, -} - -unsafe impl Send for AppFlowyWASMStore {} -unsafe impl Sync for AppFlowyWASMStore {} - -impl AppFlowyWASMStore { - pub async fn new() -> Result { - let mut db_req = IdbDatabase::open_u32("appflowy", 1)?; - db_req.set_on_upgrade_needed(Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> { - if !evt.db().object_store_names().any(|n| &n == APPFLOWY_STORE) { - evt.db().create_object_store(APPFLOWY_STORE)?; - } - Ok(()) - })); - let db = Arc::new(RwLock::new(db_req.await?)); - Ok(Self { db }) - } - - pub async fn begin_read_transaction(&self, f: F) -> Result<(), PersistenceError> - where - F: FnOnce(&IndexddbStoreImpl<'_>) -> Fut, - Fut: Future>, - { - let db = self.db.read().await; - let txn = db.transaction_on_one_with_mode(APPFLOWY_STORE, IdbTransactionMode::Readonly)?; - let store = store_from_transaction(&txn)?; - let operation = IndexddbStoreImpl(store); - f(&operation).await?; - transaction_result_to_result(txn.await)?; - Ok(()) - } - - pub async fn begin_write_transaction(&self, f: F) -> Result<(), PersistenceError> - where - F: FnOnce(IndexddbStoreImpl<'_>) -> LocalBoxFuture<'_, Result<(), PersistenceError>>, - { - let db = self.db.write().await; - let txn = db.transaction_on_one_with_mode(APPFLOWY_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&txn)?; - let operation = IndexddbStoreImpl(store); - f(operation).await?; - transaction_result_to_result(txn.await)?; - Ok(()) - } -} - -pub struct IndexddbStoreImpl<'i>(IdbObjectStore<'i>); - -impl<'i> IndexddbStore for IndexddbStoreImpl<'i> { - fn get<'a, T>(&'a self, key: &'a str) -> LocalBoxFuture, PersistenceError>> - where - T: DeserializeOwned + Sync, - { - let js_key = to_js_value(key); - Box::pin(async move { - match self.0.get(&js_key)?.await? { - None => Err(PersistenceError::RecordNotFound(format!( - "Can't find the value for given key: {} ", - key - ))), - Some(value) => { - let bytes = Uint8Array::new(&value).to_vec(); - let object = serde_json::from_slice::(&bytes)?; - Ok(Some(object)) - }, - } - }) - } - - fn set<'a, T>(&'a self, key: &'a str, value: T) -> LocalBoxFuture> - where - T: Serialize + Sync + 'a, - { - let js_key = to_js_value(key); - Box::pin(async move { - let js_value = to_js_value(serde_json::to_vec(&value)?); - self.0.put_key_val(&js_key, &js_value)?.await?; - Ok(()) - }) - } - - fn remove<'a>(&'a self, key: &'a str) -> LocalBoxFuture> { - let js_key = to_js_value(key); - Box::pin(async move { - self.0.delete(&js_key)?.await?; - Ok(()) - }) - } -} - -impl IndexddbStore for AppFlowyWASMStore { - fn get<'a, T>(&'a self, key: &'a str) -> LocalBoxFuture, PersistenceError>> - where - T: serde::de::DeserializeOwned + Sync, - { - let db = Arc::downgrade(&self.db); - Box::pin(async move { - let db = db.upgrade().ok_or_else(|| { - PersistenceError::Internal(anyhow!("Failed to upgrade the database reference")) - })?; - let read_guard = db.read().await; - let txn = - read_guard.transaction_on_one_with_mode(APPFLOWY_STORE, IdbTransactionMode::Readonly)?; - let store = store_from_transaction(&txn)?; - IndexddbStoreImpl(store).get(key).await - }) - } - - fn set<'a, T>(&'a self, key: &'a str, value: T) -> LocalBoxFuture> - where - T: serde::Serialize + Sync + 'a, - { - let db = Arc::downgrade(&self.db); - Box::pin(async move { - let db = db.upgrade().ok_or_else(|| { - PersistenceError::Internal(anyhow!("Failed to upgrade the database reference")) - })?; - let read_guard = db.read().await; - let txn = - read_guard.transaction_on_one_with_mode(APPFLOWY_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&txn)?; - IndexddbStoreImpl(store).set(key, value).await?; - transaction_result_to_result(txn.await)?; - Ok(()) - }) - } - - fn remove<'a>(&'a self, key: &'a str) -> LocalBoxFuture> { - let db = Arc::downgrade(&self.db); - Box::pin(async move { - let db = db.upgrade().ok_or_else(|| { - PersistenceError::Internal(anyhow!("Failed to upgrade the database reference")) - })?; - let read_guard = db.read().await; - let txn = - read_guard.transaction_on_one_with_mode(APPFLOWY_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&txn)?; - IndexddbStoreImpl(store).remove(key).await?; - transaction_result_to_result(txn.await)?; - Ok(()) - }) - } -} - -fn to_js_value>(key: K) -> JsValue { - JsValue::from(Uint8Array::from(key.as_ref())) -} - -fn store_from_transaction<'a>( - txn: &'a IdbTransaction<'a>, -) -> Result, PersistenceError> { - txn - .object_store(APPFLOWY_STORE) - .map_err(PersistenceError::from) -} - -fn transaction_result_to_result(result: IdbTransactionResult) -> Result<(), PersistenceError> { - match result { - IdbTransactionResult::Success => Ok(()), - IdbTransactionResult::Error(err) => Err(PersistenceError::from(err)), - IdbTransactionResult::Abort => Err(PersistenceError::Internal(anyhow!("Transaction aborted"))), - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/Cargo.toml b/frontend/appflowy_web/wasm-libs/af-user/Cargo.toml deleted file mode 100644 index 27351d8f06..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "af-user" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -af-persistence.workspace = true -lib-dispatch = { workspace = true } -flowy-derive = { workspace = true } -flowy-error = { workspace = true, features = ["impl_from_dispatch_error", "impl_from_collab_persistence"] } -flowy-user-pub = { workspace = true } -strum_macros = "0.25.2" -tracing.workspace = true -lib-infra = { workspace = true } -collab = { workspace = true } -collab-entity.workspace = true -collab-user.workspace = true -collab-integrate = { workspace = true } -protobuf.workspace = true -bytes.workspace = true -anyhow.workspace = true -wasm-bindgen-futures.workspace = true -tokio = { workspace = true, features = ["sync"] } - -[build-dependencies] -flowy-codegen = { workspace = true, features = ["ts"] } diff --git a/frontend/appflowy_web/wasm-libs/af-user/Flowy.toml b/frontend/appflowy_web/wasm-libs/af-user/Flowy.toml deleted file mode 100644 index 593c05b741..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/Flowy.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Check out the FlowyConfig (located in flowy_toml.rs) for more details. -proto_input = ["src/entities", "src/event_map.rs"] -event_files = ["src/event_map.rs"] \ No newline at end of file diff --git a/frontend/appflowy_web/wasm-libs/af-user/build.rs b/frontend/appflowy_web/wasm-libs/af-user/build.rs deleted file mode 100644 index 11b5513097..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/build.rs +++ /dev/null @@ -1,17 +0,0 @@ -use flowy_codegen::Project; - -fn main() { - flowy_codegen::protobuf_file::ts_gen( - env!("CARGO_PKG_NAME"), - "user", - Project::Web { - relative_path: "../../../".to_string(), - }, - ); - flowy_codegen::ts_event::gen( - "user", - Project::Web { - relative_path: "../../../".to_string(), - }, - ); -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/authenticate_user.rs b/frontend/appflowy_web/wasm-libs/af-user/src/authenticate_user.rs deleted file mode 100644 index 57ba448081..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/authenticate_user.rs +++ /dev/null @@ -1,20 +0,0 @@ -use af_persistence::store::AppFlowyWASMStore; -use flowy_error::FlowyResult; -use flowy_user_pub::session::Session; -use std::rc::Rc; -use std::sync::Arc; -use tokio::sync::RwLock; - -pub struct AuthenticateUser { - session: Arc>>, - store: Rc, -} - -impl AuthenticateUser { - pub async fn new(store: Rc) -> FlowyResult { - Ok(Self { - session: Arc::new(RwLock::new(None)), - store, - }) - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/define.rs b/frontend/appflowy_web/wasm-libs/af-user/src/define.rs deleted file mode 100644 index 520cf21f34..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/define.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub(crate) const AF_USER_SESSION_KEY: &str = "af-user-session"; - -pub(crate) fn user_workspace_key(uid: i64) -> String { - format!("af-user-workspaces-{}", uid) -} - -pub(crate) fn user_profile_key(uid: i64) -> String { - format!("af-user-profile-{}", uid) -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/entities/auth.rs b/frontend/appflowy_web/wasm-libs/af-user/src/entities/auth.rs deleted file mode 100644 index 96455adc5f..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/entities/auth.rs +++ /dev/null @@ -1,68 +0,0 @@ -use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_user_pub::entities::Authenticator; -use std::collections::HashMap; - -#[derive(ProtoBuf, Default)] -pub struct OauthSignInPB { - /// Use this field to store the third party auth information. - /// Different auth type has different fields. - /// Supabase: - /// - map: { "uuid": "xxx" } - /// - #[pb(index = 1)] - pub map: HashMap, - - #[pb(index = 2)] - pub authenticator: AuthenticatorPB, -} - -#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)] -pub enum AuthenticatorPB { - Local = 0, - Supabase = 1, - AppFlowyCloud = 2, -} - -impl From for AuthenticatorPB { - fn from(auth_type: Authenticator) -> Self { - match auth_type { - Authenticator::Supabase => AuthenticatorPB::Supabase, - Authenticator::Local => AuthenticatorPB::Local, - Authenticator::AppFlowyCloud => AuthenticatorPB::AppFlowyCloud, - } - } -} - -impl From for Authenticator { - fn from(pb: AuthenticatorPB) -> Self { - match pb { - AuthenticatorPB::Supabase => Authenticator::Supabase, - AuthenticatorPB::Local => Authenticator::Local, - AuthenticatorPB::AppFlowyCloud => Authenticator::AppFlowyCloud, - } - } -} - -impl Default for AuthenticatorPB { - fn default() -> Self { - Self::AppFlowyCloud - } -} - -#[derive(ProtoBuf, Default)] -pub struct AddUserPB { - #[pb(index = 1)] - pub email: String, - - #[pb(index = 2)] - pub password: String, -} - -#[derive(ProtoBuf, Default)] -pub struct UserSignInPB { - #[pb(index = 1)] - pub email: String, - - #[pb(index = 2)] - pub password: String, -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/entities/mod.rs b/frontend/appflowy_web/wasm-libs/af-user/src/entities/mod.rs deleted file mode 100644 index fd9d22da5d..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/entities/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod auth; -mod user; - -pub use auth::*; -pub use user::*; diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/entities/user.rs b/frontend/appflowy_web/wasm-libs/af-user/src/entities/user.rs deleted file mode 100644 index 113ec6fec4..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/entities/user.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::entities::AuthenticatorPB; -use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_user_pub::entities::{EncryptionType, UserProfile}; - -#[derive(ProtoBuf, Default, Eq, PartialEq, Debug, Clone)] -pub struct UserProfilePB { - #[pb(index = 1)] - pub id: i64, - - #[pb(index = 2)] - pub email: String, - - #[pb(index = 3)] - pub name: String, - - #[pb(index = 4)] - pub token: String, - - #[pb(index = 5)] - pub icon_url: String, - - #[pb(index = 6)] - pub openai_key: String, - - #[pb(index = 7)] - pub authenticator: AuthenticatorPB, - - #[pb(index = 8)] - pub encryption_sign: String, - - #[pb(index = 9)] - pub workspace_id: String, - - #[pb(index = 10)] - pub stability_ai_key: String, - - #[pb(index = 11)] - pub ai_model: String, -} - -impl From for UserProfilePB { - fn from(user_profile: UserProfile) -> Self { - let (encryption_sign, _encryption_ty) = match user_profile.encryption_type { - EncryptionType::NoEncryption => ("".to_string(), EncryptionTypePB::NoEncryption), - EncryptionType::SelfEncryption(sign) => (sign, EncryptionTypePB::Symmetric), - }; - Self { - id: user_profile.uid, - email: user_profile.email, - name: user_profile.name, - token: user_profile.token, - icon_url: user_profile.icon_url, - openai_key: user_profile.openai_key, - encryption_sign, - authenticator: user_profile.authenticator.into(), - workspace_id: user_profile.workspace_id, - stability_ai_key: user_profile.stability_ai_key, - ai_model: user_profile.ai_model, - } - } -} - -#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)] -pub enum EncryptionTypePB { - NoEncryption = 0, - Symmetric = 1, -} - -impl Default for EncryptionTypePB { - fn default() -> Self { - Self::NoEncryption - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/event_handler.rs b/frontend/appflowy_web/wasm-libs/af-user/src/event_handler.rs deleted file mode 100644 index 401f1e98ab..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/event_handler.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::entities::*; -use crate::manager::UserManager; -use flowy_error::{FlowyError, FlowyResult}; -use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult}; -use lib_infra::box_any::BoxAny; -use std::rc::{Rc, Weak}; - -#[tracing::instrument(level = "debug", skip(data, manager), err)] -pub async fn oauth_sign_in_handler( - data: AFPluginData, - manager: AFPluginState>, -) -> DataResult { - let manager = upgrade_manager(manager)?; - let params = data.into_inner(); - let user_profile = manager.sign_up(BoxAny::new(params.map)).await?; - data_result_ok(user_profile.into()) -} - -#[tracing::instrument(level = "debug", skip(data, manager), err)] -pub async fn add_user_handler( - data: AFPluginData, - manager: AFPluginState>, -) -> Result<(), FlowyError> { - let manager = upgrade_manager(manager)?; - let params = data.into_inner(); - manager.add_user(¶ms.email, ¶ms.password).await?; - Ok(()) -} - -#[tracing::instrument(level = "debug", skip(data, manager), err)] -pub async fn sign_in_with_password_handler( - data: AFPluginData, - manager: AFPluginState>, -) -> DataResult { - let manager = upgrade_manager(manager)?; - let params = data.into_inner(); - let user_profile = manager - .sign_in_with_password(¶ms.email, ¶ms.password) - .await?; - data_result_ok(UserProfilePB::from(user_profile)) -} - -fn upgrade_manager(manager: AFPluginState>) -> FlowyResult> { - let manager = manager - .upgrade() - .ok_or(FlowyError::internal().with_context("The user session is already drop"))?; - Ok(manager) -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/event_map.rs b/frontend/appflowy_web/wasm-libs/af-user/src/event_map.rs deleted file mode 100644 index 1047760352..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/event_map.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::event_handler::*; -use crate::manager::UserManager; -use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; -use lib_dispatch::prelude::AFPlugin; -use std::rc::Weak; -use strum_macros::Display; - -#[rustfmt::skip] -pub fn init(user_manager: Weak) -> AFPlugin { - AFPlugin::new() - .name("Flowy-User") - .state(user_manager) - .event(UserWasmEvent::OauthSignIn, oauth_sign_in_handler) - .event(UserWasmEvent::AddUser, add_user_handler) - .event(UserWasmEvent::SignInPassword, sign_in_with_password_handler) -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] -#[event_err = "FlowyError"] -pub enum UserWasmEvent { - #[event(input = "OauthSignInPB", output = "UserProfilePB")] - OauthSignIn = 0, - - #[event(input = "AddUserPB")] - AddUser = 1, - - #[event(input = "UserSignInPB", output = "UserProfilePB")] - SignInPassword = 2, -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/lib.rs b/frontend/appflowy_web/wasm-libs/af-user/src/lib.rs deleted file mode 100644 index d3519c7552..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod authenticate_user; -mod define; -pub mod entities; -mod event_handler; -pub mod event_map; -pub mod manager; -mod protobuf; diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/manager.rs b/frontend/appflowy_web/wasm-libs/af-user/src/manager.rs deleted file mode 100644 index 3832218ae8..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/manager.rs +++ /dev/null @@ -1,205 +0,0 @@ -use crate::authenticate_user::AuthenticateUser; -use crate::define::{user_profile_key, user_workspace_key, AF_USER_SESSION_KEY}; -use af_persistence::store::{AppFlowyWASMStore, IndexddbStore}; -use anyhow::Context; -use collab::core::collab::DataSource; -use collab_entity::CollabType; -use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig}; -use collab_integrate::{CollabKVDB, MutexCollab}; -use collab_user::core::{MutexUserAwareness, UserAwareness}; -use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_user_pub::cloud::{UserCloudConfig, UserCloudServiceProvider}; -use flowy_user_pub::entities::{ - user_awareness_object_id, AuthResponse, Authenticator, UserAuthResponse, UserProfile, - UserWorkspace, -}; -use flowy_user_pub::session::Session; -use lib_infra::box_any::BoxAny; -use lib_infra::future::Fut; -use std::rc::Rc; -use std::sync::{Arc, Mutex, Weak}; -use tracing::{error, instrument, trace}; - -pub trait UserCallback { - fn did_init( - &self, - user_id: i64, - cloud_config: &Option, - user_workspace: &UserWorkspace, - device_id: &str, - ) -> Fut>; - fn did_sign_in(&self, uid: i64, workspace: &UserWorkspace, device_id: &str) -> FlowyResult<()>; - fn did_sign_up( - &self, - is_new_user: bool, - user_profile: &UserProfile, - user_workspace: &UserWorkspace, - device_id: &str, - ) -> Fut>; -} - -pub struct UserManager { - device_id: String, - pub(crate) store: Rc, - pub(crate) cloud_services: Rc, - pub(crate) collab_builder: Weak, - pub(crate) authenticate_user: Rc, - - #[allow(dead_code)] - pub(crate) user_awareness: Rc>>, - pub(crate) collab_db: Arc, - - user_callbacks: Vec>, -} - -impl UserManager { - pub async fn new( - device_id: &str, - store: Rc, - cloud_services: Rc, - authenticate_user: Rc, - collab_builder: Weak, - ) -> Result { - let device_id = device_id.to_string(); - let store = Rc::new(AppFlowyWASMStore::new().await?); - let collab_db = Arc::new(CollabKVDB::new().await?); - Ok(Self { - device_id, - cloud_services, - collab_builder, - store, - authenticate_user, - user_callbacks: vec![], - user_awareness: Rc::new(Default::default()), - collab_db, - }) - } - - pub async fn sign_up(&self, params: BoxAny) -> FlowyResult { - let auth_service = self.cloud_services.get_user_service()?; - let response: AuthResponse = auth_service.sign_up(params).await?; - let new_user_profile = UserProfile::from((&response, &Authenticator::AppFlowyCloud)); - let new_session = Session::from(&response); - - self.prepare_collab(&new_session); - self - .save_auth_data(&response, &new_user_profile, &new_session) - .await?; - - for callback in self.user_callbacks.iter() { - if let Err(e) = callback - .did_sign_up( - response.is_new_user, - &new_user_profile, - &new_session.user_workspace, - &self.device_id, - ) - .await - { - error!("Failed to call did_sign_up callback: {:?}", e); - } - } - - // TODO(nathan): send notification - // send_auth_state_notification(AuthStateChangedPB { - // state: AuthStatePB::AuthStateSignIn, - // message: "Sign in success".to_string(), - // }); - Ok(new_user_profile) - } - - pub(crate) async fn add_user(&self, email: &str, password: &str) -> Result<(), FlowyError> { - let auth_service = self.cloud_services.get_user_service()?; - auth_service.create_user(email, password).await?; - Ok(()) - } - - pub(crate) async fn sign_in_with_password( - &self, - email: &str, - password: &str, - ) -> Result { - let auth_service = self.cloud_services.get_user_service()?; - let user_profile = auth_service.sign_in_with_password(email, password).await?; - Ok(user_profile) - } - - fn prepare_collab(&self, session: &Session) { - let collab_builder = self.collab_builder.upgrade().unwrap(); - collab_builder.initialize(session.user_workspace.id.clone()); - } - - #[instrument(level = "info", skip_all, err)] - async fn save_auth_data( - &self, - response: &impl UserAuthResponse, - user_profile: &UserProfile, - session: &Session, - ) -> Result<(), FlowyError> { - let uid = user_profile.uid; - let user_profile = user_profile.clone(); - let session = session.clone(); - let user_workspace = response.user_workspaces().to_vec(); - self - .store - .begin_write_transaction(|store| { - Box::pin(async move { - store.set(&user_workspace_key(uid), &user_workspace).await?; - store.set(AF_USER_SESSION_KEY, session).await?; - store.set(&user_profile_key(uid), user_profile).await?; - Ok(()) - }) - }) - .await?; - - Ok(()) - } - - pub async fn save_user_session(&self, session: &Session) -> FlowyResult<()> { - self.store.set(AF_USER_SESSION_KEY, session).await?; - Ok(()) - } - - pub async fn save_user_workspaces( - &self, - uid: i64, - user_workspaces: &[UserWorkspace], - ) -> FlowyResult<()> { - self - .store - .set(&user_workspace_key(uid), &user_workspaces.to_vec()) - .await?; - Ok(()) - } - - pub async fn save_user_profile(&self, user_profile: &UserProfile) -> FlowyResult<()> { - let uid = user_profile.uid; - self.store.set(&user_profile_key(uid), user_profile).await?; - Ok(()) - } - - async fn collab_for_user_awareness( - &self, - uid: i64, - object_id: &str, - collab_db: Weak, - raw_data: Vec, - ) -> Result, FlowyError> { - let collab_builder = self.collab_builder.upgrade().ok_or(FlowyError::new( - ErrorCode::Internal, - "Unexpected error: collab builder is not available", - ))?; - let collab = collab_builder - .build( - uid, - object_id, - CollabType::UserAwareness, - DataSource::DocStateV1(raw_data), - collab_db, - CollabBuilderConfig::default().sync_enable(true), - ) - .await - .context("Build collab for user awareness failed")?; - Ok(collab) - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/auth.rs b/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/auth.rs deleted file mode 100644 index 6dd0bd20f0..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/auth.rs +++ /dev/null @@ -1,689 +0,0 @@ -// This file is generated by rust-protobuf 2.28.0. Do not edit -// @generated - -// https://github.com/rust-lang/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy::all)] - -#![allow(unused_attributes)] -#![cfg_attr(rustfmt, rustfmt::skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unused_imports)] -#![allow(unused_results)] -//! Generated file from `auth.proto` - -/// Generated files are compatible only with the same version -/// of protobuf runtime. -// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0; - -#[derive(PartialEq,Clone,Default)] -pub struct OauthSignInPB { - // message fields - pub map: ::std::collections::HashMap<::std::string::String, ::std::string::String>, - pub authenticator: AuthenticatorPB, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a OauthSignInPB { - fn default() -> &'a OauthSignInPB { - ::default_instance() - } -} - -impl OauthSignInPB { - pub fn new() -> OauthSignInPB { - ::std::default::Default::default() - } - - // repeated .OauthSignInPB.MapEntry map = 1; - - - pub fn get_map(&self) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> { - &self.map - } - pub fn clear_map(&mut self) { - self.map.clear(); - } - - // Param is passed by value, moved - pub fn set_map(&mut self, v: ::std::collections::HashMap<::std::string::String, ::std::string::String>) { - self.map = v; - } - - // Mutable pointer to the field. - pub fn mut_map(&mut self) -> &mut ::std::collections::HashMap<::std::string::String, ::std::string::String> { - &mut self.map - } - - // Take field - pub fn take_map(&mut self) -> ::std::collections::HashMap<::std::string::String, ::std::string::String> { - ::std::mem::replace(&mut self.map, ::std::collections::HashMap::new()) - } - - // .AuthenticatorPB authenticator = 2; - - - pub fn get_authenticator(&self) -> AuthenticatorPB { - self.authenticator - } - pub fn clear_authenticator(&mut self) { - self.authenticator = AuthenticatorPB::Local; - } - - // Param is passed by value, moved - pub fn set_authenticator(&mut self, v: AuthenticatorPB) { - self.authenticator = v; - } -} - -impl ::protobuf::Message for OauthSignInPB { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_map_into::<::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeString>(wire_type, is, &mut self.map)?; - }, - 2 => { - ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.authenticator, 2, &mut self.unknown_fields)? - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - my_size += ::protobuf::rt::compute_map_size::<::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeString>(1, &self.map); - if self.authenticator != AuthenticatorPB::Local { - my_size += ::protobuf::rt::enum_size(2, self.authenticator); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - ::protobuf::rt::write_map_with_cached_sizes::<::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeString>(1, &self.map, os)?; - if self.authenticator != AuthenticatorPB::Local { - os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.authenticator))?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> OauthSignInPB { - OauthSignInPB::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_map_accessor::<_, ::protobuf::types::ProtobufTypeString, ::protobuf::types::ProtobufTypeString>( - "map", - |m: &OauthSignInPB| { &m.map }, - |m: &mut OauthSignInPB| { &mut m.map }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( - "authenticator", - |m: &OauthSignInPB| { &m.authenticator }, - |m: &mut OauthSignInPB| { &mut m.authenticator }, - )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "OauthSignInPB", - fields, - file_descriptor_proto() - ) - }) - } - - fn default_instance() -> &'static OauthSignInPB { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(OauthSignInPB::new) - } -} - -impl ::protobuf::Clear for OauthSignInPB { - fn clear(&mut self) { - self.map.clear(); - self.authenticator = AuthenticatorPB::Local; - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for OauthSignInPB { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for OauthSignInPB { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct AddUserPB { - // message fields - pub email: ::std::string::String, - pub password: ::std::string::String, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a AddUserPB { - fn default() -> &'a AddUserPB { - ::default_instance() - } -} - -impl AddUserPB { - pub fn new() -> AddUserPB { - ::std::default::Default::default() - } - - // string email = 1; - - - pub fn get_email(&self) -> &str { - &self.email - } - pub fn clear_email(&mut self) { - self.email.clear(); - } - - // Param is passed by value, moved - pub fn set_email(&mut self, v: ::std::string::String) { - self.email = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_email(&mut self) -> &mut ::std::string::String { - &mut self.email - } - - // Take field - pub fn take_email(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.email, ::std::string::String::new()) - } - - // string password = 2; - - - pub fn get_password(&self) -> &str { - &self.password - } - pub fn clear_password(&mut self) { - self.password.clear(); - } - - // Param is passed by value, moved - pub fn set_password(&mut self, v: ::std::string::String) { - self.password = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_password(&mut self) -> &mut ::std::string::String { - &mut self.password - } - - // Take field - pub fn take_password(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.password, ::std::string::String::new()) - } -} - -impl ::protobuf::Message for AddUserPB { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.email)?; - }, - 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.password)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.email.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.email); - } - if !self.password.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.password); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.email.is_empty() { - os.write_string(1, &self.email)?; - } - if !self.password.is_empty() { - os.write_string(2, &self.password)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> AddUserPB { - AddUserPB::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "email", - |m: &AddUserPB| { &m.email }, - |m: &mut AddUserPB| { &mut m.email }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "password", - |m: &AddUserPB| { &m.password }, - |m: &mut AddUserPB| { &mut m.password }, - )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "AddUserPB", - fields, - file_descriptor_proto() - ) - }) - } - - fn default_instance() -> &'static AddUserPB { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(AddUserPB::new) - } -} - -impl ::protobuf::Clear for AddUserPB { - fn clear(&mut self) { - self.email.clear(); - self.password.clear(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for AddUserPB { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for AddUserPB { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Message(self) - } -} - -#[derive(PartialEq,Clone,Default)] -pub struct UserSignInPB { - // message fields - pub email: ::std::string::String, - pub password: ::std::string::String, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a UserSignInPB { - fn default() -> &'a UserSignInPB { - ::default_instance() - } -} - -impl UserSignInPB { - pub fn new() -> UserSignInPB { - ::std::default::Default::default() - } - - // string email = 1; - - - pub fn get_email(&self) -> &str { - &self.email - } - pub fn clear_email(&mut self) { - self.email.clear(); - } - - // Param is passed by value, moved - pub fn set_email(&mut self, v: ::std::string::String) { - self.email = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_email(&mut self) -> &mut ::std::string::String { - &mut self.email - } - - // Take field - pub fn take_email(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.email, ::std::string::String::new()) - } - - // string password = 2; - - - pub fn get_password(&self) -> &str { - &self.password - } - pub fn clear_password(&mut self) { - self.password.clear(); - } - - // Param is passed by value, moved - pub fn set_password(&mut self, v: ::std::string::String) { - self.password = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_password(&mut self) -> &mut ::std::string::String { - &mut self.password - } - - // Take field - pub fn take_password(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.password, ::std::string::String::new()) - } -} - -impl ::protobuf::Message for UserSignInPB { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.email)?; - }, - 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.password)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.email.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.email); - } - if !self.password.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.password); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.email.is_empty() { - os.write_string(1, &self.email)?; - } - if !self.password.is_empty() { - os.write_string(2, &self.password)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> UserSignInPB { - UserSignInPB::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "email", - |m: &UserSignInPB| { &m.email }, - |m: &mut UserSignInPB| { &mut m.email }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "password", - |m: &UserSignInPB| { &m.password }, - |m: &mut UserSignInPB| { &mut m.password }, - )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "UserSignInPB", - fields, - file_descriptor_proto() - ) - }) - } - - fn default_instance() -> &'static UserSignInPB { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(UserSignInPB::new) - } -} - -impl ::protobuf::Clear for UserSignInPB { - fn clear(&mut self) { - self.email.clear(); - self.password.clear(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for UserSignInPB { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for UserSignInPB { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Message(self) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum AuthenticatorPB { - Local = 0, - Supabase = 1, - AppFlowyCloud = 2, -} - -impl ::protobuf::ProtobufEnum for AuthenticatorPB { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(AuthenticatorPB::Local), - 1 => ::std::option::Option::Some(AuthenticatorPB::Supabase), - 2 => ::std::option::Option::Some(AuthenticatorPB::AppFlowyCloud), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [AuthenticatorPB] = &[ - AuthenticatorPB::Local, - AuthenticatorPB::Supabase, - AuthenticatorPB::AppFlowyCloud, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new_pb_name::("AuthenticatorPB", file_descriptor_proto()) - }) - } -} - -impl ::std::marker::Copy for AuthenticatorPB { -} - -impl ::std::default::Default for AuthenticatorPB { - fn default() -> Self { - AuthenticatorPB::Local - } -} - -impl ::protobuf::reflect::ProtobufValue for AuthenticatorPB { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) - } -} - -static file_descriptor_proto_data: &'static [u8] = b"\ - \n\nauth.proto\"\xaa\x01\n\rOauthSignInPB\x12)\n\x03map\x18\x01\x20\x03(\ - \x0b2\x17.OauthSignInPB.MapEntryR\x03map\x126\n\rauthenticator\x18\x02\ - \x20\x01(\x0e2\x10.AuthenticatorPBR\rauthenticator\x1a6\n\x08MapEntry\ - \x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x14\n\x05value\x18\x02\ - \x20\x01(\tR\x05value:\x028\x01\"=\n\tAddUserPB\x12\x14\n\x05email\x18\ - \x01\x20\x01(\tR\x05email\x12\x1a\n\x08password\x18\x02\x20\x01(\tR\x08p\ - assword\"@\n\x0cUserSignInPB\x12\x14\n\x05email\x18\x01\x20\x01(\tR\x05e\ - mail\x12\x1a\n\x08password\x18\x02\x20\x01(\tR\x08password*=\n\x0fAuthen\ - ticatorPB\x12\t\n\x05Local\x10\0\x12\x0c\n\x08Supabase\x10\x01\x12\x11\n\ - \rAppFlowyCloud\x10\x02b\x06proto3\ -"; - -static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/event_map.rs b/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/event_map.rs deleted file mode 100644 index f3d5173833..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/event_map.rs +++ /dev/null @@ -1,95 +0,0 @@ -// This file is generated by rust-protobuf 2.28.0. Do not edit -// @generated - -// https://github.com/rust-lang/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy::all)] - -#![allow(unused_attributes)] -#![cfg_attr(rustfmt, rustfmt::skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unused_imports)] -#![allow(unused_results)] -//! Generated file from `event_map.proto` - -/// Generated files are compatible only with the same version -/// of protobuf runtime. -// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0; - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum UserWasmEvent { - OauthSignIn = 0, - AddUser = 1, - SignInPassword = 2, -} - -impl ::protobuf::ProtobufEnum for UserWasmEvent { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(UserWasmEvent::OauthSignIn), - 1 => ::std::option::Option::Some(UserWasmEvent::AddUser), - 2 => ::std::option::Option::Some(UserWasmEvent::SignInPassword), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [UserWasmEvent] = &[ - UserWasmEvent::OauthSignIn, - UserWasmEvent::AddUser, - UserWasmEvent::SignInPassword, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new_pb_name::("UserWasmEvent", file_descriptor_proto()) - }) - } -} - -impl ::std::marker::Copy for UserWasmEvent { -} - -impl ::std::default::Default for UserWasmEvent { - fn default() -> Self { - UserWasmEvent::OauthSignIn - } -} - -impl ::protobuf::reflect::ProtobufValue for UserWasmEvent { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) - } -} - -static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*A\n\rUserWasmEvent\x12\x0f\n\x0bOauthSignIn\x10\0\ - \x12\x0b\n\x07AddUser\x10\x01\x12\x12\n\x0eSignInPassword\x10\x02b\x06pr\ - oto3\ -"; - -static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) -} diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/mod.rs b/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/mod.rs deleted file mode 100644 index b79dbb09f6..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![cfg_attr(rustfmt, rustfmt::skip)] - #![allow(ambiguous_glob_reexports)] -// Auto-generated, do not edit - -mod event_map; -pub use event_map::*; - -mod auth; -pub use auth::*; - -mod user; -pub use user::*; diff --git a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/user.rs b/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/user.rs deleted file mode 100644 index 23d352aa0b..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-user/src/protobuf/user.rs +++ /dev/null @@ -1,661 +0,0 @@ -// This file is generated by rust-protobuf 2.28.0. Do not edit -// @generated - -// https://github.com/rust-lang/rust-clippy/issues/702 -#![allow(unknown_lints)] -#![allow(clippy::all)] - -#![allow(unused_attributes)] -#![cfg_attr(rustfmt, rustfmt::skip)] - -#![allow(box_pointers)] -#![allow(dead_code)] -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(trivial_casts)] -#![allow(unused_imports)] -#![allow(unused_results)] -//! Generated file from `user.proto` - -/// Generated files are compatible only with the same version -/// of protobuf runtime. -// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_28_0; - -#[derive(PartialEq,Clone,Default)] -pub struct UserProfilePB { - // message fields - pub id: i64, - pub email: ::std::string::String, - pub name: ::std::string::String, - pub token: ::std::string::String, - pub icon_url: ::std::string::String, - pub openai_key: ::std::string::String, - pub authenticator: super::auth::AuthenticatorPB, - pub encryption_sign: ::std::string::String, - pub workspace_id: ::std::string::String, - pub stability_ai_key: ::std::string::String, - pub ai_model: ::std::string::String, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a UserProfilePB { - fn default() -> &'a UserProfilePB { - ::default_instance() - } -} - -impl UserProfilePB { - pub fn new() -> UserProfilePB { - ::std::default::Default::default() - } - - // int64 id = 1; - - - pub fn get_id(&self) -> i64 { - self.id - } - pub fn clear_id(&mut self) { - self.id = 0; - } - - // Param is passed by value, moved - pub fn set_id(&mut self, v: i64) { - self.id = v; - } - - // string email = 2; - - - pub fn get_email(&self) -> &str { - &self.email - } - pub fn clear_email(&mut self) { - self.email.clear(); - } - - // Param is passed by value, moved - pub fn set_email(&mut self, v: ::std::string::String) { - self.email = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_email(&mut self) -> &mut ::std::string::String { - &mut self.email - } - - // Take field - pub fn take_email(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.email, ::std::string::String::new()) - } - - // string name = 3; - - - pub fn get_name(&self) -> &str { - &self.name - } - pub fn clear_name(&mut self) { - self.name.clear(); - } - - // Param is passed by value, moved - pub fn set_name(&mut self, v: ::std::string::String) { - self.name = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_name(&mut self) -> &mut ::std::string::String { - &mut self.name - } - - // Take field - pub fn take_name(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.name, ::std::string::String::new()) - } - - // string token = 4; - - - pub fn get_token(&self) -> &str { - &self.token - } - pub fn clear_token(&mut self) { - self.token.clear(); - } - - // Param is passed by value, moved - pub fn set_token(&mut self, v: ::std::string::String) { - self.token = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_token(&mut self) -> &mut ::std::string::String { - &mut self.token - } - - // Take field - pub fn take_token(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.token, ::std::string::String::new()) - } - - // string icon_url = 5; - - - pub fn get_icon_url(&self) -> &str { - &self.icon_url - } - pub fn clear_icon_url(&mut self) { - self.icon_url.clear(); - } - - // Param is passed by value, moved - pub fn set_icon_url(&mut self, v: ::std::string::String) { - self.icon_url = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_icon_url(&mut self) -> &mut ::std::string::String { - &mut self.icon_url - } - - // Take field - pub fn take_icon_url(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.icon_url, ::std::string::String::new()) - } - - // string openai_key = 6; - - - pub fn get_openai_key(&self) -> &str { - &self.openai_key - } - pub fn clear_openai_key(&mut self) { - self.openai_key.clear(); - } - - // Param is passed by value, moved - pub fn set_openai_key(&mut self, v: ::std::string::String) { - self.openai_key = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_openai_key(&mut self) -> &mut ::std::string::String { - &mut self.openai_key - } - - // Take field - pub fn take_openai_key(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.openai_key, ::std::string::String::new()) - } - - // .AuthenticatorPB authenticator = 7; - - - pub fn get_authenticator(&self) -> super::auth::AuthenticatorPB { - self.authenticator - } - pub fn clear_authenticator(&mut self) { - self.authenticator = super::auth::AuthenticatorPB::Local; - } - - // Param is passed by value, moved - pub fn set_authenticator(&mut self, v: super::auth::AuthenticatorPB) { - self.authenticator = v; - } - - // string encryption_sign = 8; - - - pub fn get_encryption_sign(&self) -> &str { - &self.encryption_sign - } - pub fn clear_encryption_sign(&mut self) { - self.encryption_sign.clear(); - } - - // Param is passed by value, moved - pub fn set_encryption_sign(&mut self, v: ::std::string::String) { - self.encryption_sign = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_encryption_sign(&mut self) -> &mut ::std::string::String { - &mut self.encryption_sign - } - - // Take field - pub fn take_encryption_sign(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.encryption_sign, ::std::string::String::new()) - } - - // string workspace_id = 9; - - - pub fn get_workspace_id(&self) -> &str { - &self.workspace_id - } - pub fn clear_workspace_id(&mut self) { - self.workspace_id.clear(); - } - - // Param is passed by value, moved - pub fn set_workspace_id(&mut self, v: ::std::string::String) { - self.workspace_id = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_workspace_id(&mut self) -> &mut ::std::string::String { - &mut self.workspace_id - } - - // Take field - pub fn take_workspace_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.workspace_id, ::std::string::String::new()) - } - - // string stability_ai_key = 10; - - - pub fn get_stability_ai_key(&self) -> &str { - &self.stability_ai_key - } - pub fn clear_stability_ai_key(&mut self) { - self.stability_ai_key.clear(); - } - - // Param is passed by value, moved - pub fn set_stability_ai_key(&mut self, v: ::std::string::String) { - self.stability_ai_key = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_stability_ai_key(&mut self) -> &mut ::std::string::String { - &mut self.stability_ai_key - } - - // Take field - pub fn take_stability_ai_key(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.stability_ai_key, ::std::string::String::new()) - } - - // string ai_model = 11; - - - pub fn get_ai_model(&self) -> &str { - &self.ai_model - } - pub fn clear_ai_model(&mut self) { - self.ai_model.clear(); - } - - // Param is passed by value, moved - pub fn set_ai_model(&mut self, v: ::std::string::String) { - self.ai_model = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_ai_model(&mut self) -> &mut ::std::string::String { - &mut self.ai_model - } - - // Take field - pub fn take_ai_model(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.ai_model, ::std::string::String::new()) - } -} - -impl ::protobuf::Message for UserProfilePB { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - let tmp = is.read_int64()?; - self.id = tmp; - }, - 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.email)?; - }, - 3 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?; - }, - 4 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.token)?; - }, - 5 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.icon_url)?; - }, - 6 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.openai_key)?; - }, - 7 => { - ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.authenticator, 7, &mut self.unknown_fields)? - }, - 8 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.encryption_sign)?; - }, - 9 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.workspace_id)?; - }, - 10 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.stability_ai_key)?; - }, - 11 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.ai_model)?; - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if self.id != 0 { - my_size += ::protobuf::rt::value_size(1, self.id, ::protobuf::wire_format::WireTypeVarint); - } - if !self.email.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.email); - } - if !self.name.is_empty() { - my_size += ::protobuf::rt::string_size(3, &self.name); - } - if !self.token.is_empty() { - my_size += ::protobuf::rt::string_size(4, &self.token); - } - if !self.icon_url.is_empty() { - my_size += ::protobuf::rt::string_size(5, &self.icon_url); - } - if !self.openai_key.is_empty() { - my_size += ::protobuf::rt::string_size(6, &self.openai_key); - } - if self.authenticator != super::auth::AuthenticatorPB::Local { - my_size += ::protobuf::rt::enum_size(7, self.authenticator); - } - if !self.encryption_sign.is_empty() { - my_size += ::protobuf::rt::string_size(8, &self.encryption_sign); - } - if !self.workspace_id.is_empty() { - my_size += ::protobuf::rt::string_size(9, &self.workspace_id); - } - if !self.stability_ai_key.is_empty() { - my_size += ::protobuf::rt::string_size(10, &self.stability_ai_key); - } - if !self.ai_model.is_empty() { - my_size += ::protobuf::rt::string_size(11, &self.ai_model); - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if self.id != 0 { - os.write_int64(1, self.id)?; - } - if !self.email.is_empty() { - os.write_string(2, &self.email)?; - } - if !self.name.is_empty() { - os.write_string(3, &self.name)?; - } - if !self.token.is_empty() { - os.write_string(4, &self.token)?; - } - if !self.icon_url.is_empty() { - os.write_string(5, &self.icon_url)?; - } - if !self.openai_key.is_empty() { - os.write_string(6, &self.openai_key)?; - } - if self.authenticator != super::auth::AuthenticatorPB::Local { - os.write_enum(7, ::protobuf::ProtobufEnum::value(&self.authenticator))?; - } - if !self.encryption_sign.is_empty() { - os.write_string(8, &self.encryption_sign)?; - } - if !self.workspace_id.is_empty() { - os.write_string(9, &self.workspace_id)?; - } - if !self.stability_ai_key.is_empty() { - os.write_string(10, &self.stability_ai_key)?; - } - if !self.ai_model.is_empty() { - os.write_string(11, &self.ai_model)?; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> UserProfilePB { - UserProfilePB::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>( - "id", - |m: &UserProfilePB| { &m.id }, - |m: &mut UserProfilePB| { &mut m.id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "email", - |m: &UserProfilePB| { &m.email }, - |m: &mut UserProfilePB| { &mut m.email }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "name", - |m: &UserProfilePB| { &m.name }, - |m: &mut UserProfilePB| { &mut m.name }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "token", - |m: &UserProfilePB| { &m.token }, - |m: &mut UserProfilePB| { &mut m.token }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "icon_url", - |m: &UserProfilePB| { &m.icon_url }, - |m: &mut UserProfilePB| { &mut m.icon_url }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "openai_key", - |m: &UserProfilePB| { &m.openai_key }, - |m: &mut UserProfilePB| { &mut m.openai_key }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( - "authenticator", - |m: &UserProfilePB| { &m.authenticator }, - |m: &mut UserProfilePB| { &mut m.authenticator }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "encryption_sign", - |m: &UserProfilePB| { &m.encryption_sign }, - |m: &mut UserProfilePB| { &mut m.encryption_sign }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "workspace_id", - |m: &UserProfilePB| { &m.workspace_id }, - |m: &mut UserProfilePB| { &mut m.workspace_id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "stability_ai_key", - |m: &UserProfilePB| { &m.stability_ai_key }, - |m: &mut UserProfilePB| { &mut m.stability_ai_key }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "ai_model", - |m: &UserProfilePB| { &m.ai_model }, - |m: &mut UserProfilePB| { &mut m.ai_model }, - )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "UserProfilePB", - fields, - file_descriptor_proto() - ) - }) - } - - fn default_instance() -> &'static UserProfilePB { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(UserProfilePB::new) - } -} - -impl ::protobuf::Clear for UserProfilePB { - fn clear(&mut self) { - self.id = 0; - self.email.clear(); - self.name.clear(); - self.token.clear(); - self.icon_url.clear(); - self.openai_key.clear(); - self.authenticator = super::auth::AuthenticatorPB::Local; - self.encryption_sign.clear(); - self.workspace_id.clear(); - self.stability_ai_key.clear(); - self.ai_model.clear(); - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for UserProfilePB { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for UserProfilePB { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Message(self) - } -} - -#[derive(Clone,PartialEq,Eq,Debug,Hash)] -pub enum EncryptionTypePB { - NoEncryption = 0, - Symmetric = 1, -} - -impl ::protobuf::ProtobufEnum for EncryptionTypePB { - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(EncryptionTypePB::NoEncryption), - 1 => ::std::option::Option::Some(EncryptionTypePB::Symmetric), - _ => ::std::option::Option::None - } - } - - fn values() -> &'static [Self] { - static values: &'static [EncryptionTypePB] = &[ - EncryptionTypePB::NoEncryption, - EncryptionTypePB::Symmetric, - ]; - values - } - - fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - ::protobuf::reflect::EnumDescriptor::new_pb_name::("EncryptionTypePB", file_descriptor_proto()) - }) - } -} - -impl ::std::marker::Copy for EncryptionTypePB { -} - -impl ::std::default::Default for EncryptionTypePB { - fn default() -> Self { - EncryptionTypePB::NoEncryption - } -} - -impl ::protobuf::reflect::ProtobufValue for EncryptionTypePB { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) - } -} - -static file_descriptor_proto_data: &'static [u8] = b"\ - \n\nuser.proto\x1a\nauth.proto\"\xe2\x02\n\rUserProfilePB\x12\x0e\n\x02i\ - d\x18\x01\x20\x01(\x03R\x02id\x12\x14\n\x05email\x18\x02\x20\x01(\tR\x05\ - email\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x14\n\x05token\ - \x18\x04\x20\x01(\tR\x05token\x12\x19\n\x08icon_url\x18\x05\x20\x01(\tR\ - \x07iconUrl\x12\x1d\n\nopenai_key\x18\x06\x20\x01(\tR\topenaiKey\x126\n\ - \rauthenticator\x18\x07\x20\x01(\x0e2\x10.AuthenticatorPBR\rauthenticato\ - r\x12'\n\x0fencryption_sign\x18\x08\x20\x01(\tR\x0eencryptionSign\x12!\n\ - \x0cworkspace_id\x18\t\x20\x01(\tR\x0bworkspaceId\x12(\n\x10stability_ai\ - _key\x18\n\x20\x01(\tR\x0estabilityAiKey\x12\x19\n\x08ai_model\x18\x0b\ - \x20\x01(\tR\x07aiModel*3\n\x10EncryptionTypePB\x12\x10\n\x0cNoEncryptio\ - n\x10\0\x12\r\n\tSymmetric\x10\x01b\x06proto3\ -"; - -static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; - -fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() -} - -pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/Cargo.toml b/frontend/appflowy_web/wasm-libs/af-wasm/Cargo.toml deleted file mode 100644 index c504233088..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/Cargo.toml +++ /dev/null @@ -1,58 +0,0 @@ -[package] -name = "af-wasm" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -wasm-bindgen = { version = "0.2.89" } -lazy_static = "1.4.0" -lib-dispatch = { workspace = true, features = ["use_serde"] } -parking_lot.workspace = true -tracing.workspace = true -tracing-core = { version = "0.1.32" } -tracing-wasm = "0.2.1" -serde.workspace = true -collab-integrate = { workspace = true } -tokio-stream.workspace = true - -af-user.workspace = true -af-persistence.workspace = true -flowy-notification = { workspace = true, features = ["web_ts"] } -flowy-user-pub = { workspace = true } -flowy-server = { workspace = true } -flowy-server-pub = { workspace = true } -flowy-error = { workspace = true, features = ["impl_from_dispatch_error", "web_ts"] } -flowy-document = { workspace = true, features = ["web_ts"] } -flowy-folder = { workspace = true, features = ["web_ts"] } -lib-infra = { workspace = true } -collab = { workspace = true } -web-sys = "0.3" -wasm-bindgen-futures.workspace = true -uuid.workspace = true -serde-wasm-bindgen.workspace = true -js-sys = "0.3.67" -anyhow = "1.0" - -# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size -# compared to the default allocator's ~10K. However, it is slower than the default -# allocator, so it's not enabled by default. -wee_alloc = { version = "0.4.2", optional = true } - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so it's only enabled -# in debug mode. -[target."cfg(debug_assertions)".dependencies] -console_error_panic_hook = "0.1.5" - -[dev-dependencies] -wasm-bindgen-test = "0.3.40" -tokio = { version = "1.0", features = ["sync"] } - -[features] -#default = ["wee_alloc"] -localhost_dev = [] \ No newline at end of file diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/core.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/core.rs deleted file mode 100644 index f841a13a73..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/core.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::deps_resolve::document_deps::DocumentDepsResolver; -use crate::deps_resolve::folder_deps::FolderDepsResolver; -use crate::integrate::server::ServerProviderWASM; -use af_persistence::store::AppFlowyWASMStore; -use af_user::authenticate_user::AuthenticateUser; -use af_user::manager::UserManager; -use collab_integrate::collab_builder::{AppFlowyCollabBuilder, WorkspaceCollabIntegrate}; -use flowy_document::manager::DocumentManager; -use flowy_error::FlowyResult; -use flowy_folder::manager::FolderManager; -use flowy_server_pub::af_cloud_config::AFCloudConfiguration; -use flowy_storage::ObjectStorageService; -use lib_dispatch::prelude::AFPluginDispatcher; -use lib_dispatch::runtime::AFPluginRuntime; -use std::rc::Rc; -use std::sync::Arc; - -pub struct AppFlowyWASMCore { - pub collab_builder: Arc, - pub event_dispatcher: Rc, - pub user_manager: Rc, - pub folder_manager: Rc, - pub document_manager: Rc, -} - -impl AppFlowyWASMCore { - pub async fn new(device_id: &str, cloud_config: AFCloudConfiguration) -> FlowyResult { - let runtime = Arc::new(AFPluginRuntime::new().unwrap()); - let server_provider = Rc::new(ServerProviderWASM::new(device_id, cloud_config)); - let store = Rc::new(AppFlowyWASMStore::new().await?); - let auth_user = Rc::new(AuthenticateUser::new(store.clone()).await?); - let collab_builder = Arc::new(AppFlowyCollabBuilder::new( - device_id.to_string(), - server_provider.clone(), - WorkspaceCollabIntegrateImpl(auth_user.clone()), - )); - - let document_manager = DocumentDepsResolver::resolve( - Rc::downgrade(&auth_user), - collab_builder.clone(), - server_provider.clone(), - Rc::downgrade(&(server_provider.clone() as Rc)), - ) - .await; - - let folder_manager = FolderDepsResolver::resolve( - Rc::downgrade(&auth_user), - document_manager.clone(), - collab_builder.clone(), - server_provider.clone(), - ) - .await; - - let user_manager = Rc::new( - UserManager::new( - device_id, - store, - server_provider.clone(), - auth_user, - Arc::downgrade(&collab_builder), - ) - .await?, - ); - - let event_dispatcher = Rc::new(AFPluginDispatcher::new( - runtime, - vec![af_user::event_map::init(Rc::downgrade(&user_manager))], - )); - Ok(Self { - collab_builder, - event_dispatcher, - user_manager, - folder_manager, - document_manager, - }) - } -} - -struct WorkspaceCollabIntegrateImpl(Rc); -impl WorkspaceCollabIntegrate for WorkspaceCollabIntegrateImpl { - fn workspace_id(&self) -> Result { - let workspace_id = self.0.workspace_id()?; - Ok(workspace_id) - } - - fn device_id(&self) -> Result { - Ok("fake device id".to_string()) - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/document_deps.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/document_deps.rs deleted file mode 100644 index 3580bb762f..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/document_deps.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::integrate::server::ServerProviderWASM; -use af_user::authenticate_user::AuthenticateUser; -use collab_integrate::collab_builder::AppFlowyCollabBuilder; -use flowy_document::manager::DocumentManager; -use flowy_storage::ObjectStorageService; -use std::rc::{Rc, Weak}; -use std::sync::Arc; - -pub struct DocumentDepsResolver; -impl DocumentDepsResolver { - pub async fn resolve( - authenticate_user: Weak, - collab_builder: Arc, - server_provider: Rc, - storage_service: Weak, - ) -> Rc { - todo!() - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/folder_deps.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/folder_deps.rs deleted file mode 100644 index e291b5551a..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/folder_deps.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::integrate::server::ServerProviderWASM; -use af_user::authenticate_user::AuthenticateUser; -use collab_integrate::collab_builder::AppFlowyCollabBuilder; -use flowy_document::manager::DocumentManager; -use flowy_folder::manager::FolderManager; -use std::rc::{Rc, Weak}; -use std::sync::Arc; - -pub struct FolderDepsResolver; - -impl FolderDepsResolver { - pub async fn resolve( - authenticate_user: Weak, - document_manager: Rc, - collab_builder: Arc, - server_provider: Rc, - ) -> Rc { - todo!() - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/mod.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/mod.rs deleted file mode 100644 index b210522360..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/deps_resolve/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod document_deps; -pub(crate) mod folder_deps; diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/mod.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/mod.rs deleted file mode 100644 index 74f47ad347..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod server; diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/server.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/server.rs deleted file mode 100644 index 03ab3f5364..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/integrate/server.rs +++ /dev/null @@ -1,126 +0,0 @@ -use collab::preclude::CollabPlugin; -use collab_integrate::collab_builder::{ - CollabCloudPluginProvider, CollabPluginProviderContext, CollabPluginProviderType, -}; -use flowy_error::FlowyError; -use flowy_server::af_cloud::AppFlowyCloudServer; -use flowy_server::AppFlowyServer; -use flowy_server_pub::af_cloud_config::AFCloudConfiguration; -use flowy_storage::{ObjectIdentity, ObjectStorageService, ObjectValue}; -use flowy_user_pub::cloud::{UserCloudService, UserCloudServiceProvider}; -use flowy_user_pub::entities::{Authenticator, UserTokenState}; -use lib_infra::future::{to_fut, Fut, FutureResult}; -use parking_lot::RwLock; -use std::rc::Rc; -use std::sync::Arc; -use tokio_stream::wrappers::WatchStream; -use tracing::{info, warn}; - -pub struct ServerProviderWASM { - device_id: String, - config: AFCloudConfiguration, - server: RwLock>>, -} - -impl ServerProviderWASM { - pub fn new(device_id: &str, config: AFCloudConfiguration) -> Self { - info!("Server config: {}", config); - Self { - device_id: device_id.to_string(), - server: RwLock::new(Default::default()), - config, - } - } - - pub fn get_server(&self) -> Rc { - let server = self.server.read().as_ref().cloned(); - match server { - Some(server) => server, - None => { - let server = Rc::new(AppFlowyCloudServer::new( - self.config.clone(), - true, - self.device_id.clone(), - "0.0.1", - )); - *self.server.write() = Some(server.clone()); - server - }, - } - } -} - -impl CollabCloudPluginProvider for ServerProviderWASM { - fn provider_type(&self) -> CollabPluginProviderType { - CollabPluginProviderType::AppFlowyCloud - } - - fn get_plugins(&self, _context: CollabPluginProviderContext) -> Vec> { - vec![] - } - - fn is_sync_enabled(&self) -> bool { - true - } -} - -impl UserCloudServiceProvider for ServerProviderWASM { - fn set_token(&self, token: &str) -> Result<(), FlowyError> { - self.get_server().set_token(token)?; - Ok(()) - } - - fn set_ai_model(&self, ai_model: &str) -> Result<(), FlowyError> { - Ok(()) - } - - fn subscribe_token_state(&self) -> Option> { - self.get_server().subscribe_token_state() - } - - fn set_enable_sync(&self, _uid: i64, _enable_sync: bool) { - warn!("enable sync is not supported in wasm") - } - - fn set_user_authenticator(&self, _authenticator: &Authenticator) { - warn!("set user authenticator is not supported in wasm") - } - - fn get_user_authenticator(&self) -> Authenticator { - Authenticator::AppFlowyCloud - } - - fn set_network_reachable(&self, _reachable: bool) { - warn!("set network reachable is not supported in wasm") - } - - fn set_encrypt_secret(&self, _secret: String) { - warn!("set encrypt secret is not supported in wasm") - } - - fn get_user_service(&self) -> Result, FlowyError> { - Ok(self.get_server().user_service()) - } - - fn service_url(&self) -> String { - self.config.base_url.clone() - } -} - -impl ObjectStorageService for ServerProviderWASM { - fn get_object_url(&self, object_id: ObjectIdentity) -> FutureResult { - todo!() - } - - fn put_object(&self, url: String, object_value: ObjectValue) -> FutureResult<(), FlowyError> { - todo!() - } - - fn delete_object(&self, url: String) -> FutureResult<(), FlowyError> { - todo!() - } - - fn get_object(&self, url: String) -> FutureResult { - todo!() - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/lib.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/lib.rs deleted file mode 100644 index efe3855f28..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/lib.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::notification::TSNotificationSender; -use flowy_notification::{register_notification_sender, unregister_all_notification_sender}; -use std::cell::RefCell; -use std::rc::Rc; - -pub mod core; -mod deps_resolve; -mod integrate; -pub mod notification; - -use crate::core::AppFlowyWASMCore; -use lazy_static::lazy_static; -use lib_dispatch::prelude::{ - AFPluginDispatcher, AFPluginEventResponse, AFPluginRequest, StatusCode, -}; - -use flowy_server_pub::af_cloud_config::AFCloudConfiguration; -use tracing::{error, info}; -use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; -use wasm_bindgen_futures::{future_to_promise, js_sys}; - -lazy_static! { - static ref APPFLOWY_CORE: RefCellAppFlowyCore = RefCellAppFlowyCore::new(); -} - -#[cfg(feature = "wee_alloc")] -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_namespace = console)] - pub fn log(s: &str); - #[wasm_bindgen(js_namespace = window)] - fn onFlowyNotify(event_name: &str, payload: JsValue); -} -#[wasm_bindgen] -pub fn init_tracing_log() { - tracing_wasm::set_as_global_default(); -} - -#[wasm_bindgen] -pub fn init_wasm_core() -> js_sys::Promise { - // It's disabled in release mode so it doesn't bloat up the file size. - #[cfg(debug_assertions)] - console_error_panic_hook::set_once(); - - #[cfg(feature = "localhost_dev")] - let config = AFCloudConfiguration { - base_url: "http://localhost".to_string(), - ws_base_url: "ws://localhost/ws/v1".to_string(), - gotrue_url: "http://localhost/gotrue".to_string(), - }; - - #[cfg(not(feature = "localhost_dev"))] - let config = AFCloudConfiguration { - base_url: "https://beta.appflowy.cloud".to_string(), - ws_base_url: "wss://beta.appflowy.cloud/ws/v1".to_string(), - gotrue_url: "https://beta.appflowy.cloud/gotrue".to_string(), - }; - - let future = async move { - if let Ok(core) = AppFlowyWASMCore::new("device_id", config).await { - *APPFLOWY_CORE.0.borrow_mut() = Some(core); - info!("🔥🔥🔥Initialized AppFlowyWASMCore"); - } else { - error!("Failed to initialize AppFlowyWASMCore") - } - Ok(JsValue::from_str("")) - }; - future_to_promise(future) -} - -#[wasm_bindgen] -pub fn async_event(name: String, payload: Vec) -> js_sys::Promise { - if let Some(dispatcher) = APPFLOWY_CORE.dispatcher() { - let future = async move { - let request = WasmRequest::new(name, payload); - let event_resp = - AFPluginDispatcher::boxed_async_send_with_callback(dispatcher.as_ref(), request, |_| { - Box::pin(async {}) - }) - .await; - - let response = WasmResponse::from(event_resp); - serde_wasm_bindgen::to_value(&response).map_err(error_response) - }; - - future_to_promise(future) - } else { - future_to_promise(async { Err(JsValue::from_str("Dispatcher is not initialized")) }) - } -} - -#[wasm_bindgen] -pub fn register_listener() { - unregister_all_notification_sender(); - register_notification_sender(TSNotificationSender::new()); -} - -pub fn on_event(event_name: &str, args: JsValue) { - onFlowyNotify(event_name, args); -} - -struct RefCellAppFlowyCore(RefCell>); - -/// safety: -/// In a WebAssembly, implement the Sync for RefCellAppFlowyCore is safety -/// since WASM currently operates in a single-threaded environment. -unsafe impl Sync for RefCellAppFlowyCore {} - -impl RefCellAppFlowyCore { - fn new() -> Self { - Self(RefCell::new(None)) - } - - fn dispatcher(&self) -> Option> { - self - .0 - .borrow() - .as_ref() - .map(|core| core.event_dispatcher.clone()) - } -} - -fn error_response(error: serde_wasm_bindgen::Error) -> JsValue { - error!("Error: {}", error); - serde_wasm_bindgen::to_value(&WasmResponse::error(error.to_string())).unwrap() -} - -pub struct WasmRequest { - name: String, - payload: Vec, -} - -impl WasmRequest { - pub fn new(name: String, payload: Vec) -> Self { - Self { name, payload } - } -} - -impl From for AFPluginRequest { - fn from(request: WasmRequest) -> Self { - AFPluginRequest::new(request.name).payload(request.payload) - } -} - -#[derive(serde::Serialize)] -pub struct WasmResponse { - pub code: i8, - pub payload: Vec, -} -impl WasmResponse { - pub fn error(msg: String) -> Self { - Self { - code: StatusCode::Err as i8, - payload: msg.into_bytes(), - } - } -} - -impl From for WasmResponse { - fn from(response: AFPluginEventResponse) -> Self { - Self { - code: response.status_code as i8, - payload: response.payload.to_vec(), - } - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/src/notification.rs b/frontend/appflowy_web/wasm-libs/af-wasm/src/notification.rs deleted file mode 100644 index d329ee0cb1..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/src/notification.rs +++ /dev/null @@ -1,19 +0,0 @@ -use flowy_notification::entities::SubscribeObject; -use flowy_notification::NotificationSender; - -pub const AF_NOTIFICATION: &str = "af-notification"; - -pub struct TSNotificationSender {} - -impl TSNotificationSender { - pub(crate) fn new() -> Self { - TSNotificationSender {} - } -} - -impl NotificationSender for TSNotificationSender { - fn send_subject(&self, _subject: SubscribeObject) -> Result<(), String> { - // on_event(AF_NOTIFICATION, serde_wasm_bindgen::to_value(&subject).unwrap_or(JsValue::UNDEFINED)); - Ok(()) - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/tests/main.rs b/frontend/appflowy_web/wasm-libs/af-wasm/tests/main.rs deleted file mode 100644 index 0498e45195..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/tests/main.rs +++ /dev/null @@ -1,4 +0,0 @@ -use wasm_bindgen_test::wasm_bindgen_test_configure; -wasm_bindgen_test_configure!(run_in_browser); -mod user; -pub(crate) mod util; diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/tests/user/event_test.rs b/frontend/appflowy_web/wasm-libs/af-wasm/tests/user/event_test.rs deleted file mode 100644 index d053043e7e..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/tests/user/event_test.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::util::tester::{unique_email, WASMEventTester}; -use wasm_bindgen_test::wasm_bindgen_test; - -#[wasm_bindgen_test] -async fn sign_up_event_test() { - let tester = WASMEventTester::new().await; - let email = unique_email(); - let user_profile = tester.sign_in_with_email(&email).await.unwrap(); - assert_eq!(user_profile.email, email); -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/tests/user/mod.rs b/frontend/appflowy_web/wasm-libs/af-wasm/tests/user/mod.rs deleted file mode 100644 index 83ac8063ea..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/tests/user/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod event_test; diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/event_builder.rs b/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/event_builder.rs deleted file mode 100644 index 99185a6837..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/event_builder.rs +++ /dev/null @@ -1,132 +0,0 @@ -use af_wasm::core::AppFlowyWASMCore; -use flowy_error::{internal_error, FlowyError}; -use std::rc::Rc; -use std::{ - convert::TryFrom, - fmt::{Debug, Display}, - hash::Hash, - sync::Arc, -}; - -use lib_dispatch::prelude::{ - AFPluginDispatcher, AFPluginEventResponse, AFPluginFromBytes, AFPluginRequest, ToBytes, *, -}; - -#[derive(Clone)] -pub struct EventBuilder { - context: TestContext, -} - -impl EventBuilder { - pub fn new(core: Arc) -> Self { - Self { - context: TestContext::new(core), - } - } - - pub fn payload

(mut self, payload: P) -> Self - where - P: ToBytes, - { - match payload.into_bytes() { - Ok(bytes) => { - let module_request = self.take_request(); - self.context.request = Some(module_request.payload(bytes)) - }, - Err(e) => { - tracing::error!("Set payload failed: {:?}", e); - }, - } - self - } - - pub fn event(mut self, event: Event) -> Self - where - Event: Eq + Hash + Debug + Clone + Display, - { - self.context.request = Some(AFPluginRequest::new(event)); - self - } - - pub async fn async_send(mut self) -> Self { - let request = self.take_request(); - let resp = AFPluginDispatcher::async_send(self.dispatch().as_ref(), request).await; - self.context.response = Some(resp); - self - } - - pub fn parse(self) -> R - where - R: AFPluginFromBytes, - { - let response = self.get_response(); - match response.clone().parse::() { - Ok(Ok(data)) => data, - Ok(Err(e)) => { - panic!( - "Parser {:?} failed: {:?}, response {:?}", - std::any::type_name::(), - e, - response - ) - }, - Err(e) => panic!( - "Dispatch {:?} failed: {:?}, response {:?}", - std::any::type_name::(), - e, - response - ), - } - } - - #[allow(dead_code)] - pub fn try_parse(self) -> Result - where - R: AFPluginFromBytes, - { - let response = self.get_response(); - response.parse::().map_err(internal_error)? - } - - #[allow(dead_code)] - pub fn error(self) -> Option { - let response = self.get_response(); - >::try_from(response.payload) - .ok() - .map(|data| data.into_inner()) - } - - fn dispatch(&self) -> &Rc { - &self.context.sdk.event_dispatcher - } - - fn get_response(&self) -> AFPluginEventResponse { - self - .context - .response - .as_ref() - .expect("must call sync_send/async_send first") - .clone() - } - - fn take_request(&mut self) -> AFPluginRequest { - self.context.request.take().expect("must call event first") - } -} - -#[derive(Clone)] -pub struct TestContext { - pub sdk: Arc, - request: Option, - response: Option, -} - -impl TestContext { - pub fn new(sdk: Arc) -> Self { - Self { - sdk, - request: None, - response: None, - } - } -} diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/mod.rs b/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/mod.rs deleted file mode 100644 index 8458398ffd..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod event_builder; -pub mod tester; diff --git a/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/tester.rs b/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/tester.rs deleted file mode 100644 index 5142d8012f..0000000000 --- a/frontend/appflowy_web/wasm-libs/af-wasm/tests/util/tester.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::util::event_builder::EventBuilder; -use af_user::entities::*; -use af_user::event_map::UserWasmEvent::*; -use af_wasm::core::AppFlowyWASMCore; -use flowy_error::FlowyResult; - -use flowy_server_pub::af_cloud_config::AFCloudConfiguration; -use parking_lot::Once; - -use flowy_document::deps::DocumentData; -use flowy_document::entities::{CreateDocumentPayloadPB, DocumentDataPB, OpenDocumentPayloadPB}; -use flowy_document::event_map::DocumentEvent; -use flowy_folder::entities::{CreateViewPayloadPB, ViewLayoutPB, ViewPB}; -use flowy_folder::event_map::FolderEvent; -use std::sync::Arc; -use uuid::Uuid; - -pub struct WASMEventTester { - core: Arc, -} - -impl WASMEventTester { - pub async fn new() -> Self { - setup_log(); - let config = AFCloudConfiguration { - base_url: "http://localhost".to_string(), - ws_base_url: "ws://localhost/ws/v1".to_string(), - gotrue_url: "http://localhost/gotrue".to_string(), - }; - let core = Arc::new(AppFlowyWASMCore::new("device_id", config).await.unwrap()); - Self { core } - } - - pub async fn sign_in_with_email(&self, email: &str) -> FlowyResult { - let email = email.to_string(); - let password = "AppFlowy!2024".to_string(); - let payload = AddUserPB { - email: email.clone(), - password: password.clone(), - }; - EventBuilder::new(self.core.clone()) - .event(AddUser) - .payload(payload) - .async_send() - .await; - - let payload = UserSignInPB { email, password }; - let user_profile = EventBuilder::new(self.core.clone()) - .event(SignInPassword) - .payload(payload) - .async_send() - .await - .parse::(); - Ok(user_profile) - } - - pub async fn create_and_open_document(&self, parent_id: &str) -> ViewPB { - let payload = CreateViewPayloadPB { - parent_view_id: parent_id.to_string(), - name, - desc: "".to_string(), - thumbnail: None, - layout: ViewLayoutPB::Document, - initial_data, - meta: Default::default(), - set_as_current: true, - index: None, - }; - let view = self - .event_builder() - .event(FolderEvent::CreateView) - .payload(payload) - .async_send() - .await - .parse::(); - - let payload = OpenDocumentPayloadPB { - document_id: view.id.clone(), - }; - - let _ = self - .event_builder() - .event(DocumentEvent::OpenDocument) - .payload(payload) - .async_send() - .await - .parse::(); - view - } - - fn event_builder(&self) -> EventBuilder { - EventBuilder::new(self.core.clone()) - } -} - -pub fn unique_email() -> String { - format!("{}@appflowy.io", Uuid::new_v4()) -} - -pub fn setup_log() { - static START: Once = Once::new(); - START.call_once(|| { - tracing_wasm::set_as_global_default(); - }); -} diff --git a/frontend/appflowy_web/wasm-libs/rust-toolchain.toml b/frontend/appflowy_web/wasm-libs/rust-toolchain.toml deleted file mode 100644 index 6f14058b2e..0000000000 --- a/frontend/appflowy_web/wasm-libs/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "1.77.2" diff --git a/frontend/appflowy_web/wasm-libs/rustfmt.toml b/frontend/appflowy_web/wasm-libs/rustfmt.toml deleted file mode 100644 index 5cb0d67ee5..0000000000 --- a/frontend/appflowy_web/wasm-libs/rustfmt.toml +++ /dev/null @@ -1,12 +0,0 @@ -# https://rust-lang.github.io/rustfmt/?version=master&search= -max_width = 100 -tab_spaces = 2 -newline_style = "Auto" -match_block_trailing_comma = true -use_field_init_shorthand = true -use_try_shorthand = true -reorder_imports = true -reorder_modules = true -remove_nested_parens = true -merge_derives = true -edition = "2021" \ No newline at end of file diff --git a/frontend/rust-lib/build-tool/flowy-codegen/src/lib.rs b/frontend/rust-lib/build-tool/flowy-codegen/src/lib.rs index 768147c10a..2df1e98ee9 100644 --- a/frontend/rust-lib/build-tool/flowy-codegen/src/lib.rs +++ b/frontend/rust-lib/build-tool/flowy-codegen/src/lib.rs @@ -23,7 +23,6 @@ pub struct ProtoCache { pub enum Project { Tauri, TauriApp, - Web { relative_path: String }, Native, } @@ -34,7 +33,6 @@ impl Project { Project::TauriApp => { "appflowy_web_app/src/application/services/tauri-services/backend".to_string() }, - Project::Web { .. } => "appflowy_web/src/services/backend".to_string(), Project::Native => panic!("Native project is not supported yet."), } } @@ -42,7 +40,6 @@ impl Project { pub fn event_root(&self) -> String { match self { Project::Tauri | Project::TauriApp => "../../".to_string(), - Project::Web { relative_path } => relative_path.to_string(), Project::Native => panic!("Native project is not supported yet."), } } @@ -50,7 +47,6 @@ impl Project { pub fn model_root(&self) -> String { match self { Project::Tauri | Project::TauriApp => "../../".to_string(), - Project::Web { relative_path } => relative_path.to_string(), Project::Native => panic!("Native project is not supported yet."), } } @@ -62,13 +58,6 @@ impl Project { import { Ok, Err, Result } from "ts-results"; import { invoke } from "@tauri-apps/api/tauri"; import * as pb from "../.."; -"# - .to_string(), - Project::Web { .. } => r#" -/// Auto generate. Do not edit -import { Ok, Err, Result } from "ts-results"; -import { invoke } from "@/application/app.ts"; -import * as pb from "../.."; "# .to_string(), Project::Native => panic!("Native project is not supported yet."), diff --git a/frontend/scripts/makefile/web.toml b/frontend/scripts/makefile/web.toml index 40162c9e6c..1d40d9da17 100644 --- a/frontend/scripts/makefile/web.toml +++ b/frontend/scripts/makefile/web.toml @@ -1,4 +1,3 @@ - [tasks.wasm_build] script_runner = "bash" script = [ @@ -29,15 +28,6 @@ run_task = { name = [ "rm_pkg", ] } - -[tasks.rm_pkg] -private = true -script = [""" -cd ${WEB_LIB_PATH} -rimraf dist pkg -"""] -script_runner = "@duckscript" - [tasks.rm_web_generated_protobuf_files] private = true script = [""" diff --git a/frontend/scripts/tool/update_client_api_rev.sh b/frontend/scripts/tool/update_client_api_rev.sh index 1af8987922..ea16622f6f 100755 --- a/frontend/scripts/tool/update_client_api_rev.sh +++ b/frontend/scripts/tool/update_client_api_rev.sh @@ -8,7 +8,7 @@ fi NEW_REV="$1" echo "New revision: $NEW_REV" -directories=("rust-lib" "appflowy_tauri/src-tauri" "appflowy_web/wasm-libs" "appflowy_web_app/src-tauri") +directories=("rust-lib" "appflowy_tauri/src-tauri" "appflowy_web_app/src-tauri") for dir in "${directories[@]}"; do echo "Updating $dir" diff --git a/frontend/scripts/tool/update_collab_rev.sh b/frontend/scripts/tool/update_collab_rev.sh index 26076df248..fabc71160a 100755 --- a/frontend/scripts/tool/update_collab_rev.sh +++ b/frontend/scripts/tool/update_collab_rev.sh @@ -8,7 +8,7 @@ fi NEW_REV="$1" echo "New revision: $NEW_REV" -directories=("rust-lib" "appflowy_tauri/src-tauri" "appflowy_web/wasm-libs" "appflowy_web_app/src-tauri") +directories=("rust-lib" "appflowy_tauri/src-tauri" "appflowy_web_app/src-tauri") for dir in "${directories[@]}"; do echo "Updating $dir" From f9fba6b561c53a1641247af8834faca3a23739bc Mon Sep 17 00:00:00 2001 From: Stefan Weiberg <2744377+suntorytimed@users.noreply.github.com> Date: Tue, 2 Jul 2024 03:44:16 +0200 Subject: [PATCH 07/12] chore: update German translations (#5640) --- frontend/resources/translations/ar-SA.json | 2 +- frontend/resources/translations/ca-ES.json | 2 +- frontend/resources/translations/ckb-KU.json | 2 +- frontend/resources/translations/cs-CZ.json | 2 +- frontend/resources/translations/de-DE.json | 8 +++++++- frontend/resources/translations/es-VE.json | 2 +- frontend/resources/translations/eu-ES.json | 2 +- frontend/resources/translations/fa.json | 2 +- frontend/resources/translations/fr-CA.json | 2 +- frontend/resources/translations/fr-FR.json | 2 +- frontend/resources/translations/hu-HU.json | 2 +- frontend/resources/translations/id-ID.json | 2 +- frontend/resources/translations/it-IT.json | 2 +- frontend/resources/translations/ja-JP.json | 2 +- frontend/resources/translations/ko-KR.json | 2 +- frontend/resources/translations/pl-PL.json | 2 +- frontend/resources/translations/pt-BR.json | 2 +- frontend/resources/translations/pt-PT.json | 2 +- frontend/resources/translations/ru-RU.json | 2 +- frontend/resources/translations/sv-SE.json | 2 +- frontend/resources/translations/tr-TR.json | 2 +- frontend/resources/translations/uk-UA.json | 2 +- frontend/resources/translations/vi-VN.json | 2 +- frontend/resources/translations/vi.json | 2 +- frontend/resources/translations/zh-CN.json | 2 +- frontend/resources/translations/zh-TW.json | 2 +- 26 files changed, 32 insertions(+), 26 deletions(-) diff --git a/frontend/resources/translations/ar-SA.json b/frontend/resources/translations/ar-SA.json index 1e1bc31ae6..3cbc7c5f08 100644 --- a/frontend/resources/translations/ar-SA.json +++ b/frontend/resources/translations/ar-SA.json @@ -1169,4 +1169,4 @@ "addField": "إضافة حقل", "userIcon": "رمز المستخدم" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/ca-ES.json b/frontend/resources/translations/ca-ES.json index 1612d60dbc..646a9f7ce8 100644 --- a/frontend/resources/translations/ca-ES.json +++ b/frontend/resources/translations/ca-ES.json @@ -812,4 +812,4 @@ "deleteContentTitle": "Esteu segur que voleu suprimir {pageType}?", "deleteContentCaption": "si suprimiu aquest {pageType}, podeu restaurar-lo des de la paperera." } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/ckb-KU.json b/frontend/resources/translations/ckb-KU.json index a7dd404f90..fb52a87e4e 100644 --- a/frontend/resources/translations/ckb-KU.json +++ b/frontend/resources/translations/ckb-KU.json @@ -946,4 +946,4 @@ "frequentlyUsed": "زۆرجار بەکارت هێناوە" } } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/cs-CZ.json b/frontend/resources/translations/cs-CZ.json index d56e74d530..978281190c 100644 --- a/frontend/resources/translations/cs-CZ.json +++ b/frontend/resources/translations/cs-CZ.json @@ -1094,4 +1094,4 @@ "font": "Písmo", "actions": "Příkazy" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/de-DE.json b/frontend/resources/translations/de-DE.json index 7f651ffbac..cfed21a8d9 100644 --- a/frontend/resources/translations/de-DE.json +++ b/frontend/resources/translations/de-DE.json @@ -509,6 +509,11 @@ "description": "Durch das Leeren des Caches werden Bilder und Schriftarten beim Laden erneut heruntergeladen. Deine Daten werden durch diese Aktion weder entfernt noch geändert.", "successHint": "Cache geleert!" } + }, + "data": { + "fixYourData": "Deine Daten korrigieren", + "fixButton": "Korrigieren", + "fixYourDataDescription": "Wenn du Probleme mit deinen Daten hast, kannst du hier versuchen, diese zu beheben." } }, "shortcutsPage": { @@ -651,6 +656,7 @@ "proBadge": "Pro", "memberProToggle": "Unbegrenzte Mitgliederzahl", "guestCollabToggle": "10 Gastmitarbeiter", + "storageUnlimited": "Unbegrenzter Speicherplatz mit deinem Pro-Plan", "aiCredit": { "title": "@:appName KI-Guthaben hinzufügen", "price": "5 $", @@ -2063,4 +2069,4 @@ "quicklySwitch": "Schnell zur nächsten Domäne wechseln", "duplicate": "Domäne duplizieren" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/es-VE.json b/frontend/resources/translations/es-VE.json index bed7a3f9ff..74b20955a4 100644 --- a/frontend/resources/translations/es-VE.json +++ b/frontend/resources/translations/es-VE.json @@ -1536,4 +1536,4 @@ "betaTooltip": "Actualmente solo admitimos la búsqueda de páginas.", "fromTrashHint": "De la papelera" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/eu-ES.json b/frontend/resources/translations/eu-ES.json index e7029a0d38..a070a59c54 100644 --- a/frontend/resources/translations/eu-ES.json +++ b/frontend/resources/translations/eu-ES.json @@ -601,4 +601,4 @@ "deleteContentTitle": "Ziur {pageType} ezabatu nahi duzula?", "deleteContentCaption": "{pageType} hau ezabatzen baduzu, zaborrontzitik leheneratu dezakezu." } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/fa.json b/frontend/resources/translations/fa.json index 147bca02b6..1f9b3526de 100644 --- a/frontend/resources/translations/fa.json +++ b/frontend/resources/translations/fa.json @@ -674,4 +674,4 @@ "frequentlyUsed": "استفاده‌شده" } } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/fr-CA.json b/frontend/resources/translations/fr-CA.json index 5d2f52fe67..e0e7310610 100644 --- a/frontend/resources/translations/fr-CA.json +++ b/frontend/resources/translations/fr-CA.json @@ -1262,4 +1262,4 @@ "userIcon": "Icône utilisateur" }, "noLogFiles": "Il n'y a pas de log" -} \ No newline at end of file +} diff --git a/frontend/resources/translations/fr-FR.json b/frontend/resources/translations/fr-FR.json index 1db313a9ee..b5b567d9de 100644 --- a/frontend/resources/translations/fr-FR.json +++ b/frontend/resources/translations/fr-FR.json @@ -1573,4 +1573,4 @@ "loadingTooltip": "Nous recherchons des résultats...", "betaTooltip": "Nous ne prenons actuellement en charge que la recherche de pages" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/hu-HU.json b/frontend/resources/translations/hu-HU.json index 1a60a1c6f5..7c25d96d14 100644 --- a/frontend/resources/translations/hu-HU.json +++ b/frontend/resources/translations/hu-HU.json @@ -599,4 +599,4 @@ "deleteContentTitle": "Biztosan törli a következőt: {pageType}?", "deleteContentCaption": "ha törli ezt a {pageType} oldalt, visszaállíthatja a kukából." } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/id-ID.json b/frontend/resources/translations/id-ID.json index da3598d11a..a238987da5 100644 --- a/frontend/resources/translations/id-ID.json +++ b/frontend/resources/translations/id-ID.json @@ -1022,4 +1022,4 @@ "noFavorite": "Tidak ada halaman favorit", "noFavoriteHintText": "Geser halaman ke kiri untuk menambahkannya ke favorit Anda" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/it-IT.json b/frontend/resources/translations/it-IT.json index 4cc563bc6e..0933967115 100644 --- a/frontend/resources/translations/it-IT.json +++ b/frontend/resources/translations/it-IT.json @@ -1262,4 +1262,4 @@ "userIcon": "Icona utente" }, "noLogFiles": "Non ci sono file di log" -} \ No newline at end of file +} diff --git a/frontend/resources/translations/ja-JP.json b/frontend/resources/translations/ja-JP.json index 79fd2f4dc9..538619cc57 100644 --- a/frontend/resources/translations/ja-JP.json +++ b/frontend/resources/translations/ja-JP.json @@ -686,4 +686,4 @@ "deleteContentTitle": "{pageType} を削除してもよろしいですか?", "deleteContentCaption": "この {pageType} を削除しても、ゴミ箱から復元できます。" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/ko-KR.json b/frontend/resources/translations/ko-KR.json index b0b7a472b4..ecfc4dfe5b 100644 --- a/frontend/resources/translations/ko-KR.json +++ b/frontend/resources/translations/ko-KR.json @@ -598,4 +598,4 @@ "deleteContentTitle": "{pageType}을(를) 삭제하시겠습니까?", "deleteContentCaption": "이 {pageType}을(를) 삭제하면 휴지통에서 복원할 수 있습니다." } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/pl-PL.json b/frontend/resources/translations/pl-PL.json index 372b71d1e0..f5cb6e49b9 100644 --- a/frontend/resources/translations/pl-PL.json +++ b/frontend/resources/translations/pl-PL.json @@ -1146,4 +1146,4 @@ "language": "Język", "font": "Czcionka" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/pt-BR.json b/frontend/resources/translations/pt-BR.json index 10cb323032..c1b3be0f94 100644 --- a/frontend/resources/translations/pt-BR.json +++ b/frontend/resources/translations/pt-BR.json @@ -1219,4 +1219,4 @@ "addField": "Adicionar campo", "userIcon": "Ícone do usuário" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/pt-PT.json b/frontend/resources/translations/pt-PT.json index 1b5ee1fcd1..699be162e8 100644 --- a/frontend/resources/translations/pt-PT.json +++ b/frontend/resources/translations/pt-PT.json @@ -857,4 +857,4 @@ "noResult": "Nenhum resultado", "caseSensitive": "Maiúsculas e minúsculas" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/ru-RU.json b/frontend/resources/translations/ru-RU.json index 9145e262d3..072063470f 100644 --- a/frontend/resources/translations/ru-RU.json +++ b/frontend/resources/translations/ru-RU.json @@ -1311,4 +1311,4 @@ "userIcon": "Пользовательская иконка" }, "noLogFiles": "Нет файлов журналов" -} \ No newline at end of file +} diff --git a/frontend/resources/translations/sv-SE.json b/frontend/resources/translations/sv-SE.json index 50be68350d..2231ec75fb 100644 --- a/frontend/resources/translations/sv-SE.json +++ b/frontend/resources/translations/sv-SE.json @@ -668,4 +668,4 @@ "deleteContentTitle": "Är du säker på att du vill ta bort {pageType}?", "deleteContentCaption": "om du tar bort denna {pageType} kan du återställa den från papperskorgen." } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/tr-TR.json b/frontend/resources/translations/tr-TR.json index 51bb4bf8b9..e37d7fdd31 100644 --- a/frontend/resources/translations/tr-TR.json +++ b/frontend/resources/translations/tr-TR.json @@ -1523,4 +1523,4 @@ "betaTooltip": "Şu anda yalnızca sayfaları aramayı destekliyoruz", "fromTrashHint": "Çöp kutusundan" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/uk-UA.json b/frontend/resources/translations/uk-UA.json index b8d8828f6f..113c99b010 100644 --- a/frontend/resources/translations/uk-UA.json +++ b/frontend/resources/translations/uk-UA.json @@ -813,4 +813,4 @@ "noResult": "Немає результатів", "caseSensitive": "З урахуванням регістру" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/vi-VN.json b/frontend/resources/translations/vi-VN.json index be97d77022..699f9a0857 100644 --- a/frontend/resources/translations/vi-VN.json +++ b/frontend/resources/translations/vi-VN.json @@ -868,4 +868,4 @@ "font": "Phông chữ", "date": "Ngày" } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/vi.json b/frontend/resources/translations/vi.json index 4d1716447a..b921c1844e 100644 --- a/frontend/resources/translations/vi.json +++ b/frontend/resources/translations/vi.json @@ -6,4 +6,4 @@ "failedToLoad": "Không tải được chế độ xem bảng" } } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/zh-CN.json b/frontend/resources/translations/zh-CN.json index 66ee6004d5..9689f2156c 100644 --- a/frontend/resources/translations/zh-CN.json +++ b/frontend/resources/translations/zh-CN.json @@ -1615,4 +1615,4 @@ "commandPalette": { "placeholder": "输入你要搜索的内容..." } -} \ No newline at end of file +} diff --git a/frontend/resources/translations/zh-TW.json b/frontend/resources/translations/zh-TW.json index 7479681c0c..654b7bbae8 100644 --- a/frontend/resources/translations/zh-TW.json +++ b/frontend/resources/translations/zh-TW.json @@ -1479,4 +1479,4 @@ "betaLabel": "BETA", "betaTooltip": "目前我們只支援搜尋頁面" } -} \ No newline at end of file +} From 42dc6017c61b125ba9f75b46e56d89fc6dd076df Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 2 Jul 2024 10:29:46 +0800 Subject: [PATCH 08/12] feat: support moving page to a space (#5665) * feat: support moving page to a space * chore: update collab repo --- .../menu/sidebar/move_to/move_page_menu.dart | 7 ++ .../menu/sidebar/space/shared_widget.dart | 88 ++++++++++++++----- frontend/appflowy_tauri/src-tauri/Cargo.lock | 14 +-- frontend/appflowy_tauri/src-tauri/Cargo.toml | 14 +-- .../appflowy_web_app/src-tauri/Cargo.lock | 21 +++-- .../appflowy_web_app/src-tauri/Cargo.toml | 14 +-- frontend/resources/translations/en.json | 4 +- frontend/rust-lib/Cargo.lock | 14 +-- frontend/rust-lib/Cargo.toml | 14 +-- 9 files changed, 123 insertions(+), 67 deletions(-) diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart index 4225f81ad2..6146311648 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/move_to/move_page_menu.dart @@ -117,8 +117,15 @@ class _MovePageMenuState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ SpacePopup( + useIntrinsicWidth: false, + expand: true, + height: 30, showCreateButton: false, child: CurrentSpace( + onTapBlankArea: () { + // move the page to current space + widget.onSelected(space); + }, space: space, ), ), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart index 42168abc9e..edc15dea5e 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/shared_widget.dart @@ -15,6 +15,8 @@ import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/decoration.dart'; +import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -277,17 +279,23 @@ class DeleteSpacePopup extends StatelessWidget { class SpacePopup extends StatelessWidget { const SpacePopup({ super.key, + this.height, + this.useIntrinsicWidth = true, + this.expand = false, required this.showCreateButton, required this.child, }); final bool showCreateButton; + final bool useIntrinsicWidth; + final bool expand; + final double? height; final Widget child; @override Widget build(BuildContext context) { return SizedBox( - height: HomeSizes.workspaceSectionHeight, + height: height ?? HomeSizes.workspaceSectionHeight, child: AppFlowyPopover( constraints: const BoxConstraints(maxWidth: 260), direction: PopoverDirection.bottomWithLeftAligned, @@ -300,7 +308,8 @@ class SpacePopup extends StatelessWidget { ), ), child: FlowyButton( - useIntrinsicWidth: true, + useIntrinsicWidth: useIntrinsicWidth, + expand: expand, margin: const EdgeInsets.only(left: 3.0, right: 4.0), iconPadding: 10.0, text: child, @@ -313,37 +322,68 @@ class SpacePopup extends StatelessWidget { class CurrentSpace extends StatelessWidget { const CurrentSpace({ super.key, + this.onTapBlankArea, required this.space, }); final ViewPB space; + final VoidCallback? onTapBlankArea; @override Widget build(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - SpaceIcon( - dimension: 20, - space: space, - cornerRadius: 6.0, - ), - const HSpace(10), - Flexible( - child: FlowyText.medium( - space.name, - fontSize: 14.0, - overflow: TextOverflow.ellipsis, + final child = FlowyTooltip( + message: LocaleKeys.space_switchSpace.tr(), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SpaceIcon( + dimension: 20, + space: space, + cornerRadius: 6.0, ), - ), - const HSpace(4.0), - FlowySvg( - context.read().state.isExpanded - ? FlowySvgs.workspace_drop_down_menu_show_s - : FlowySvgs.workspace_drop_down_menu_hide_s, - ), - ], + const HSpace(10), + Flexible( + child: FlowyText.medium( + space.name, + fontSize: 14.0, + overflow: TextOverflow.ellipsis, + ), + ), + const HSpace(4.0), + FlowySvg( + context.read().state.isExpanded + ? FlowySvgs.workspace_drop_down_menu_show_s + : FlowySvgs.workspace_drop_down_menu_hide_s, + ), + ], + ), ); + + if (onTapBlankArea != null) { + return Row( + children: [ + Expanded( + flex: 2, + child: FlowyHover( + child: Padding( + padding: const EdgeInsets.all(2.0), + child: child, + ), + ), + ), + Expanded( + child: FlowyTooltip( + message: LocaleKeys.space_movePageToSpace.tr(), + child: GestureDetector( + onTap: onTapBlankArea, + ), + ), + ), + ], + ); + } + + return child; } } diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index 477d103909..0aae7ac784 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -907,7 +907,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-trait", @@ -931,7 +931,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-trait", @@ -961,7 +961,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "collab", @@ -981,7 +981,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "bytes", @@ -996,7 +996,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "chrono", @@ -1034,7 +1034,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-stream", @@ -1115,7 +1115,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "collab", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 6dd8b25b86..eec5698341 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -106,10 +106,10 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 05a7af34e6..385d1c881d 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-trait", @@ -914,7 +914,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-trait", @@ -944,7 +944,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "collab", @@ -964,7 +964,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "bytes", @@ -979,7 +979,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "chrono", @@ -1017,7 +1017,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-stream", @@ -1098,7 +1098,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "collab", @@ -1886,6 +1886,7 @@ name = "flowy-chat" version = "0.1.0" dependencies = [ "allo-isolate", + "anyhow", "bytes", "dashmap", "flowy-chat-pub", @@ -1899,9 +1900,13 @@ dependencies = [ "lib-dispatch", "lib-infra", "log", + "parking_lot 0.12.1", "protobuf", + "serde", + "serde_json", "strum_macros 0.21.1", "tokio", + "tokio-stream", "tracing", "uuid", "validator", @@ -2171,6 +2176,7 @@ dependencies = [ "fancy-regex 0.11.0", "flowy-codegen", "flowy-derive", + "flowy-sidecar", "flowy-sqlite", "lib-dispatch", "protobuf", @@ -2486,6 +2492,7 @@ dependencies = [ "anyhow", "base64 0.21.7", "chrono", + "client-api", "collab", "collab-entity", "flowy-error", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index c87aa9e925..419317f66f 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -107,10 +107,10 @@ default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] [patch.crates-io] -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index ed4c43df84..6c37938d97 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -2027,6 +2027,8 @@ "upgrade": "Update", "upgradeYourSpace": "Create multiple Spaces", "quicklySwitch": "Quickly switch to the next space", - "duplicate": "Duplicate Space" + "duplicate": "Duplicate Space", + "movePageToSpace": "Move page to space", + "switchSpace": "Switch space" } } diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 215fbdd43b..41028d6aba 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -768,7 +768,7 @@ dependencies = [ [[package]] name = "collab" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-trait", @@ -792,7 +792,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-trait", @@ -822,7 +822,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "collab", @@ -842,7 +842,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "bytes", @@ -857,7 +857,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "chrono", @@ -895,7 +895,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "async-stream", @@ -976,7 +976,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=3a58d95#3a58d95a202b2814920650fa71c458fb0b49293d" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5048762#5048762dbb01abcbe75237e86c0d090e2f1d7c23" dependencies = [ "anyhow", "collab", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 70b6b5e7e2..95402906de 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -139,10 +139,10 @@ rocksdb = { git = "https://github.com/LucasXu0/rust-rocksdb", rev = "21cf4a23ec1 # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "3a58d95" } +collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5048762" } From a7b850e752fb177a2648e4c60e574c83c24bce1c Mon Sep 17 00:00:00 2001 From: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> Date: Tue, 2 Jul 2024 07:02:01 +0200 Subject: [PATCH 09/12] chore: disable cloud search (#5663) Co-authored-by: Lucas.Xu --- .../rust-lib/flowy-core/src/deps_resolve/search_deps.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/search_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/search_deps.rs index b31853a803..e775976818 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/search_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/search_deps.rs @@ -1,5 +1,4 @@ use flowy_folder::manager::FolderManager; -use flowy_search::document::handler::DocumentSearchHandler; use flowy_search::folder::handler::FolderSearchHandler; use flowy_search::folder::indexer::FolderIndexManagerImpl; use flowy_search::services::manager::SearchManager; @@ -10,11 +9,11 @@ pub struct SearchDepsResolver(); impl SearchDepsResolver { pub async fn resolve( folder_indexer: Arc, - cloud_service: Arc, - folder_manager: Arc, + _cloud_service: Arc, + _folder_manager: Arc, ) -> Arc { let folder_handler = Arc::new(FolderSearchHandler::new(folder_indexer)); - let document_handler = Arc::new(DocumentSearchHandler::new(cloud_service, folder_manager)); - Arc::new(SearchManager::new(vec![folder_handler, document_handler])) + // let document_handler = Arc::new(DocumentSearchHandler::new(cloud_service, folder_manager)); + Arc::new(SearchManager::new(vec![folder_handler])) } } From 8c1520b273b3e2a9ebf5789acc2a5b77816dbe8e Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 2 Jul 2024 13:02:15 +0800 Subject: [PATCH 10/12] feat: sync the created view after duplicating (#5674) * feat: sync the created view after duplicating * chore: revert launch.json * chore: refacotor code --- .../application/sidebar/space/space_bloc.dart | 1 + .../workspace/application/view/view_bloc.dart | 1 + .../application/view/view_service.dart | 4 +- .../menu/view/view_more_action_button.dart | 13 +-- .../src/folder_event.rs | 2 +- .../src/deps_resolve/folder_deps.rs | 16 +-- .../rust-lib/flowy-database2/src/manager.rs | 13 ++- .../flowy-folder/src/entities/view.rs | 6 ++ .../flowy-folder/src/event_handler.rs | 2 +- frontend/rust-lib/flowy-folder/src/manager.rs | 102 ++++++++++++++---- .../rust-lib/flowy-folder/src/test_helper.rs | 2 +- .../flowy-folder/src/view_operation.rs | 5 +- 12 files changed, 124 insertions(+), 43 deletions(-) diff --git a/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart index 611908cb1a..eeb5043920 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart @@ -625,6 +625,7 @@ class SpaceBloc extends Bloc { await ViewBackendService.duplicate( view: view, openAfterDuplicate: true, + syncAfterDuplicate: true, includeChildren: true, parentViewId: newSpace.id, suffix: '', diff --git a/frontend/appflowy_flutter/lib/workspace/application/view/view_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/view/view_bloc.dart index 2600422511..ff486fbace 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/view/view_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/view/view_bloc.dart @@ -157,6 +157,7 @@ class ViewBloc extends Bloc { final result = await ViewBackendService.duplicate( view: view, openAfterDuplicate: true, + syncAfterDuplicate: true, includeChildren: true, ); emit( diff --git a/frontend/appflowy_flutter/lib/workspace/application/view/view_service.dart b/frontend/appflowy_flutter/lib/workspace/application/view/view_service.dart index 9a0874b711..4d59958333 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/view/view_service.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/view/view_service.dart @@ -143,11 +143,13 @@ class ViewBackendService { required bool includeChildren, String? parentViewId, String? suffix, + required bool syncAfterDuplicate, }) { final payload = DuplicateViewPayloadPB.create() ..viewId = view.id ..openAfterDuplicate = openAfterDuplicate - ..includeChildren = includeChildren; + ..includeChildren = includeChildren + ..syncAfterCreate = syncAfterDuplicate; if (parentViewId != null) { payload.parentViewId = parentViewId; diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_more_action_button.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_more_action_button.dart index 5e0107ce73..0cecd4849c 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_more_action_button.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/view_more_action_button.dart @@ -242,14 +242,11 @@ class ViewMoreActionTypeWrapper extends CustomActionCell { leftIcon: inner.leftIcon, rightIcon: inner.rightIcon, iconPadding: 10.0, - text: SizedBox( - height: 18.0, - child: FlowyText.regular( - inner.name, - color: inner == ViewMoreActionType.delete - ? Theme.of(context).colorScheme.error - : null, - ), + text: FlowyText.regular( + inner.name, + color: inner == ViewMoreActionType.delete + ? Theme.of(context).colorScheme.error + : null, ), onTap: onTap, ), diff --git a/frontend/rust-lib/event-integration-test/src/folder_event.rs b/frontend/rust-lib/event-integration-test/src/folder_event.rs index 4c07a19862..6168d4bd41 100644 --- a/frontend/rust-lib/event-integration-test/src/folder_event.rs +++ b/frontend/rust-lib/event-integration-test/src/folder_event.rs @@ -140,7 +140,7 @@ impl EventIntegrationTest { self .appflowy_core .folder_manager - .create_view_with_params(params) + .create_view_with_params(params, true) .await .unwrap(); } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index e1f53a55e9..81739a51d8 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -185,16 +185,16 @@ impl FolderOperationHandler for DocumentFolderOperation { &self, user_id: i64, params: CreateViewParams, - ) -> FutureResult<(), FlowyError> { + ) -> FutureResult, FlowyError> { debug_assert_eq!(params.layout, ViewLayoutPB::Document); let view_id = params.view_id.to_string(); let manager = self.0.clone(); FutureResult::new(async move { let data = DocumentDataPB::try_from(Bytes::from(params.initial_data))?; - manager + let encoded_collab = manager .create_document(user_id, &view_id, Some(data.into())) .await?; - Ok(()) + Ok(Some(encoded_collab)) }) } @@ -301,16 +301,16 @@ impl FolderOperationHandler for DatabaseFolderOperation { &self, _user_id: i64, params: CreateViewParams, - ) -> FutureResult<(), FlowyError> { + ) -> FutureResult, FlowyError> { match CreateDatabaseExtParams::from_map(params.meta.clone()) { None => { let database_manager = self.0.clone(); let view_id = params.view_id.to_string(); FutureResult::new(async move { - database_manager + let encoded_collab = database_manager .create_database_with_database_data(&view_id, params.initial_data) .await?; - Ok(()) + Ok(Some(encoded_collab)) }) }, Some(database_params) => { @@ -338,7 +338,7 @@ impl FolderOperationHandler for DatabaseFolderOperation { database_parent_view_id, ) .await?; - Ok(()) + Ok(None) }) }, } @@ -505,7 +505,7 @@ impl FolderOperationHandler for ChatFolderOperation { &self, _user_id: i64, _params: CreateViewParams, - ) -> FutureResult<(), FlowyError> { + ) -> FutureResult, FlowyError> { FutureResult::new(async move { Err(FlowyError::not_support()) }) } diff --git a/frontend/rust-lib/flowy-database2/src/manager.rs b/frontend/rust-lib/flowy-database2/src/manager.rs index 58ccec904d..c7d941f4cb 100644 --- a/frontend/rust-lib/flowy-database2/src/manager.rs +++ b/frontend/rust-lib/flowy-database2/src/manager.rs @@ -10,7 +10,7 @@ use collab_database::views::{CreateDatabaseParams, CreateViewParams, DatabaseLay use collab_database::workspace_database::{ CollabDocStateByOid, CollabFuture, DatabaseCollabService, DatabaseMeta, WorkspaceDatabase, }; -use collab_entity::CollabType; +use collab_entity::{CollabType, EncodedCollab}; use collab_plugins::local_storage::kv::KVTransactionDB; use tokio::sync::{Mutex, RwLock}; use tracing::{event, instrument, trace}; @@ -289,7 +289,7 @@ impl DatabaseManager { &self, view_id: &str, data: Vec, - ) -> FlowyResult<()> { + ) -> FlowyResult { let database_data = DatabaseData::from_json_bytes(data)?; let mut create_database_params = CreateDatabaseParams::from_database_data(database_data); @@ -305,8 +305,13 @@ impl DatabaseManager { } let wdb = self.get_database_indexer().await?; - let _ = wdb.create_database(create_database_params)?; - Ok(()) + let database = wdb.create_database(create_database_params)?; + let encoded_collab = database + .lock() + .get_collab() + .lock() + .encode_collab_v1(|collab| CollabType::Database.validate_require_data(collab))?; + Ok(encoded_collab) } pub async fn create_database_with_params( diff --git a/frontend/rust-lib/flowy-folder/src/entities/view.rs b/frontend/rust-lib/flowy-folder/src/entities/view.rs index 3a919e8ec4..c774b199a4 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/view.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/view.rs @@ -599,6 +599,9 @@ pub struct DuplicateViewPayloadPB { // If the suffix is None, the duplicated view will have the same name with (copy) suffix. #[pb(index = 5, one_of)] pub suffix: Option, + + #[pb(index = 6)] + pub sync_after_create: bool, } #[derive(Debug)] @@ -612,6 +615,8 @@ pub struct DuplicateViewParams { pub parent_view_id: Option, pub suffix: Option, + + pub sync_after_create: bool, } impl TryInto for DuplicateViewPayloadPB { @@ -625,6 +630,7 @@ impl TryInto for DuplicateViewPayloadPB { include_children: self.include_children, parent_view_id: self.parent_view_id, suffix: self.suffix, + sync_after_create: self.sync_after_create, }) } } diff --git a/frontend/rust-lib/flowy-folder/src/event_handler.rs b/frontend/rust-lib/flowy-folder/src/event_handler.rs index c22fdeacca..7af6d23f78 100644 --- a/frontend/rust-lib/flowy-folder/src/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/event_handler.rs @@ -105,7 +105,7 @@ pub(crate) async fn create_view_handler( let folder = upgrade_folder(folder)?; let params: CreateViewParams = data.into_inner().try_into()?; let set_as_current = params.set_as_current; - let view = folder.create_view_with_params(params).await?; + let (view, _) = folder.create_view_with_params(params, true).await?; if set_as_current { let _ = folder.set_current_view(&view.id).await; } diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 6ebf619689..adcbe416ac 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -371,11 +371,21 @@ impl FolderManager { } } - pub async fn create_view_with_params(&self, params: CreateViewParams) -> FlowyResult { + /// Asynchronously creates a view with provided parameters and notifies the workspace if update is needed. + /// + /// Commonly, the notify_workspace_update parameter is set to true when the view is created in the workspace. + /// If you're handling multiple views in the same hierarchy and want to notify the workspace only after the last view is created, + /// you can set notify_workspace_update to false to avoid multiple notifications. + pub async fn create_view_with_params( + &self, + params: CreateViewParams, + notify_workspace_update: bool, + ) -> FlowyResult<(View, Option)> { let workspace_id = self.user.workspace_id()?; let view_layout: ViewLayout = params.layout.clone().into(); let handler = self.get_handler(&view_layout)?; let user_id = self.user.user_id()?; + let mut encoded_collab: Option = None; if params.meta.is_empty() && params.initial_data.is_empty() { tracing::trace!("Create view with build-in data"); @@ -384,7 +394,7 @@ impl FolderManager { .await?; } else { tracing::trace!("Create view with view data"); - handler + encoded_collab = handler .create_view_with_view_data(user_id, params.clone()) .await?; } @@ -403,12 +413,14 @@ impl FolderManager { }, ); - let folder = &self.mutex_folder.read(); - if let Some(folder) = folder.as_ref() { - notify_did_update_workspace(&workspace_id, folder); + if notify_workspace_update { + let folder = &self.mutex_folder.read(); + if let Some(folder) = folder.as_ref() { + notify_did_update_workspace(&workspace_id, folder); + } } - Ok(view) + Ok((view, encoded_collab)) } /// The orphan view is meant to be a view that is not attached to any parent view. By default, this @@ -752,6 +764,7 @@ impl FolderManager { params.open_after_duplicate, params.include_children, params.suffix, + params.sync_after_create, ) .await } @@ -767,6 +780,7 @@ impl FolderManager { open_after_duplicated: bool, include_children: bool, suffix: Option, + sync_after_create: bool, ) -> Result<(), FlowyError> { if view_id == parent_view_id { return Err(FlowyError::new( @@ -775,6 +789,7 @@ impl FolderManager { )); } + // filter the view ids that in the trash or private section let filtered_view_ids = self.with_folder(Vec::new, |folder| { self.get_view_ids_should_be_filtered(folder) }); @@ -783,6 +798,7 @@ impl FolderManager { let mut is_source_view = true; // use a stack to duplicate the view and its children let mut stack = vec![(view_id.to_string(), parent_view_id.to_string())]; + let mut objects = vec![]; let suffix = suffix.unwrap_or(" (copy)".to_string()); while let Some((current_view_id, current_parent_id)) = stack.pop() { @@ -823,6 +839,7 @@ impl FolderManager { } else { view.name.clone() }; + let duplicate_params = CreateViewParams { parent_view_id: current_parent_id.clone(), name, @@ -838,7 +855,30 @@ impl FolderManager { icon: view.icon.clone(), }; - let duplicated_view = self.create_view_with_params(duplicate_params).await?; + // set the notify_workspace_update to false to avoid multiple notifications + let (duplicated_view, encoded_collab) = self + .create_view_with_params(duplicate_params, false) + .await?; + + if sync_after_create { + if let Some(encoded_collab) = encoded_collab { + let object_id = duplicated_view.id.clone(); + let collab_type = match duplicated_view.layout { + ViewLayout::Document => CollabType::Document, + ViewLayout::Board | ViewLayout::Grid | ViewLayout::Calendar => CollabType::Database, + ViewLayout::Chat => CollabType::Unknown, + }; + // don't block the whole import process if the view can't be encoded + if collab_type != CollabType::Unknown { + match self.get_folder_collab_params(object_id, collab_type, encoded_collab) { + Ok(params) => objects.push(params), + Err(e) => { + error!("duplicate error {}", e); + }, + } + } + } + } if include_children { let child_views = self.get_views_belong_to(¤t_view_id).await?; @@ -854,6 +894,23 @@ impl FolderManager { is_source_view = false } + let workspace_id = &self.user.workspace_id()?; + + // Sync the view to the cloud + if sync_after_create { + self + .cloud_service + .batch_create_folder_collab_objects(workspace_id, objects) + .await?; + } + + // notify the update here + notify_parent_view_did_change( + workspace_id, + self.mutex_folder.clone(), + vec![parent_view_id.to_string()], + ); + Ok(()) } @@ -1128,18 +1185,11 @@ impl FolderManager { if sync_after_create { if let Some(encoded_collab) = encoded_collab { - // Try to encode the collaboration data to bytes - let encode_collab_v1 = encoded_collab.encode_to_bytes().map_err(internal_error); - - // If the view can't be encoded, skip it and don't block the whole import process - match encode_collab_v1 { - Ok(encode_collab_v1) => objects.push(FolderCollabParams { - object_id, - encoded_collab_v1: encode_collab_v1, - collab_type, - }), + // don't block the whole import process if the view can't be encoded + match self.get_folder_collab_params(object_id, collab_type, encoded_collab) { + Ok(params) => objects.push(params), Err(e) => { - error!("import error {}", e) + error!("import error {}", e); }, } } @@ -1214,6 +1264,22 @@ impl FolderManager { } } + fn get_folder_collab_params( + &self, + object_id: String, + collab_type: CollabType, + encoded_collab: EncodedCollab, + ) -> FlowyResult { + // Try to encode the collaboration data to bytes + let encoded_collab_v1: Result, FlowyError> = + encoded_collab.encode_to_bytes().map_err(internal_error); + encoded_collab_v1.map(|encoded_collab_v1| FolderCollabParams { + object_id, + encoded_collab_v1, + collab_type, + }) + } + /// Returns the relation of the view. The relation is a tuple of (is_workspace, parent_view_id, /// child_view_ids). If the view is a workspace, then the parent_view_id is the workspace id. /// Otherwise, the parent_view_id is the parent view id of the view. The child_view_ids is the diff --git a/frontend/rust-lib/flowy-folder/src/test_helper.rs b/frontend/rust-lib/flowy-folder/src/test_helper.rs index f702956828..3779a91b48 100644 --- a/frontend/rust-lib/flowy-folder/src/test_helper.rs +++ b/frontend/rust-lib/flowy-folder/src/test_helper.rs @@ -51,7 +51,7 @@ impl FolderManager { icon: None, extra: None, }; - self.create_view_with_params(params).await.unwrap(); + self.create_view_with_params(params, true).await.unwrap(); view_id } } diff --git a/frontend/rust-lib/flowy-folder/src/view_operation.rs b/frontend/rust-lib/flowy-folder/src/view_operation.rs index 969092c58b..86b3f4894f 100644 --- a/frontend/rust-lib/flowy-folder/src/view_operation.rs +++ b/frontend/rust-lib/flowy-folder/src/view_operation.rs @@ -61,11 +61,14 @@ pub trait FolderOperationHandler { /// * `layout`: the layout of the view /// * `meta`: use to carry extra information. For example, the database view will use this /// to carry the reference database id. + /// + /// The return value is the [Option] that can be used to create the view. + /// It can be used in syncing the view data to cloud. fn create_view_with_view_data( &self, user_id: i64, params: CreateViewParams, - ) -> FutureResult<(), FlowyError>; + ) -> FutureResult, FlowyError>; /// Create a view with the pre-defined data. /// For example, the initial data of the grid/calendar/kanban board when From 7a3f013a8767e30e47bc4db453bed56f5f025314 Mon Sep 17 00:00:00 2001 From: "Nathan.fooo" <86001920+appflowy@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:26:53 +0800 Subject: [PATCH 11/12] chore: show ai service error (#5675) --- frontend/rust-lib/flowy-chat/src/chat.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/rust-lib/flowy-chat/src/chat.rs b/frontend/rust-lib/flowy-chat/src/chat.rs index 2854d12a92..6c5e06d7a8 100644 --- a/frontend/rust-lib/flowy-chat/src/chat.rs +++ b/frontend/rust-lib/flowy-chat/src/chat.rs @@ -140,12 +140,14 @@ impl Chat { send_notification(&chat_id, ChatNotification::StreamChatMessageError) .payload(pb) .send(); - break; + return Err(err); }, } } }, Err(err) => { + error!("[Chat] failed to stream answer: {}", err); + let _ = text_sink.send(format!("error:{}", err)).await; let pb = ChatMessageErrorPB { chat_id: chat_id.clone(), error_message: err.to_string(), @@ -153,10 +155,15 @@ impl Chat { send_notification(&chat_id, ChatNotification::StreamChatMessageError) .payload(pb) .send(); + return Err(err); }, } send_notification(&chat_id, ChatNotification::FinishStreaming).send(); + if stream_buffer.lock().await.is_empty() { + return Ok(()); + } + let answer = cloud_service .save_answer( &workspace_id, @@ -166,7 +173,6 @@ impl Chat { ) .await?; Self::save_answer(uid, &chat_id, &user_service, answer)?; - Ok::<(), FlowyError>(()) }); From 6d0c9f766bd73ad07dad34dfff7fe9d8bffda418 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 2 Jul 2024 14:35:29 +0800 Subject: [PATCH 12/12] fix: filter chat page when duplicating (#5676) * fix: filter chat page when duplicating * fix: don't clear selection if it has been disposed --- CHANGELOG.md | 6 ++++++ .../lib/plugins/document/presentation/editor_page.dart | 6 +++++- frontend/rust-lib/flowy-folder/src/manager.rs | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79d7e607e2..f973b99f42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ # Release Notes ## Version 0.6.2 - 01/07/2024 ### New Features +- Added support for duplicating spaces. +- Added support for moving pages across spaces. +- Undo markdown formatting with `Ctrl + Z` or `Cmd + Z`. +- Improved shortcuts settings UI. ### Bug Fixes +- Fixed unable to zoom in with `Ctrl` and `+` or `Cmd` and `+` on some keyboards. +- Fixed unable to paste nested lists in existing lists. ## Version 0.6.1 - 22/06/2024 ### New Features diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart index ea94d31df3..bf2ad68e16 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart @@ -214,7 +214,11 @@ class _AppFlowyEditorPageState extends State { AFFocusManager? focusManager; - void _loseFocus() => widget.editorState.selection = null; + void _loseFocus() { + if (!widget.editorState.isDisposed) { + widget.editorState.selection = null; + } + } @override void initState() { diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index adcbe416ac..39ee2fa5de 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -885,7 +885,7 @@ impl FolderManager { // reverse the child views to keep the order for child_view in child_views.iter().rev() { // skip the view_id should be filtered and the child_view is the duplicated view - if !filtered_view_ids.contains(&child_view.id) { + if !filtered_view_ids.contains(&child_view.id) && child_view.layout != ViewLayout::Chat { stack.push((child_view.id.clone(), duplicated_view.id.clone())); } }