From 4844abc4cf91ba4c83f3f8fbe98cf01702d4b112 Mon Sep 17 00:00:00 2001 From: David Lee Date: Wed, 2 Oct 2024 11:49:06 -0700 Subject: [PATCH 001/259] Make Avatar#text nullable --- packages/ui/src/components/Avatar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/Avatar.tsx b/packages/ui/src/components/Avatar.tsx index cba7388eb9..f45bea82be 100644 --- a/packages/ui/src/components/Avatar.tsx +++ b/packages/ui/src/components/Avatar.tsx @@ -252,7 +252,7 @@ export const TextAvatar = React.memo(function TextAvatarComponent({ backgroundColor = '$secondaryBackground', ...props }: { - text: string; + text: string | null; } & AvatarProps) { const fontSize = { $xl: 12, @@ -278,7 +278,7 @@ export const TextAvatar = React.memo(function TextAvatarComponent({ fontSize={fontSize} color={getContrastingColor(finalBackgroundColor)} > - {text[0]?.toUpperCase()} + {text?.[0]?.toUpperCase()} From d2cc36c0fbe0e2198c8d2878e7401365357db024 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 30 Sep 2024 20:00:15 -0700 Subject: [PATCH 002/259] [wip] Replace checks on channel type with feature-based config --- .../src/fixtures/MessageActions.fixture.tsx | 7 +- .../ui/src/components/Channel/Scroller.tsx | 233 +++++++++++++----- .../ChatMessageActions/Component.android.tsx | 7 +- .../ChatMessageActions/Component.tsx | 7 +- .../ChatMessageActions/MessageActions.tsx | 31 +-- 5 files changed, 187 insertions(+), 98 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx index c74a3db312..50ec4e2e7f 100644 --- a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx @@ -1,5 +1,6 @@ import * as db from '@tloncorp/shared/dist/db'; import { ChatMessageActions, Modal, ZStack } from '@tloncorp/ui'; +import { getPostActions } from 'packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions'; import { createRef, useEffect, useState } from 'react'; import { View } from 'react-native'; @@ -22,14 +23,18 @@ function MessageActions() { } }, []); + const [postActions] = useState(() => + getPostActions({ post, channelType: currentChannel?.type ?? 'chat' }) + ); + if (currentChannel) { return ( null}> null} - channelType={currentChannel.type} /> ); diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 83a2b1295b..207ce61693 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -1,10 +1,10 @@ import { useMutableCallback } from '@tloncorp/shared'; import { createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; +import * as logic from '@tloncorp/shared/dist/logic'; import { isSameDay } from '@tloncorp/shared/dist/logic'; import { Story } from '@tloncorp/shared/dist/urbit'; import { isEqual } from 'lodash'; -import { MotiView } from 'moti'; import React, { PropsWithChildren, ReactElement, @@ -28,11 +28,22 @@ import { } from 'react-native'; import Animated from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { View, styled, useStyle, useTheme } from 'tamagui'; - +import { + ViewStyle as TamaguiViewStyle, + View, + styled, + useStyle, + useTheme, +} from 'tamagui'; + +import { useCurrentUserId } from '../../contexts'; import { useLivePost } from '../../contexts/requests'; import { useScrollDirectionTracker } from '../../contexts/scroll'; import { ChatMessageActions } from '../ChatMessage/ChatMessageActions/Component'; +import { + ChannelAction, + getPostActions, +} from '../ChatMessage/ChatMessageActions/MessageActions'; import { ViewReactionsSheet } from '../ChatMessage/ViewReactionsSheet'; import { Modal } from '../Modal'; import { ChannelDivider } from './ChannelDivider'; @@ -73,6 +84,77 @@ export type ScrollAnchor = { postId: string; }; +interface PostCollectionConfiguration { + shouldMaintainVisibleContentPosition: boolean; + contentContainerStyle: TamaguiViewStyle; + columnCount: 1 | 2; + + /** if true, enables day / unread dividers between elements */ + dividersEnabled: boolean; + + /** Width/height ratio for a collection element; e.g. 1 for square, 2 for + * landscape, 0.5 for portrait. If null, defers to item sizing. */ + itemAspectRatio: number | null; + + postActions: (options: { + post: db.Post; + isMuted?: boolean; + }) => ChannelAction[]; +} + +function usePostCollectionConfigurationFromChannelType( + channelType: db.ChannelType +): PostCollectionConfiguration { + const safeAreaInsets = useSafeAreaInsets(); + + return useMemo(() => { + switch (channelType) { + case 'chat': + // fallthrough + case 'dm': + // fallthrough + case 'groupDm': + return { + shouldMaintainVisibleContentPosition: true, + contentContainerStyle: { + paddingHorizontal: '$m', + }, + columnCount: 1, + dividersEnabled: true, + itemAspectRatio: null, + postActions: (options) => getPostActions({ ...options, channelType }), + }; + + case 'notebook': + return { + shouldMaintainVisibleContentPosition: false, + contentContainerStyle: { + paddingHorizontal: '$m', + gap: '$l', + }, + columnCount: 1, + dividersEnabled: false, + itemAspectRatio: null, + postActions: (options) => getPostActions({ ...options, channelType }), + }; + + case 'gallery': + return { + shouldMaintainVisibleContentPosition: false, + contentContainerStyle: { + paddingHorizontal: '$l', + paddingBottom: safeAreaInsets.bottom, + gap: '$l', + }, + columnCount: 2, + dividersEnabled: false, + itemAspectRatio: 1, + postActions: (options) => getPostActions({ ...options, channelType }), + }; + } + }, [channelType, safeAreaInsets]); +} + /** * This scroller makes some assumptions you should not break! * - Posts and unread state should be be loaded before the scroller is rendered @@ -140,6 +222,9 @@ const Scroller = forwardRef( }, ref ) => { + const collectionConfig = + usePostCollectionConfigurationFromChannelType(channelType); + const [isAtBottom, setIsAtBottom] = useState(true); const [hasPressedGoToBottom, setHasPressedGoToBottom] = useState(false); @@ -185,7 +270,8 @@ const Scroller = forwardRef( anchor, flatListRef, hasNewerPosts, - channelType, + shouldMaintainVisibleContentPosition: + collectionConfig.shouldMaintainVisibleContentPosition, }); const theme = useTheme(); @@ -247,7 +333,6 @@ const Scroller = forwardRef( unreadCount={unreadCount} editingPost={editingPost} channelId={channelId} - channelType={channelType} setEditingPost={setEditingPost} setViewReactionsPost={setViewReactionsPost} editPost={editPost} @@ -260,6 +345,8 @@ const Scroller = forwardRef( onLongPressPost={handlePostLongPressed} activeMessage={activeMessage} messageRef={activeMessageRefs.current[post.id]} + dividersEnabled={collectionConfig.dividersEnabled} + itemAspectRatio={collectionConfig.itemAspectRatio ?? undefined} {...anchorScrollLockScrollerItemProps} /> ); @@ -273,7 +360,6 @@ const Scroller = forwardRef( editingPost, anchorScrollLockScrollerItemProps, channelId, - channelType, setEditingPost, editPost, showReplies, @@ -285,40 +371,24 @@ const Scroller = forwardRef( handlePostLongPressed, activeMessage, showDividers, + collectionConfig.dividersEnabled, + collectionConfig.itemAspectRatio, ] ); const insets = useSafeAreaInsets(); const contentContainerStyle = useStyle( - !posts?.length - ? { flex: 1 } - : channelType === 'gallery' - ? { - paddingHorizontal: '$l', - paddingTop: headerMode === 'next' ? insets.top + 54 : 0, - paddingBottom: insets.bottom, - gap: '$l', - } - : channelType === 'notebook' - ? { - paddingHorizontal: '$m', - paddingTop: headerMode === 'next' ? insets.top + 54 : 0, - paddingBottom: insets.bottom, - gap: '$l', - } - : { - paddingHorizontal: '$m', - } + !posts?.length ? { flex: 1 } : collectionConfig.contentContainerStyle ) as StyleProp; const columnWrapperStyle = useStyle( - channelType === 'gallery' - ? { + collectionConfig.columnCount === 1 + ? {} + : { gap: '$l', width: '100%', } - : {} ) as StyleProp; const pendingEvents = useRef({ @@ -386,6 +456,11 @@ const Scroller = forwardRef( }; }, [insets.bottom]); + const postActions = useListPostActions({ + activeMessage, + collectionConfig, + }); + return ( {/* {unreadCount && !hasPressedGoToBottom ? ( @@ -403,7 +478,13 @@ const Scroller = forwardRef( keyExtractor={getPostId} keyboardDismissMode="on-drag" contentContainerStyle={contentContainerStyle} - columnWrapperStyle={channelType === 'gallery' && columnWrapperStyle} + columnWrapperStyle={ + // FlatList raises an error if `columnWrapperStyle` is provided + // with numColumns=1, even if the style is empty + collectionConfig.columnCount === 1 + ? undefined + : columnWrapperStyle + } inverted={ // https://github.com/facebook/react-native/issues/21196 // It looks like this bug has regressed a few times - to avoid @@ -414,7 +495,7 @@ const Scroller = forwardRef( initialNumToRender={INITIAL_POSTS_PER_PAGE} maxToRenderPerBatch={8} windowSize={8} - numColumns={channelType === 'gallery' ? 2 : 1} + numColumns={collectionConfig.columnCount} style={style} onEndReached={handleEndReached} onEndReachedThreshold={1} @@ -433,9 +514,9 @@ const Scroller = forwardRef( {activeMessage !== null && ( setActiveMessage(null)} - channelType={channelType} onReply={onPressReplies} onEdit={() => { setEditingPost?.(activeMessage); @@ -479,7 +560,6 @@ const BaseScrollerItem = ({ editingPost, onLayout, channelId, - channelType, setViewReactionsPost, setEditingPost, editPost, @@ -494,6 +574,8 @@ const BaseScrollerItem = ({ messageRef, isSelected, isLastPostOfBlock, + dividersEnabled, + itemAspectRatio, }: { showUnreadDivider: boolean; showAuthor: boolean; @@ -504,7 +586,6 @@ const BaseScrollerItem = ({ unreadCount?: number | null; onLayout: (post: db.Post, index: number, e: LayoutChangeEvent) => void; channelId: string; - channelType: db.ChannelType; onPressImage?: (post: db.Post, imageUri?: string) => void; onPressReplies?: (post: db.Post) => void; showReplies?: boolean; @@ -520,6 +601,8 @@ const BaseScrollerItem = ({ messageRef: RefObject; isSelected: boolean; isLastPostOfBlock: boolean; + dividersEnabled: boolean; + itemAspectRatio?: number; }) => { const post = useLivePost(item); @@ -531,26 +614,17 @@ const BaseScrollerItem = ({ ); const dividerType = useMemo(() => { - switch (channelType) { - case 'chat': - // fallthrough - case 'dm': - // fallthrough - case 'groupDm': - if (showUnreadDivider) { - return 'unread'; - } - if (showDayDivider) { - return 'day'; - } - return null; - - case 'gallery': - // fallthrough - case 'notebook': - return null; + if (!dividersEnabled) { + return null; + } + if (showUnreadDivider) { + return 'unread'; } - }, [channelType, showUnreadDivider, showDayDivider]); + if (showDayDivider) { + return 'day'; + } + return null; + }, [dividersEnabled, showUnreadDivider, showDayDivider]); const divider = useMemo(() => { switch (dividerType) { @@ -578,13 +652,7 @@ const BaseScrollerItem = ({ }, [dividerType, post, unreadCount, showDayDivider]); return ( - (channelType === 'gallery' ? { aspectRatio: 1, flex: 0.5 } : {}), - [channelType] - )} - > + {divider} >; @@ -668,7 +736,7 @@ function useAnchorScrollLock({ posts: db.Post[] | null; anchor: ScrollAnchor | null | undefined; hasNewerPosts?: boolean; - channelType: db.ChannelType; + shouldMaintainVisibleContentPosition: boolean; }) { const [userHasScrolled, setUserHasScrolled] = useState(false); const [needsScrollToAnchor, setNeedsScrollToAnchor] = useState( @@ -775,7 +843,7 @@ function useAnchorScrollLock({ } ); const maintainVisibleContentPositionConfig = useMemo(() => { - if (!['chat', 'dm', 'groupDm'].includes(channelType)) { + if (!shouldMaintainVisibleContentPosition) { return undefined; } @@ -788,7 +856,7 @@ function useAnchorScrollLock({ // only enable it when there's nothing newer left to load (so, for new incoming messages only). autoscrollToTopThreshold: hasNewerPosts ? undefined : 0, }; - }, [hasNewerPosts, channelType]); + }, [hasNewerPosts, shouldMaintainVisibleContentPosition]); const handleScrollToIndexFailed = useMutableCallback( (info: { @@ -857,3 +925,42 @@ function useAnchorScrollLock({ ), }; } + +function useListPostActions({ + activeMessage: post, + collectionConfig, +}: { + collectionConfig: PostCollectionConfiguration; + activeMessage?: db.Post | null; +}): ChannelAction[] { + const currentUserId = useCurrentUserId(); + const getPostActions = collectionConfig.postActions; + return useMemo(() => { + if (post == null) { + return []; + } + + return getPostActions({ + post, + isMuted: logic.isMuted(post.volumeSettings?.level, 'thread'), + }).filter((action) => { + switch (action.id) { + case 'startThread': + // only show start thread if + // 1. the message is delivered + // 2. the message isn't a reply + // 3. an existing thread for that message doesn't already exist + return ( + !post.deliveryStatus && !post.parentId && post.replyCount === 0 + ); + case 'edit': + // only show edit for current user's posts + return post.authorId === currentUserId; + case 'viewReactions': + return (post.reactions?.length ?? 0) > 0; + default: + return true; + } + }); + }, [post, getPostActions, currentUserId]); +} diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx index e6d81d0d58..585e19e2dc 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx @@ -1,3 +1,4 @@ +import { ChannelAction } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import * as Haptics from 'expo-haptics'; import { MotiView } from 'moti'; @@ -12,15 +13,15 @@ import { MessageContainer } from './MessageContainer'; export function ChatMessageActions({ post, - channelType, + postActions, onDismiss, onReply, onEdit, onViewReactions, }: { post: db.Post; + postActions: ChannelAction[]; postRef: RefObject; - channelType: db.ChannelType; onDismiss: () => void; onReply?: (post: db.Post) => void; onViewReactions?: (post: db.Post) => void; @@ -69,7 +70,7 @@ export function ChatMessageActions({ ; - channelType: db.ChannelType; onDismiss: () => void; width?: DimensionValue; height?: DimensionValue; @@ -150,7 +151,7 @@ export function ChatMessageActions({ void; onViewReactions?: (post: db.Post) => void; post: db.Post; - channelType: db.ChannelType; + postActions: ChannelAction[]; }) { const currentSession = useCurrentSession(); const currentUserId = useCurrentUserId(); const { addAttachment } = useAttachmentContext(); const channel = useChannelContext(); - const postActions = useMemo(() => { - return getPostActions({ - post, - channelType, - isMuted: logic.isMuted(post.volumeSettings?.level, 'thread'), - }).filter((action) => { - switch (action.id) { - case 'startThread': - // only show start thread if - // 1. the message is delivered - // 2. the message isn't a reply - // 3. an existing thread for that message doesn't already exist - return ( - !post.deliveryStatus && !post.parentId && post.replyCount === 0 - ); - case 'edit': - // only show edit for current user's posts - return post.authorId === currentUserId; - case 'viewReactions': - return (post.reactions?.length ?? 0) > 0; - default: - return true; - } - }); - }, [post, channelType, currentUserId]); return ( // arbitrary width that looks reasonable given labels @@ -108,7 +83,7 @@ function CopyJsonAction({ post }: { post: db.Post }) { ); } -interface ChannelAction { +export interface ChannelAction { id: string; label: string; actionType?: 'destructive'; From 6c8fb99234d2ee70683159f71f5f18a0d3c8a1a5 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 30 Sep 2024 22:42:44 -0700 Subject: [PATCH 003/259] Switch uses of getChannelTitle -> useChannelTitle --- .../components/Activity/ActivityListItem.tsx | 23 +++++++++-------- packages/ui/src/components/Channel/index.tsx | 8 +++--- .../ui/src/components/ChatOptionsSheet.tsx | 25 ++++++++++++------- packages/ui/src/utils/channelUtils.tsx | 12 ++++----- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/packages/ui/src/components/Activity/ActivityListItem.tsx b/packages/ui/src/components/Activity/ActivityListItem.tsx index c2cfd79a34..a90fd480ed 100644 --- a/packages/ui/src/components/Activity/ActivityListItem.tsx +++ b/packages/ui/src/components/Activity/ActivityListItem.tsx @@ -5,7 +5,7 @@ import React, { PropsWithChildren, useCallback, useMemo } from 'react'; import { View, XStack, YStack, styled } from 'tamagui'; import { useCalm } from '../../contexts'; -import { getChannelTitle } from '../../utils'; +import { useChannelTitle } from '../../utils'; import { ChannelAvatar, ContactAvatar, GroupAvatar } from '../Avatar'; import { Icon } from '../Icon'; import { Text } from '../TextV2'; @@ -70,16 +70,17 @@ export function ActivityListItemContent({ return (isGroupUnread(unread) ? unread.notifyCount : unread?.count) ?? 0; }, [unread]); - const title = !channel - ? group - ? group.title ?? '' - : '' - : channel.type === 'dm' - ? 'Direct message' - : channel.type === 'groupDm' - ? 'Group chat' - : (group?.title ? group.title + ': ' : '') + - getChannelTitle(channel, calm.disableNicknames); + const channelTitle = useChannelTitle(channel ?? null); + const title = + channel == null || channelTitle == null + ? group + ? group.title ?? '' + : '' + : channel.type === 'dm' + ? 'Direct message' + : channel.type === 'groupDm' + ? 'Group chat' + : (group?.title ? group.title + ': ' : '') + channelTitle; return ( (null); const [inputShouldBlur, setInputShouldBlur] = useState(false); const [groupPreview, setGroupPreview] = useState(null); - const disableNicknames = !!useCalm()?.disableNicknames; - const title = channel ? utils.getChannelTitle(channel, disableNicknames) : ''; + const title = utils.useChannelTitle(channel); const groups = useMemo(() => (group ? [group] : null), [group]); const currentUserId = useCurrentUserId(); const canWrite = utils.useCanWrite(channel, currentUserId); @@ -278,7 +276,7 @@ export function Channel({ channel={channel} group={group} mode={headerMode} - title={title} + title={title ?? ''} goBack={() => draftInputPresentationMode === 'fullscreen' && draftInputRef.current != null @@ -377,7 +375,7 @@ export function Channel({ {headerMode === 'next' ? ( { - return channel - ? utils.getChannelTitle(channel, disableNicknames) - : 'Loading...'; - }, [channel, disableNicknames]); + const title = utils.useChannelTitle(channel); const subtitle = useMemo(() => { if (!channel) { @@ -703,7 +698,7 @@ export function ChannelOptions({ } as ActionGroup, ] : []), - // TODO: redefine in a more readable way. + // TODO: redefine in a more readable way. ...(group && !['groupDm', 'dm'].includes(channel.type) && (group.privacy === 'public' || @@ -791,10 +786,22 @@ export function ChannelOptions({ onPressInvite, title, ]); + + const displayTitle = useMemo((): string => { + if (pane === 'initial') { + return title ?? ''; + } + if (title == null) { + return 'Notifications'; + } else { + return 'Notifications for ' + title; + } + }, [title, pane]); + return ( (channel == null ? null : getChannelTitle(channel, disableNicknames)), + [channel, disableNicknames] + ); } export function isDmChannel(channel: db.Channel): boolean { From 6170a9139d146ad06a43d69b7e104030e7d9b9f4 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 30 Sep 2024 22:54:59 -0700 Subject: [PATCH 004/259] Move ChannelAction + PostCollectionConfiguration to `shared` package --- .../src/fixtures/MessageActions.fixture.tsx | 2 +- packages/shared/src/index.ts | 5 + .../src/types/PostCollectionConfiguration.ts | 77 ++++++++++ packages/shared/src/types/messageActions.ts | 135 ++++++++++++++++++ .../ui/src/components/Channel/Scroller.tsx | 99 +++---------- .../ChatMessageActions/MessageActions.tsx | 129 +---------------- 6 files changed, 241 insertions(+), 206 deletions(-) create mode 100644 packages/shared/src/types/PostCollectionConfiguration.ts create mode 100644 packages/shared/src/types/messageActions.ts diff --git a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx index 50ec4e2e7f..130d09d165 100644 --- a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx @@ -1,6 +1,6 @@ +import { getPostActions } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import { ChatMessageActions, Modal, ZStack } from '@tloncorp/ui'; -import { getPostActions } from 'packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions'; import { createRef, useEffect, useState } from 'react'; import { View } from 'react-native'; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 71a2bef1ae..d2bde740f6 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -8,6 +8,11 @@ export type { WebAppAction, WebAppCommand, } from './types/native'; +export { getPostActions, ChannelAction } from './types/messageActions'; +export { + PostCollectionConfiguration, + usePostCollectionConfigurationFromChannelType, +} from './types/PostCollectionConfiguration'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; export * from './store'; diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts new file mode 100644 index 0000000000..1564b15f47 --- /dev/null +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -0,0 +1,77 @@ +import { useMemo } from 'react'; +import { ViewStyle as TamaguiViewStyle } from 'tamagui'; + +import * as db from '../db'; +import { ChannelAction, getPostActions } from '../types/messageActions'; + +export interface PostCollectionConfiguration { + shouldMaintainVisibleContentPosition: boolean; + contentContainerStyle: TamaguiViewStyle; + columnCount: 1 | 2; + + /** if true, enables day / unread dividers between elements */ + dividersEnabled: boolean; + + /** Width/height ratio for a collection element; e.g. 1 for square, 2 for + * landscape, 0.5 for portrait. If null, defers to item sizing. */ + itemAspectRatio: number | null; + + postActions: (options: { + post: db.Post; + isMuted?: boolean; + }) => ChannelAction[]; +} + +export function usePostCollectionConfigurationFromChannelType( + channelType: db.ChannelType +): PostCollectionConfiguration { + return useMemo(() => { + switch (channelType) { + case 'chat': + // fallthrough + case 'dm': + // fallthrough + case 'groupDm': + return { + shouldMaintainVisibleContentPosition: true, + contentContainerStyle: { + paddingHorizontal: '$m', + }, + columnCount: 1, + dividersEnabled: true, + itemAspectRatio: null, + postActions: (options) => getPostActions({ ...options, channelType }), + }; + + case 'notebook': + return { + shouldMaintainVisibleContentPosition: false, + contentContainerStyle: { + paddingHorizontal: '$m', + gap: '$l', + }, + columnCount: 1, + dividersEnabled: false, + itemAspectRatio: null, + postActions: (options) => getPostActions({ ...options, channelType }), + }; + + case 'gallery': + return { + shouldMaintainVisibleContentPosition: false, + contentContainerStyle: { + paddingHorizontal: '$l', + gap: '$l', + + // We can't access safe area insets from this package :( + // Special-case this at call-site. + // paddingBottom: safeAreaInsets.bottom, + }, + columnCount: 2, + dividersEnabled: false, + itemAspectRatio: 1, + postActions: (options) => getPostActions({ ...options, channelType }), + }; + } + }, [channelType]); +} diff --git a/packages/shared/src/types/messageActions.ts b/packages/shared/src/types/messageActions.ts new file mode 100644 index 0000000000..5d84a79809 --- /dev/null +++ b/packages/shared/src/types/messageActions.ts @@ -0,0 +1,135 @@ +import * as db from '../db'; + +export interface ChannelAction { + id: string; + label: string; + actionType?: 'destructive'; + networkDependent: boolean; +} + +// a very "UI"-focused function to include in `shared`, no? +// well, think about it this way: +// we're using this to configure the actions for the default channels: +// a shared set of primitives for all Tlon software. +// are you getting it? +export function getPostActions({ + post, + channelType, + isMuted, +}: { + post: db.Post; + channelType: db.ChannelType; + isMuted?: boolean; +}): ChannelAction[] { + switch (channelType) { + case 'gallery': + return [ + { id: 'startThread', label: 'Comment on post', networkDependent: true }, + { + id: 'muteThread', + label: isMuted ? 'Unmute thread' : 'Mute thread', + networkDependent: true, + }, + { id: 'copyRef', label: 'Copy link to post', networkDependent: false }, + { id: 'edit', label: 'Edit post', networkDependent: true }, + { id: 'report', label: 'Report post', networkDependent: true }, + { + id: 'visibility', + label: post?.hidden ? 'Show post' : 'Hide post', + networkDependent: true, + }, + { + id: 'delete', + label: 'Delete message', + actionType: 'destructive', + networkDependent: true, + }, + ]; + case 'notebook': + return [ + { id: 'startThread', label: 'Comment on post', networkDependent: true }, + { + id: 'muteThread', + label: isMuted ? 'Unmute thread' : 'Mute thread', + networkDependent: true, + }, + { id: 'copyRef', label: 'Copy link to post', networkDependent: false }, + { id: 'edit', label: 'Edit post', networkDependent: true }, + { id: 'report', label: 'Report post', networkDependent: true }, + { + id: 'visibility', + label: post?.hidden ? 'Show post' : 'Hide post', + networkDependent: true, + }, + { + id: 'delete', + label: 'Delete message', + actionType: 'destructive', + networkDependent: true, + }, + ]; + case 'dm': + case 'groupDm': + return [ + // { id: 'quote', label: 'Quote' }, + { id: 'startThread', label: 'Start thread', networkDependent: true }, + { + id: 'muteThread', + label: isMuted ? 'Unmute thread' : 'Mute thread', + networkDependent: true, + }, + { + id: 'viewReactions', + label: 'View reactions', + networkDependent: false, + }, + { id: 'copyText', label: 'Copy message text', networkDependent: false }, + { + id: 'visibility', + label: post?.hidden ? 'Show post' : 'Hide post', + networkDependent: true, + }, + { + id: 'delete', + label: 'Delete message', + actionType: 'destructive', + networkDependent: true, + }, + ]; + case 'chat': + default: + return [ + { id: 'quote', label: 'Quote', networkDependent: true }, + { id: 'startThread', label: 'Start thread', networkDependent: true }, + { + id: 'muteThread', + label: isMuted ? 'Unmute thread' : 'Mute thread', + networkDependent: true, + }, + { + id: 'viewReactions', + label: 'View reactions', + networkDependent: false, + }, + { + id: 'copyRef', + label: 'Copy link to message', + networkDependent: false, + }, + { id: 'copyText', label: 'Copy message text', networkDependent: false }, + { id: 'edit', label: 'Edit message', networkDependent: true }, + { + id: 'visibility', + label: post?.hidden ? 'Show post' : 'Hide post', + networkDependent: true, + }, + { id: 'report', label: 'Report message', networkDependent: true }, + { + id: 'delete', + label: 'Delete message', + actionType: 'destructive', + networkDependent: true, + }, + ]; + } +} diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 207ce61693..48e4768b25 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -1,4 +1,9 @@ -import { useMutableCallback } from '@tloncorp/shared'; +import { + ChannelAction, + PostCollectionConfiguration, + useMutableCallback, + usePostCollectionConfigurationFromChannelType, +} from '@tloncorp/shared'; import { createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; import * as logic from '@tloncorp/shared/dist/logic'; @@ -24,6 +29,7 @@ import { ListRenderItem, View as RNView, StyleProp, + StyleSheet, ViewStyle, } from 'react-native'; import Animated from 'react-native-reanimated'; @@ -40,10 +46,6 @@ import { useCurrentUserId } from '../../contexts'; import { useLivePost } from '../../contexts/requests'; import { useScrollDirectionTracker } from '../../contexts/scroll'; import { ChatMessageActions } from '../ChatMessage/ChatMessageActions/Component'; -import { - ChannelAction, - getPostActions, -} from '../ChatMessage/ChatMessageActions/MessageActions'; import { ViewReactionsSheet } from '../ChatMessage/ViewReactionsSheet'; import { Modal } from '../Modal'; import { ChannelDivider } from './ChannelDivider'; @@ -84,77 +86,6 @@ export type ScrollAnchor = { postId: string; }; -interface PostCollectionConfiguration { - shouldMaintainVisibleContentPosition: boolean; - contentContainerStyle: TamaguiViewStyle; - columnCount: 1 | 2; - - /** if true, enables day / unread dividers between elements */ - dividersEnabled: boolean; - - /** Width/height ratio for a collection element; e.g. 1 for square, 2 for - * landscape, 0.5 for portrait. If null, defers to item sizing. */ - itemAspectRatio: number | null; - - postActions: (options: { - post: db.Post; - isMuted?: boolean; - }) => ChannelAction[]; -} - -function usePostCollectionConfigurationFromChannelType( - channelType: db.ChannelType -): PostCollectionConfiguration { - const safeAreaInsets = useSafeAreaInsets(); - - return useMemo(() => { - switch (channelType) { - case 'chat': - // fallthrough - case 'dm': - // fallthrough - case 'groupDm': - return { - shouldMaintainVisibleContentPosition: true, - contentContainerStyle: { - paddingHorizontal: '$m', - }, - columnCount: 1, - dividersEnabled: true, - itemAspectRatio: null, - postActions: (options) => getPostActions({ ...options, channelType }), - }; - - case 'notebook': - return { - shouldMaintainVisibleContentPosition: false, - contentContainerStyle: { - paddingHorizontal: '$m', - gap: '$l', - }, - columnCount: 1, - dividersEnabled: false, - itemAspectRatio: null, - postActions: (options) => getPostActions({ ...options, channelType }), - }; - - case 'gallery': - return { - shouldMaintainVisibleContentPosition: false, - contentContainerStyle: { - paddingHorizontal: '$l', - paddingBottom: safeAreaInsets.bottom, - gap: '$l', - }, - columnCount: 2, - dividersEnabled: false, - itemAspectRatio: 1, - postActions: (options) => getPostActions({ ...options, channelType }), - }; - } - }, [channelType, safeAreaInsets]); -} - /** * This scroller makes some assumptions you should not break! * - Posts and unread state should be be loaded before the scroller is rendered @@ -382,6 +313,17 @@ const Scroller = forwardRef( !posts?.length ? { flex: 1 } : collectionConfig.contentContainerStyle ) as StyleProp; + // We want to add a safe area inset for gallery, but we can't cleanly + // access safe area insets in the PostCollectionConfiguration definition. + // Special-case it here. + const extracContentContainerStyle = useMemo( + () => + !posts?.length || channelType !== 'gallery' + ? undefined + : { paddingBottom: insets.bottom }, + [channelType, insets, posts?.length] + ); + const columnWrapperStyle = useStyle( collectionConfig.columnCount === 1 ? {} @@ -477,7 +419,10 @@ const Scroller = forwardRef( ListEmptyComponent={renderEmptyComponent} keyExtractor={getPostId} keyboardDismissMode="on-drag" - contentContainerStyle={contentContainerStyle} + contentContainerStyle={StyleSheet.compose( + contentContainerStyle, + extracContentContainerStyle + )} columnWrapperStyle={ // FlatList raises an error if `columnWrapperStyle` is provided // with numColumns=1, even if the style is empty diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx index 289bbb0b90..3b9e4ab452 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx @@ -1,5 +1,6 @@ import Clipboard from '@react-native-clipboard/clipboard'; import { type Session, useCurrentSession } from '@tloncorp/shared'; +import { ChannelAction } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import * as logic from '@tloncorp/shared/dist/logic'; import * as store from '@tloncorp/shared/dist/store'; @@ -83,134 +84,6 @@ function CopyJsonAction({ post }: { post: db.Post }) { ); } -export interface ChannelAction { - id: string; - label: string; - actionType?: 'destructive'; - networkDependent: boolean; -} -export function getPostActions({ - post, - channelType, - isMuted, -}: { - post: db.Post; - channelType: db.ChannelType; - isMuted?: boolean; -}): ChannelAction[] { - switch (channelType) { - case 'gallery': - return [ - { id: 'startThread', label: 'Comment on post', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { id: 'copyRef', label: 'Copy link to post', networkDependent: false }, - { id: 'edit', label: 'Edit post', networkDependent: true }, - { id: 'report', label: 'Report post', networkDependent: true }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, - ]; - case 'notebook': - return [ - { id: 'startThread', label: 'Comment on post', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { id: 'copyRef', label: 'Copy link to post', networkDependent: false }, - { id: 'edit', label: 'Edit post', networkDependent: true }, - { id: 'report', label: 'Report post', networkDependent: true }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, - ]; - case 'dm': - case 'groupDm': - return [ - // { id: 'quote', label: 'Quote' }, - { id: 'startThread', label: 'Start thread', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { - id: 'viewReactions', - label: 'View reactions', - networkDependent: false, - }, - { id: 'copyText', label: 'Copy message text', networkDependent: false }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, - ]; - case 'chat': - default: - return [ - { id: 'quote', label: 'Quote', networkDependent: true }, - { id: 'startThread', label: 'Start thread', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { - id: 'viewReactions', - label: 'View reactions', - networkDependent: false, - }, - { - id: 'copyRef', - label: 'Copy link to message', - networkDependent: false, - }, - { id: 'copyText', label: 'Copy message text', networkDependent: false }, - { id: 'edit', label: 'Edit message', networkDependent: true }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { id: 'report', label: 'Report message', networkDependent: true }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, - ]; - } -} - export async function handleAction({ id, post, From 66d0f4fd751000909c8009b1507615b491279013 Mon Sep 17 00:00:00 2001 From: David Lee Date: Tue, 1 Oct 2024 09:28:24 -0700 Subject: [PATCH 005/259] Remove dependency on channel type from channel titling --- .../src/types/PostCollectionConfiguration.ts | 24 +++++++++- packages/ui/src/utils/channelUtils.tsx | 48 +++++++++++++------ 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 1564b15f47..6a4f431360 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -16,17 +16,36 @@ export interface PostCollectionConfiguration { * landscape, 0.5 for portrait. If null, defers to item sizing. */ itemAspectRatio: number | null; + // TODO: this might make more sense as either a property of a post, or of the + // channel's config (separate from collection config) postActions: (options: { post: db.Post; isMuted?: boolean; }) => ChannelAction[]; + + /** + * If true, in the absence of a given title, the channel will be titled in UI + * with a comma-separated list of member names. + */ + usesMemberListAsFallbackTitle: boolean; } +// Why overload this function instead of just doing a union? +// If the caller has a non-nullable `channelType`, they can then get a +// non-nullable return value - nice, right? export function usePostCollectionConfigurationFromChannelType( channelType: db.ChannelType -): PostCollectionConfiguration { +): PostCollectionConfiguration; +export function usePostCollectionConfigurationFromChannelType( + channelType: db.ChannelType | null +): PostCollectionConfiguration | null; +export function usePostCollectionConfigurationFromChannelType( + channelType: db.ChannelType | null +): PostCollectionConfiguration | null { return useMemo(() => { switch (channelType) { + case null: + return null; case 'chat': // fallthrough case 'dm': @@ -41,6 +60,7 @@ export function usePostCollectionConfigurationFromChannelType( dividersEnabled: true, itemAspectRatio: null, postActions: (options) => getPostActions({ ...options, channelType }), + usesMemberListAsFallbackTitle: channelType !== 'chat', }; case 'notebook': @@ -54,6 +74,7 @@ export function usePostCollectionConfigurationFromChannelType( dividersEnabled: false, itemAspectRatio: null, postActions: (options) => getPostActions({ ...options, channelType }), + usesMemberListAsFallbackTitle: false, }; case 'gallery': @@ -71,6 +92,7 @@ export function usePostCollectionConfigurationFromChannelType( dividersEnabled: false, itemAspectRatio: 1, postActions: (options) => getPostActions({ ...options, channelType }), + usesMemberListAsFallbackTitle: false, }; } }, [channelType]); diff --git a/packages/ui/src/utils/channelUtils.tsx b/packages/ui/src/utils/channelUtils.tsx index 721a2a3be0..6f4d8d6ba8 100644 --- a/packages/ui/src/utils/channelUtils.tsx +++ b/packages/ui/src/utils/channelUtils.tsx @@ -1,3 +1,4 @@ +import { usePostCollectionConfigurationFromChannelType } from '@tloncorp/shared'; import type * as db from '@tloncorp/shared/dist/db'; import { useMemberRoles } from '@tloncorp/shared/dist/store'; import { useMemo } from 'react'; @@ -20,29 +21,48 @@ export function useChannelMemberName(member: db.ChatMember) { return getChannelMemberName(member, disableNicknames); } -function getChannelTitle(channel: db.Channel, disableNicknames: boolean) { - if (channel.type === 'dm') { - const member = channel.members?.[0]; - if (!member) { - return channel.id; - } - return getChannelMemberName(member, disableNicknames); - } else if (channel.type === 'groupDm') { - return channel.title - ? channel.title - : channel.members +function getChannelTitle({ + usesMemberListAsFallbackTitle, + channelTitle, + members, + disableNicknames, +}: { + usesMemberListAsFallbackTitle: boolean; + channelTitle?: string | null; + members?: db.ChatMember[] | null; + disableNicknames: boolean; +}) { + if (usesMemberListAsFallbackTitle) { + // NB: This has the potential to use a DM's given title if it has one. + // (There should be no path to titling a 1:1 DM in-app.) + return channelTitle + ? channelTitle + : members ?.map((member) => getChannelMemberName(member, disableNicknames)) .join(', ') ?? 'No title'; } else { - return channel.title ?? 'Untitled channel'; + return channelTitle ?? 'Untitled channel'; } } export function useChannelTitle(channel: db.Channel | null) { const { disableNicknames } = useCalm(); + const usesMemberListAsFallbackTitle = + usePostCollectionConfigurationFromChannelType( + channel?.type ?? null + )?.usesMemberListAsFallbackTitle; + return useMemo( - () => (channel == null ? null : getChannelTitle(channel, disableNicknames)), - [channel, disableNicknames] + () => + channel == null || usesMemberListAsFallbackTitle == null + ? null + : getChannelTitle({ + usesMemberListAsFallbackTitle, + channelTitle: channel.title, + members: channel.members, + disableNicknames, + }), + [channel, disableNicknames, usesMemberListAsFallbackTitle] ); } From 497764e289642ec4f5c12b0234e73da756e37a86 Mon Sep 17 00:00:00 2001 From: David Lee Date: Wed, 2 Oct 2024 11:51:51 -0700 Subject: [PATCH 006/259] Remove unused Scroller#channelId prop --- packages/ui/src/components/Channel/Scroller.tsx | 6 ------ packages/ui/src/components/Channel/index.tsx | 1 - packages/ui/src/components/DetailView.tsx | 2 -- 3 files changed, 9 deletions(-) diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 48e4768b25..d39c8ee99a 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -103,7 +103,6 @@ const Scroller = forwardRef( renderEmptyComponent: renderEmptyComponentFn, posts, channelType, - channelId, firstUnreadId, unreadCount, onStartReached, @@ -129,7 +128,6 @@ const Scroller = forwardRef( renderEmptyComponent?: () => ReactElement; posts: db.Post[] | null; channelType: db.ChannelType; - channelId: string; firstUnreadId?: string | null; unreadCount?: number | null; onStartReached?: () => void; @@ -263,7 +261,6 @@ const Scroller = forwardRef( Component={renderItem} unreadCount={unreadCount} editingPost={editingPost} - channelId={channelId} setEditingPost={setEditingPost} setViewReactionsPost={setViewReactionsPost} editPost={editPost} @@ -290,7 +287,6 @@ const Scroller = forwardRef( unreadCount, editingPost, anchorScrollLockScrollerItemProps, - channelId, setEditingPost, editPost, showReplies, @@ -504,7 +500,6 @@ const BaseScrollerItem = ({ unreadCount, editingPost, onLayout, - channelId, setViewReactionsPost, setEditingPost, editPost, @@ -530,7 +525,6 @@ const BaseScrollerItem = ({ Component: RenderItemType; unreadCount?: number | null; onLayout: (post: db.Post, index: number, e: LayoutChangeEvent) => void; - channelId: string; onPressImage?: (post: db.Post, imageUri?: string) => void; onPressReplies?: (post: db.Post) => void; showReplies?: boolean; diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 58a47328fe..f6cf2ca73e 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -306,7 +306,6 @@ export function Channel({ setEditingPost={setEditingPost} editPost={editPost} channelType={channel.type} - channelId={channel.id} firstUnreadId={ initialChannelUnread?.countWithoutThreads ?? 0 > 0 diff --git a/packages/ui/src/components/DetailView.tsx b/packages/ui/src/components/DetailView.tsx index d088e2ae5c..71d021a893 100644 --- a/packages/ui/src/components/DetailView.tsx +++ b/packages/ui/src/components/DetailView.tsx @@ -62,7 +62,6 @@ export const DetailView = ({ inverted renderItem={ChatMessage} channelType="chat" - channelId={post.channelId} editingPost={editingPost} setEditingPost={setEditingPost} editPost={editPost} @@ -94,7 +93,6 @@ export const DetailView = ({ onPressDelete, onPressImage, onPressRetry, - post.channelId, resolvedPosts, setActiveMessage, setEditingPost, From 2fdf6e520974f7331804a36a1bc244f262ef2548 Mon Sep 17 00:00:00 2001 From: David Lee Date: Wed, 2 Oct 2024 12:00:49 -0700 Subject: [PATCH 007/259] Use post collection config for enabling unread anchors --- .../src/types/PostCollectionConfiguration.ts | 8 ++++ packages/ui/src/components/Channel/index.tsx | 37 ++++++++++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 6a4f431360..d979f0c5b8 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -28,6 +28,11 @@ export interface PostCollectionConfiguration { * with a comma-separated list of member names. */ usesMemberListAsFallbackTitle: boolean; + + /** + * If true, entering channel scrolls to the viewer's first unread post. + */ + enableUnreadAnchor: boolean; } // Why overload this function instead of just doing a union? @@ -61,6 +66,7 @@ export function usePostCollectionConfigurationFromChannelType( itemAspectRatio: null, postActions: (options) => getPostActions({ ...options, channelType }), usesMemberListAsFallbackTitle: channelType !== 'chat', + enableUnreadAnchor: true, }; case 'notebook': @@ -75,6 +81,7 @@ export function usePostCollectionConfigurationFromChannelType( itemAspectRatio: null, postActions: (options) => getPostActions({ ...options, channelType }), usesMemberListAsFallbackTitle: false, + enableUnreadAnchor: false, }; case 'gallery': @@ -93,6 +100,7 @@ export function usePostCollectionConfigurationFromChannelType( itemAspectRatio: 1, postActions: (options) => getPostActions({ ...options, channelType }), usesMemberListAsFallbackTitle: false, + enableUnreadAnchor: false, }; } }, [channelType]); diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index f6cf2ca73e..659764b349 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -2,6 +2,7 @@ import { isChatChannel as getIsChatChannel, useChannel as useChannelFromStore, useGroupPreview, + usePostCollectionConfigurationFromChannelType, usePostReference as usePostReferenceHook, usePostWithRelations, } from '@tloncorp/shared/dist'; @@ -132,6 +133,10 @@ export function Channel({ const currentUserId = useCurrentUserId(); const canWrite = utils.useCanWrite(channel, currentUserId); + const postCollectionConfig = usePostCollectionConfigurationFromChannelType( + channel.type + ); + const isChatChannel = channel ? getIsChatChannel(channel) : true; const renderItem = isChatChannel ? ChatMessage @@ -163,19 +168,31 @@ export function Channel({ }, [hasLoaded, markRead]); const scrollerAnchor: ScrollAnchor | null = useMemo(() => { - if (channel.type === 'notebook') { - return null; - } else if (selectedPostId) { + // NB: technical behavior change: previously, we would avoid scroll-to-selected on notebooks. + // afaict, there's no way to select a post in a notebook, so the UX should be the same. + // (also, I personally think it's confusing to user to block scroll-to on selection for notebooks) + if (selectedPostId) { return { type: 'selected', postId: selectedPostId }; - } else if ( - channel.type !== 'gallery' && - initialChannelUnread?.countWithoutThreads && - initialChannelUnread.firstUnreadPostId - ) { - return { type: 'unread', postId: initialChannelUnread.firstUnreadPostId }; } + + if (postCollectionConfig.enableUnreadAnchor) { + if ( + initialChannelUnread?.countWithoutThreads && + initialChannelUnread.firstUnreadPostId + ) { + return { + type: 'unread', + postId: initialChannelUnread.firstUnreadPostId, + }; + } + } + return null; - }, [channel.type, selectedPostId, initialChannelUnread]); + }, [ + postCollectionConfig.enableUnreadAnchor, + selectedPostId, + initialChannelUnread, + ]); const flatListRef = useRef>(null); From 8d4517e23edc39c4fcbe27ad9d74e3f1114d857e Mon Sep 17 00:00:00 2001 From: David Lee Date: Wed, 2 Oct 2024 12:07:18 -0700 Subject: [PATCH 008/259] Derive post collection config from db.Channel instead of db.ChannelType --- packages/shared/src/index.ts | 2 +- .../src/types/PostCollectionConfiguration.ts | 18 +++++++++------ .../ui/src/components/Channel/Scroller.tsx | 23 +++++++------------ packages/ui/src/components/Channel/index.tsx | 9 ++++---- packages/ui/src/components/DetailView.tsx | 9 ++++---- packages/ui/src/components/PostScreenView.tsx | 1 + packages/ui/src/utils/channelUtils.tsx | 6 ++--- 7 files changed, 32 insertions(+), 36 deletions(-) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index d2bde740f6..8515a5b6af 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -11,7 +11,7 @@ export type { export { getPostActions, ChannelAction } from './types/messageActions'; export { PostCollectionConfiguration, - usePostCollectionConfigurationFromChannelType, + usePostCollectionConfigurationFromChannel, } from './types/PostCollectionConfiguration'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index d979f0c5b8..69e4deabda 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -36,20 +36,24 @@ export interface PostCollectionConfiguration { } // Why overload this function instead of just doing a union? -// If the caller has a non-nullable `channelType`, they can then get a +// If the caller has a non-nullable `channel`, they can then get a // non-nullable return value - nice, right? -export function usePostCollectionConfigurationFromChannelType( - channelType: db.ChannelType +export function usePostCollectionConfigurationFromChannel( + channel: db.Channel ): PostCollectionConfiguration; -export function usePostCollectionConfigurationFromChannelType( - channelType: db.ChannelType | null +export function usePostCollectionConfigurationFromChannel( + channel: db.Channel | null ): PostCollectionConfiguration | null; -export function usePostCollectionConfigurationFromChannelType( - channelType: db.ChannelType | null +export function usePostCollectionConfigurationFromChannel( + channel: db.Channel | null ): PostCollectionConfiguration | null { + const channelType = channel?.type; + return useMemo(() => { switch (channelType) { case null: + // fallthrough + case undefined: return null; case 'chat': // fallthrough diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index d39c8ee99a..97b16751c4 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -2,7 +2,7 @@ import { ChannelAction, PostCollectionConfiguration, useMutableCallback, - usePostCollectionConfigurationFromChannelType, + usePostCollectionConfigurationFromChannel, } from '@tloncorp/shared'; import { createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; @@ -34,13 +34,7 @@ import { } from 'react-native'; import Animated from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { - ViewStyle as TamaguiViewStyle, - View, - styled, - useStyle, - useTheme, -} from 'tamagui'; +import { View, styled, useStyle, useTheme } from 'tamagui'; import { useCurrentUserId } from '../../contexts'; import { useLivePost } from '../../contexts/requests'; @@ -102,7 +96,7 @@ const Scroller = forwardRef( renderItem, renderEmptyComponent: renderEmptyComponentFn, posts, - channelType, + channel, firstUnreadId, unreadCount, onStartReached, @@ -127,7 +121,7 @@ const Scroller = forwardRef( renderItem: RenderItemType; renderEmptyComponent?: () => ReactElement; posts: db.Post[] | null; - channelType: db.ChannelType; + channel: db.Channel; firstUnreadId?: string | null; unreadCount?: number | null; onStartReached?: () => void; @@ -151,8 +145,7 @@ const Scroller = forwardRef( }, ref ) => { - const collectionConfig = - usePostCollectionConfigurationFromChannelType(channelType); + const collectionConfig = usePostCollectionConfigurationFromChannel(channel); const [isAtBottom, setIsAtBottom] = useState(true); @@ -314,10 +307,10 @@ const Scroller = forwardRef( // Special-case it here. const extracContentContainerStyle = useMemo( () => - !posts?.length || channelType !== 'gallery' + !posts?.length || channel.type !== 'gallery' ? undefined : { paddingBottom: insets.bottom }, - [channelType, insets, posts?.length] + [channel.type, insets, posts?.length] ); const columnWrapperStyle = useStyle( @@ -409,7 +402,7 @@ const Scroller = forwardRef( ref={flatListRef as React.RefObject>} // This is needed so that we can force a refresh of the list when // we need to switch from 1 to 2 columns or vice versa. - key={channelType} + key={channel.type} data={postsWithNeighbors} renderItem={listRenderItem} ListEmptyComponent={renderEmptyComponent} diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 659764b349..2fec200861 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -1,8 +1,8 @@ +import { usePostCollectionConfigurationFromChannel } from '@tloncorp/shared'; import { isChatChannel as getIsChatChannel, useChannel as useChannelFromStore, useGroupPreview, - usePostCollectionConfigurationFromChannelType, usePostReference as usePostReferenceHook, usePostWithRelations, } from '@tloncorp/shared/dist'; @@ -133,9 +133,8 @@ export function Channel({ const currentUserId = useCurrentUserId(); const canWrite = utils.useCanWrite(channel, currentUserId); - const postCollectionConfig = usePostCollectionConfigurationFromChannelType( - channel.type - ); + const postCollectionConfig = + usePostCollectionConfigurationFromChannel(channel); const isChatChannel = channel ? getIsChatChannel(channel) : true; const renderItem = isChatChannel @@ -322,7 +321,7 @@ export function Channel({ editingPost={editingPost} setEditingPost={setEditingPost} editPost={editPost} - channelType={channel.type} + channel={channel} firstUnreadId={ initialChannelUnread?.countWithoutThreads ?? 0 > 0 diff --git a/packages/ui/src/components/DetailView.tsx b/packages/ui/src/components/DetailView.tsx index 71d021a893..2a1e786f3f 100644 --- a/packages/ui/src/components/DetailView.tsx +++ b/packages/ui/src/components/DetailView.tsx @@ -12,6 +12,7 @@ import { Text } from './TextV2'; export interface DetailViewProps { post: db.Post; + channel: db.Channel; initialPostUnread?: db.ThreadUnreadState | null; children?: JSX.Element; editingPost?: db.Post; @@ -34,6 +35,7 @@ export interface DetailViewProps { export const DetailView = ({ post, + channel, initialPostUnread, editingPost, setEditingPost, @@ -46,10 +48,7 @@ export const DetailView = ({ activeMessage, headerMode, }: DetailViewProps) => { - const channelType = useMemo( - () => urbit.getChannelType(post.channelId), - [post.channelId] - ); + const channelType = channel.type; const isChat = channelType !== 'notebook' && channelType !== 'gallery'; const resolvedPosts = useMemo(() => { return isChat && posts ? [...posts, post] : posts; @@ -61,7 +60,7 @@ export const DetailView = ({ Date: Thu, 3 Oct 2024 10:58:12 -0700 Subject: [PATCH 009/259] Rename messageActions.ts -> ChannelActions.ts --- packages/shared/src/index.ts | 2 +- .../shared/src/types/{messageActions.ts => ChannelActions.ts} | 0 packages/shared/src/types/PostCollectionConfiguration.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/shared/src/types/{messageActions.ts => ChannelActions.ts} (100%) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 8515a5b6af..7f679fc1f8 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -8,7 +8,7 @@ export type { WebAppAction, WebAppCommand, } from './types/native'; -export { getPostActions, ChannelAction } from './types/messageActions'; +export { getPostActions, ChannelAction } from './types/ChannelActions'; export { PostCollectionConfiguration, usePostCollectionConfigurationFromChannel, diff --git a/packages/shared/src/types/messageActions.ts b/packages/shared/src/types/ChannelActions.ts similarity index 100% rename from packages/shared/src/types/messageActions.ts rename to packages/shared/src/types/ChannelActions.ts diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 69e4deabda..6e067af6eb 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { ViewStyle as TamaguiViewStyle } from 'tamagui'; import * as db from '../db'; -import { ChannelAction, getPostActions } from '../types/messageActions'; +import { ChannelAction, getPostActions } from './ChannelActions'; export interface PostCollectionConfiguration { shouldMaintainVisibleContentPosition: boolean; From 00e06abb8b676dea04520d53e2c30d1abf6ca1a0 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 4 Oct 2024 12:49:57 -0700 Subject: [PATCH 010/259] Separate ChannelAction static spec from display spec --- .../src/fixtures/MessageActions.fixture.tsx | 10 +- packages/shared/src/index.ts | 2 +- packages/shared/src/types/ChannelActions.ts | 183 +++++++--------- .../src/types/PostCollectionConfiguration.ts | 25 +-- .../ui/src/components/Channel/Scroller.tsx | 46 +--- .../ChatMessageActions/Component.android.tsx | 6 +- .../ChatMessageActions/Component.tsx | 6 +- .../ChatMessageActions/MessageActions.tsx | 197 ++++++++++++++---- 8 files changed, 254 insertions(+), 221 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx index 130d09d165..71817e472f 100644 --- a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx @@ -1,6 +1,6 @@ -import { getPostActions } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import { ChatMessageActions, Modal, ZStack } from '@tloncorp/ui'; +import { ChannelAction } from 'packages/shared/dist'; import { createRef, useEffect, useState } from 'react'; import { View } from 'react-native'; @@ -23,8 +23,10 @@ function MessageActions() { } }, []); - const [postActions] = useState(() => - getPostActions({ post, channelType: currentChannel?.type ?? 'chat' }) + const [postActionIds] = useState(() => + currentChannel == null + ? [] + : ChannelAction.channelActionIdsFor({ channel: currentChannel }) ); if (currentChannel) { @@ -32,7 +34,7 @@ function MessageActions() { null}> null} /> diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 7f679fc1f8..eec4c906cb 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,3 +1,4 @@ +export * as ChannelAction from './types/ChannelActions'; export type { GroupMeta } from './types/groups'; export type { NativeWebViewOptions, @@ -8,7 +9,6 @@ export type { WebAppAction, WebAppCommand, } from './types/native'; -export { getPostActions, ChannelAction } from './types/ChannelActions'; export { PostCollectionConfiguration, usePostCollectionConfigurationFromChannel, diff --git a/packages/shared/src/types/ChannelActions.ts b/packages/shared/src/types/ChannelActions.ts index 5d84a79809..b65eeff144 100644 --- a/packages/shared/src/types/ChannelActions.ts +++ b/packages/shared/src/types/ChannelActions.ts @@ -1,135 +1,92 @@ import * as db from '../db'; -export interface ChannelAction { - id: string; - label: string; +export type Id = + | 'quote' + | 'startThread' + | 'muteThread' + | 'viewReactions' + | 'copyRef' + | 'copyText' + | 'edit' + | 'report' + | 'visibility' + | 'delete'; + +/** + * Info about a channel action type that should not change based on context. + */ +export interface StaticSpec { actionType?: 'destructive'; - networkDependent: boolean; + isNetworkDependent: boolean; } -// a very "UI"-focused function to include in `shared`, no? -// well, think about it this way: -// we're using this to configure the actions for the default channels: -// a shared set of primitives for all Tlon software. -// are you getting it? -export function getPostActions({ - post, - channelType, - isMuted, +export function channelActionIdsFor({ + channel, }: { - post: db.Post; - channelType: db.ChannelType; - isMuted?: boolean; -}): ChannelAction[] { + channel: db.Channel; +}): Id[] { + const channelType = channel?.type; switch (channelType) { + case undefined: + return []; case 'gallery': return [ - { id: 'startThread', label: 'Comment on post', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { id: 'copyRef', label: 'Copy link to post', networkDependent: false }, - { id: 'edit', label: 'Edit post', networkDependent: true }, - { id: 'report', label: 'Report post', networkDependent: true }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, + 'startThread', + 'muteThread', + 'copyRef', + 'edit', + 'report', + 'visibility', + 'delete', ]; case 'notebook': return [ - { id: 'startThread', label: 'Comment on post', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { id: 'copyRef', label: 'Copy link to post', networkDependent: false }, - { id: 'edit', label: 'Edit post', networkDependent: true }, - { id: 'report', label: 'Report post', networkDependent: true }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, + 'startThread', + 'muteThread', + 'copyRef', + 'edit', + 'report', + 'visibility', + 'delete', ]; case 'dm': case 'groupDm': return [ - // { id: 'quote', label: 'Quote' }, - { id: 'startThread', label: 'Start thread', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { - id: 'viewReactions', - label: 'View reactions', - networkDependent: false, - }, - { id: 'copyText', label: 'Copy message text', networkDependent: false }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, + 'startThread', + 'muteThread', + 'viewReactions', + 'copyText', + 'visibility', + 'delete', ]; case 'chat': - default: return [ - { id: 'quote', label: 'Quote', networkDependent: true }, - { id: 'startThread', label: 'Start thread', networkDependent: true }, - { - id: 'muteThread', - label: isMuted ? 'Unmute thread' : 'Mute thread', - networkDependent: true, - }, - { - id: 'viewReactions', - label: 'View reactions', - networkDependent: false, - }, - { - id: 'copyRef', - label: 'Copy link to message', - networkDependent: false, - }, - { id: 'copyText', label: 'Copy message text', networkDependent: false }, - { id: 'edit', label: 'Edit message', networkDependent: true }, - { - id: 'visibility', - label: post?.hidden ? 'Show post' : 'Hide post', - networkDependent: true, - }, - { id: 'report', label: 'Report message', networkDependent: true }, - { - id: 'delete', - label: 'Delete message', - actionType: 'destructive', - networkDependent: true, - }, + 'quote', + 'startThread', + 'muteThread', + 'viewReactions', + 'copyRef', + 'copyText', + 'edit', + 'visibility', + 'report', + 'delete', ]; } } +export function staticSpecForId(id: Id): StaticSpec { + return STATIC_SPECS[id]; +} + +const STATIC_SPECS = { + copyRef: { isNetworkDependent: false }, + copyText: { isNetworkDependent: false }, + delete: { isNetworkDependent: true, actionType: 'destructive' }, + edit: { isNetworkDependent: true }, + muteThread: { isNetworkDependent: true }, + quote: { isNetworkDependent: true }, + report: { isNetworkDependent: true }, + startThread: { isNetworkDependent: true }, + viewReactions: { isNetworkDependent: false }, + visibility: { isNetworkDependent: true }, +} satisfies Record; diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 6e067af6eb..0ef1840bf6 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { ViewStyle as TamaguiViewStyle } from 'tamagui'; import * as db from '../db'; -import { ChannelAction, getPostActions } from './ChannelActions'; +import * as ChannelAction from './ChannelActions'; export interface PostCollectionConfiguration { shouldMaintainVisibleContentPosition: boolean; @@ -16,13 +16,6 @@ export interface PostCollectionConfiguration { * landscape, 0.5 for portrait. If null, defers to item sizing. */ itemAspectRatio: number | null; - // TODO: this might make more sense as either a property of a post, or of the - // channel's config (separate from collection config) - postActions: (options: { - post: db.Post; - isMuted?: boolean; - }) => ChannelAction[]; - /** * If true, in the absence of a given title, the channel will be titled in UI * with a comma-separated list of member names. @@ -33,6 +26,8 @@ export interface PostCollectionConfiguration { * If true, entering channel scrolls to the viewer's first unread post. */ enableUnreadAnchor: boolean; + + postActionIds: ChannelAction.Id[]; } // Why overload this function instead of just doing a union? @@ -47,10 +42,8 @@ export function usePostCollectionConfigurationFromChannel( export function usePostCollectionConfigurationFromChannel( channel: db.Channel | null ): PostCollectionConfiguration | null { - const channelType = channel?.type; - return useMemo(() => { - switch (channelType) { + switch (channel?.type) { case null: // fallthrough case undefined: @@ -68,8 +61,8 @@ export function usePostCollectionConfigurationFromChannel( columnCount: 1, dividersEnabled: true, itemAspectRatio: null, - postActions: (options) => getPostActions({ ...options, channelType }), - usesMemberListAsFallbackTitle: channelType !== 'chat', + postActionIds: ChannelAction.channelActionIdsFor({ channel }), + usesMemberListAsFallbackTitle: channel.type !== 'chat', enableUnreadAnchor: true, }; @@ -83,7 +76,7 @@ export function usePostCollectionConfigurationFromChannel( columnCount: 1, dividersEnabled: false, itemAspectRatio: null, - postActions: (options) => getPostActions({ ...options, channelType }), + postActionIds: ChannelAction.channelActionIdsFor({ channel }), usesMemberListAsFallbackTitle: false, enableUnreadAnchor: false, }; @@ -102,10 +95,10 @@ export function usePostCollectionConfigurationFromChannel( columnCount: 2, dividersEnabled: false, itemAspectRatio: 1, - postActions: (options) => getPostActions({ ...options, channelType }), + postActionIds: ChannelAction.channelActionIdsFor({ channel }), usesMemberListAsFallbackTitle: false, enableUnreadAnchor: false, }; } - }, [channelType]); + }, [channel]); } diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 97b16751c4..54d4d7571a 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -387,11 +387,6 @@ const Scroller = forwardRef( }; }, [insets.bottom]); - const postActions = useListPostActions({ - activeMessage, - collectionConfig, - }); - return ( {/* {unreadCount && !hasPressedGoToBottom ? ( @@ -448,7 +443,7 @@ const Scroller = forwardRef( {activeMessage !== null && ( setActiveMessage(null)} onReply={onPressReplies} @@ -857,42 +852,3 @@ function useAnchorScrollLock({ ), }; } - -function useListPostActions({ - activeMessage: post, - collectionConfig, -}: { - collectionConfig: PostCollectionConfiguration; - activeMessage?: db.Post | null; -}): ChannelAction[] { - const currentUserId = useCurrentUserId(); - const getPostActions = collectionConfig.postActions; - return useMemo(() => { - if (post == null) { - return []; - } - - return getPostActions({ - post, - isMuted: logic.isMuted(post.volumeSettings?.level, 'thread'), - }).filter((action) => { - switch (action.id) { - case 'startThread': - // only show start thread if - // 1. the message is delivered - // 2. the message isn't a reply - // 3. an existing thread for that message doesn't already exist - return ( - !post.deliveryStatus && !post.parentId && post.replyCount === 0 - ); - case 'edit': - // only show edit for current user's posts - return post.authorId === currentUserId; - case 'viewReactions': - return (post.reactions?.length ?? 0) > 0; - default: - return true; - } - }); - }, [post, getPostActions, currentUserId]); -} diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx index 585e19e2dc..a9f796e14f 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx @@ -13,14 +13,14 @@ import { MessageContainer } from './MessageContainer'; export function ChatMessageActions({ post, - postActions, + postActionIds, onDismiss, onReply, onEdit, onViewReactions, }: { post: db.Post; - postActions: ChannelAction[]; + postActionIds: ChannelAction.Id[]; postRef: RefObject; onDismiss: () => void; onReply?: (post: db.Post) => void; @@ -70,7 +70,7 @@ export function ChatMessageActions({ ; onDismiss: () => void; width?: DimensionValue; @@ -151,7 +151,7 @@ export function ChatMessageActions({ void; onViewReactions?: (post: db.Post) => void; post: db.Post; - postActions: ChannelAction[]; + postActionIds: ChannelAction.Id[]; }) { - const currentSession = useCurrentSession(); - const currentUserId = useCurrentUserId(); - const { addAttachment } = useAttachmentContext(); - const channel = useChannelContext(); - return ( // arbitrary width that looks reasonable given labels - {postActions.map((action, index) => ( - - handleAction({ - id: action.id, - post, - userId: currentUserId, - channel, - isMuted: logic.isMuted(post.volumeSettings?.level, 'thread'), - dismiss, - onReply, - onEdit, - onViewReactions, - addAttachment, - currentSession, - isNetworkDependent: action.networkDependent, - }) - } - key={action.id} - actionType={action.actionType} - last={index === postActions.length - 1 && !__DEV__} - > - {action.label} - + {postActionIds.map((actionId, index, list) => ( + ))} {ENABLE_COPY_JSON ? : null} ); } +function ConnectedAction({ + actionId, + dismiss, + last, + onEdit, + onReply, + onViewReactions, + post, +}: { + actionId: ChannelAction.Id; + post: db.Post; + last: boolean; + + dismiss: () => void; + onReply?: (post: db.Post) => void; + onEdit?: () => void; + onViewReactions?: (post: db.Post) => void; +}) { + const currentUserId = useCurrentUserId(); + const currentSession = useCurrentSession(); + const channel = useChannelContext(); + const { addAttachment } = useAttachmentContext(); + + const { label } = useDisplaySpecForChannelActionId(actionId, { + post, + channel, + }); + const action = useMemo( + () => ChannelAction.staticSpecForId(actionId), + [actionId] + ); + + const visible = useMemo(() => { + switch (actionId) { + case 'startThread': + // only show start thread if + // 1. the message is delivered + // 2. the message isn't a reply + // 3. an existing thread for that message doesn't already exist + return !post.deliveryStatus && !post.parentId && post.replyCount === 0; + case 'edit': + // only show edit for current user's posts + return post.authorId === currentUserId; + case 'viewReactions': + return (post.reactions?.length ?? 0) > 0; + default: + return true; + } + }, [post, actionId, currentUserId]); + + if (!visible) { + return null; + } + + return ( + + handleAction({ + id: actionId, + post, + userId: currentUserId, + channel, + isMuted: logic.isMuted(post.volumeSettings?.level, 'thread'), + dismiss, + onReply, + onEdit, + onViewReactions, + addAttachment, + currentSession, + isNetworkDependent: action.isNetworkDependent, + }) + } + key={actionId} + actionType={action.actionType} + last={last} + > + {label} + + ); +} + function CopyJsonAction({ post }: { post: db.Post }) { const jsonString = useMemo(() => { return JSON.stringify(post.content, null, 2); @@ -98,7 +156,7 @@ export async function handleAction({ currentSession, isNetworkDependent, }: { - id: string; + id: ChannelAction.Id; post: db.Post; userId: string; channel: db.Channel; @@ -163,3 +221,70 @@ export async function handleAction({ await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); dismiss(); } + +/** + * Extra information about how to display the action. This can change based on + * the UI context - e.g. the label for `startThread` changes based on channel + * type. + */ +export function useDisplaySpecForChannelActionId( + id: ChannelAction.Id, + { + post, + channel, + }: { + post: db.Post; + channel: db.Channel; + } +): { + label: string; +} { + const isMuted = logic.isMuted(post.volumeSettings?.level, 'thread'); + + return useMemo(() => { + switch (id) { + case 'copyRef': + return { + label: + channel?.type === 'chat' + ? 'Copy link to message' + : 'Copy link to post', + }; + + case 'copyText': + return { label: 'Copy message text' }; + + case 'delete': + return { label: 'Delete message' }; + + case 'edit': + return { + label: channel?.type === 'chat' ? 'Edit message' : 'Edit post', + }; + + case 'muteThread': + return { label: isMuted ? 'Unmute thread' : 'Mute thread' }; + + case 'quote': + return { label: 'Quote' }; + + case 'report': + return { + label: channel?.type === 'chat' ? 'Report message' : 'Report post', + }; + + case 'startThread': + return { + label: ['dm', 'groupDm', 'chat'].includes(channel?.type) + ? 'Start thread' + : 'Comment on post', + }; + + case 'viewReactions': + return { label: 'View reactions' }; + + case 'visibility': + return { label: post.hidden ? 'Show post' : 'Hide post' }; + } + }, [channel?.type, isMuted, post.hidden, id]); +} From 39f7014a380db72f8dc1c4fee7b5958edf9ac09a Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 4 Oct 2024 13:04:17 -0700 Subject: [PATCH 011/259] Be consistent about "message"/"post" in action labels --- .../ChatMessageActions/MessageActions.tsx | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx index a199a4ab36..734873a2f2 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx @@ -240,13 +240,18 @@ export function useDisplaySpecForChannelActionId( label: string; } { const isMuted = logic.isMuted(post.volumeSettings?.level, 'thread'); + const postTerm = useMemo(() => { + return ['dm', 'groupDm', 'chat'].includes(channel?.type) + ? 'message' + : 'post'; + }, [channel?.type]); return useMemo(() => { switch (id) { case 'copyRef': return { label: - channel?.type === 'chat' + postTerm === 'message' ? 'Copy link to message' : 'Copy link to post', }; @@ -255,11 +260,13 @@ export function useDisplaySpecForChannelActionId( return { label: 'Copy message text' }; case 'delete': - return { label: 'Delete message' }; + return { + label: postTerm === 'message' ? 'Delete message' : 'Delete post', + }; case 'edit': return { - label: channel?.type === 'chat' ? 'Edit message' : 'Edit post', + label: postTerm === 'message' ? 'Edit message' : 'Edit post', }; case 'muteThread': @@ -270,7 +277,7 @@ export function useDisplaySpecForChannelActionId( case 'report': return { - label: channel?.type === 'chat' ? 'Report message' : 'Report post', + label: postTerm === 'message' ? 'Report message' : 'Report post', }; case 'startThread': @@ -283,8 +290,11 @@ export function useDisplaySpecForChannelActionId( case 'viewReactions': return { label: 'View reactions' }; - case 'visibility': - return { label: post.hidden ? 'Show post' : 'Hide post' }; + case 'visibility': { + const showMsg = postTerm === 'message' ? 'Show message' : 'Show post'; + const hideMsg = postTerm === 'message' ? 'Hide message' : 'Hide post'; + return { label: post.hidden ? showMsg : hideMsg }; + } } - }, [channel?.type, isMuted, post.hidden, id]); + }, [channel?.type, isMuted, post.hidden, id, postTerm]); } From 1cf63b800b40f000d4e2a44915829be217a29859 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 4 Oct 2024 14:03:15 -0700 Subject: [PATCH 012/259] Integrate changes from c3833e3 (dropped from rebase) --- .../ui/src/components/Channel/Scroller.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 54d4d7571a..36d9c6ee93 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -302,16 +302,22 @@ const Scroller = forwardRef( !posts?.length ? { flex: 1 } : collectionConfig.contentContainerStyle ) as StyleProp; - // We want to add a safe area inset for gallery, but we can't cleanly - // access safe area insets in the PostCollectionConfiguration definition. + // We want to add a safe area inset for gallery/notebook, but we can't + // cleanly access safe area insets in the PostCollectionConfiguration + // definition. // Special-case it here. - const extracContentContainerStyle = useMemo( - () => - !posts?.length || channel.type !== 'gallery' - ? undefined - : { paddingBottom: insets.bottom }, - [channel.type, insets, posts?.length] - ); + const extracContentContainerStyle = useMemo(() => { + if (!posts?.length) { + return undefined; + } + if (['notebook', 'gallery'].includes(channel.type)) { + return { + paddingBottom: insets.bottom, + paddingTop: headerMode === 'next' ? insets.top + 54 : 0, + }; + } + return undefined; + }, [channel.type, insets, posts?.length, headerMode]); const columnWrapperStyle = useStyle( collectionConfig.columnCount === 1 From f95e019fd26adf543fcb78b98f3d87090c489c41 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 4 Oct 2024 14:16:45 -0700 Subject: [PATCH 013/259] Move PostCollectionConfiguration#contentContainerStyle back into view --- .../src/types/PostCollectionConfiguration.ts | 21 ++----- .../ui/src/components/Channel/Scroller.tsx | 59 ++++++++++--------- 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 0ef1840bf6..b16c8c0c4c 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -1,12 +1,11 @@ import { useMemo } from 'react'; -import { ViewStyle as TamaguiViewStyle } from 'tamagui'; import * as db from '../db'; import * as ChannelAction from './ChannelActions'; export interface PostCollectionConfiguration { shouldMaintainVisibleContentPosition: boolean; - contentContainerStyle: TamaguiViewStyle; + type: 'compact-list-bottom-to-top' | 'comfy-list-top-to-bottom' | 'grid'; columnCount: 1 | 2; /** if true, enables day / unread dividers between elements */ @@ -54,10 +53,8 @@ export function usePostCollectionConfigurationFromChannel( // fallthrough case 'groupDm': return { + type: 'compact-list-bottom-to-top', shouldMaintainVisibleContentPosition: true, - contentContainerStyle: { - paddingHorizontal: '$m', - }, columnCount: 1, dividersEnabled: true, itemAspectRatio: null, @@ -68,11 +65,8 @@ export function usePostCollectionConfigurationFromChannel( case 'notebook': return { + type: 'comfy-list-top-to-bottom', shouldMaintainVisibleContentPosition: false, - contentContainerStyle: { - paddingHorizontal: '$m', - gap: '$l', - }, columnCount: 1, dividersEnabled: false, itemAspectRatio: null, @@ -83,15 +77,8 @@ export function usePostCollectionConfigurationFromChannel( case 'gallery': return { + type: 'grid', shouldMaintainVisibleContentPosition: false, - contentContainerStyle: { - paddingHorizontal: '$l', - gap: '$l', - - // We can't access safe area insets from this package :( - // Special-case this at call-site. - // paddingBottom: safeAreaInsets.bottom, - }, columnCount: 2, dividersEnabled: false, itemAspectRatio: 1, diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 36d9c6ee93..a77975e9e4 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -1,12 +1,9 @@ import { - ChannelAction, - PostCollectionConfiguration, useMutableCallback, usePostCollectionConfigurationFromChannel, } from '@tloncorp/shared'; import { createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; import { isSameDay } from '@tloncorp/shared/dist/logic'; import { Story } from '@tloncorp/shared/dist/urbit'; import { isEqual } from 'lodash'; @@ -29,14 +26,12 @@ import { ListRenderItem, View as RNView, StyleProp, - StyleSheet, ViewStyle, } from 'react-native'; import Animated from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { View, styled, useStyle, useTheme } from 'tamagui'; -import { useCurrentUserId } from '../../contexts'; import { useLivePost } from '../../contexts/requests'; import { useScrollDirectionTracker } from '../../contexts/scroll'; import { ChatMessageActions } from '../ChatMessage/ChatMessageActions/Component'; @@ -299,25 +294,38 @@ const Scroller = forwardRef( const insets = useSafeAreaInsets(); const contentContainerStyle = useStyle( - !posts?.length ? { flex: 1 } : collectionConfig.contentContainerStyle - ) as StyleProp; + useMemo(() => { + if (!posts?.length) { + return { flex: 1 }; + } - // We want to add a safe area inset for gallery/notebook, but we can't - // cleanly access safe area insets in the PostCollectionConfiguration - // definition. - // Special-case it here. - const extracContentContainerStyle = useMemo(() => { - if (!posts?.length) { - return undefined; - } - if (['notebook', 'gallery'].includes(channel.type)) { - return { - paddingBottom: insets.bottom, - paddingTop: headerMode === 'next' ? insets.top + 54 : 0, - }; - } - return undefined; - }, [channel.type, insets, posts?.length, headerMode]); + switch (collectionConfig.type) { + case 'compact-list-bottom-to-top': { + return { + paddingHorizontal: '$m', + }; + } + + case 'comfy-list-top-to-bottom': { + return { + paddingHorizontal: '$m', + gap: '$l', + paddingBottom: insets.bottom, + paddingTop: headerMode === 'next' ? insets.top + 54 : 0, + }; + } + + case 'grid': { + return { + paddingHorizontal: '$m', + gap: '$l', + paddingBottom: insets.bottom, + paddingTop: headerMode === 'next' ? insets.top + 54 : 0, + }; + } + } + }, [insets, posts?.length, headerMode, collectionConfig.type]) + ) as StyleProp; const columnWrapperStyle = useStyle( collectionConfig.columnCount === 1 @@ -409,10 +417,7 @@ const Scroller = forwardRef( ListEmptyComponent={renderEmptyComponent} keyExtractor={getPostId} keyboardDismissMode="on-drag" - contentContainerStyle={StyleSheet.compose( - contentContainerStyle, - extracContentContainerStyle - )} + contentContainerStyle={contentContainerStyle} columnWrapperStyle={ // FlatList raises an error if `columnWrapperStyle` is provided // with numColumns=1, even if the style is empty From 1bec37093a49d20991e67ad33f069282345ce0ec Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 4 Oct 2024 14:25:12 -0700 Subject: [PATCH 014/259] Add comment --- packages/shared/src/types/PostCollectionConfiguration.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index b16c8c0c4c..c6842ede69 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -5,7 +5,14 @@ import * as ChannelAction from './ChannelActions'; export interface PostCollectionConfiguration { shouldMaintainVisibleContentPosition: boolean; + + /** + * High-level type of collection - specificity is to indicate that e.g. + * `comy-list-top-to-bottom` is different from simply a inverted + * `compact-list-bottom-to-top`. + */ type: 'compact-list-bottom-to-top' | 'comfy-list-top-to-bottom' | 'grid'; + columnCount: 1 | 2; /** if true, enables day / unread dividers between elements */ From 42ddac22aefd7746ad8dffb14403f6832d836fb5 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 4 Oct 2024 14:25:16 -0700 Subject: [PATCH 015/259] Fix lint --- apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx index 71817e472f..627970be00 100644 --- a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx @@ -1,6 +1,6 @@ +import { ChannelAction } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import { ChatMessageActions, Modal, ZStack } from '@tloncorp/ui'; -import { ChannelAction } from 'packages/shared/dist'; import { createRef, useEffect, useState } from 'react'; import { View } from 'react-native'; From ec53b55b5de1347a564a259e444ba54ef14509fb Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 4 Oct 2024 18:08:08 -0500 Subject: [PATCH 016/259] urbit: auth recovery --- .../src/components/AuthenticatedApp.tsx | 49 +- .../screens/Onboarding/ReserveShipScreen.tsx | 8 +- .../screens/Onboarding/ShipLoginScreen.tsx | 1 + .../screens/Onboarding/TlonLoginScreen.tsx | 14 +- packages/app/contexts/ship.tsx | 124 ++--- packages/app/lib/api.ts | 25 +- packages/app/lib/hostingApi.ts | 6 +- packages/shared/src/api/urbit.ts | 438 ++++++++++++------ 8 files changed, 412 insertions(+), 253 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 939b6a9b91..8b918554ae 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -1,4 +1,6 @@ import crashlytics from '@react-native-firebase/crashlytics'; +import { useNavigation } from '@react-navigation/native'; +import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; @@ -7,10 +9,15 @@ import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; import { usePostSignup } from '@tloncorp/app/hooks/usePostSignup'; import { cancelFetch, configureClient } from '@tloncorp/app/lib/api'; +import { getShipAccessCode } from '@tloncorp/app/lib/hostingApi'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; -import { initializeCrashReporter, sync } from '@tloncorp/shared'; +import { + createDevLogger, + initializeCrashReporter, + sync, +} from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; import { useCallback, useEffect } from 'react'; @@ -20,6 +27,9 @@ import { useDeepLinkListener } from '../hooks/useDeepLinkListener'; import useNotificationListener, { type Props as NotificationListenerProps, } from '../hooks/useNotificationListener'; +import { OnboardingStackParamList } from '../types'; + +const appLogger = createDevLogger('app', false); export interface AuthenticatedAppProps { notificationListenerProps: NotificationListenerProps; @@ -28,7 +38,7 @@ export interface AuthenticatedAppProps { function AuthenticatedApp({ notificationListenerProps, }: AuthenticatedAppProps) { - const { ship, shipUrl } = useShip(); + const { ship, shipUrl, authType, setShip } = useShip(); const currentUserId = useCurrentUserId(); const signupContext = useSignupContext(); const handlePostSignup = usePostSignup(); @@ -36,13 +46,46 @@ function AuthenticatedApp({ useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); + const navigation = + useNavigation< + NativeStackNavigationProp< + OnboardingStackParamList, + 'TlonLogin' | 'ShipLogin' + > + >(); useEffect(() => { configureClient({ shipName: ship ?? '', shipUrl: shipUrl ?? '', - onReset: () => sync.syncStart(), verbose: __DEV__, + getCode: + authType === 'self' + ? undefined + : async () => { + appLogger.log('Getting ship access code', { ship, authType }); + if (!ship) { + throw new Error('Trying to retrieve +code, no ship set'); + } + + const { code } = await getShipAccessCode(ship); + return code; + }, + handleAuthFailure: () => { + setShip({ + ship: undefined, + shipUrl, + authType, + authCookie: undefined, + }); + if (authType === 'self') { + navigation.navigate('ShipLogin'); + return; + } + + navigation.navigate('TlonLogin'); + }, + onReset: () => sync.syncStart(), onChannelReset: () => sync.handleDiscontinuity(), onChannelStatusChange: sync.handleChannelStatusChange, }); diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index a62d21435e..e60ac141d2 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -11,10 +11,7 @@ import { } from '@tloncorp/app/lib/hostingApi'; import { trackError, trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { getShipFromCookie, getShipUrl } from '@tloncorp/app/utils/ship'; -import { - configureApi, - getLandscapeAuthCookie, -} from '@tloncorp/shared/dist/api'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; import { Spinner, Text, View, YStack } from '@tloncorp/ui'; import { useCallback, useEffect, useState } from 'react'; import { Alert } from 'react-native'; @@ -77,13 +74,12 @@ export const ReserveShipScreen = ({ } const ship = getShipFromCookie(authCookie); - configureApi(ship, shipUrl); - // Set the ship info in the main context to navigate to chat view setShip({ ship, shipUrl, authCookie, + authType: 'hosted', }); }, [ diff --git a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx index 84d6f2093f..fb35e1c199 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx @@ -96,6 +96,7 @@ export const ShipLoginScreen = ({ navigation }: Props) => { ship: shipId, shipUrl, authCookie, + authType: 'self', }); } else { setRemoteError( diff --git a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx index 56aa9e3b3e..f2e9277fbe 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx @@ -92,14 +92,12 @@ export const TlonLoginScreen = ({ navigation }: Props) => { ); if (authCookie) { if (await isEulaAgreed()) { - setShip( - { - ship: shipId, - shipUrl, - authCookie, - }, - authCookie - ); + setShip({ + ship: shipId, + shipUrl, + authCookie, + authType: 'hosted', + }); } else { setRemoteError( 'Please agree to the End User License Agreement to continue.' diff --git a/packages/app/contexts/ship.tsx b/packages/app/contexts/ship.tsx index c88aecfff2..7da4043ebe 100644 --- a/packages/app/contexts/ship.tsx +++ b/packages/app/contexts/ship.tsx @@ -1,5 +1,4 @@ import crashlytics from '@react-native-firebase/crashlytics'; -import { configureApi } from '@tloncorp/shared/dist/api'; import { preSig } from '@urbit/aura'; import type { ReactNode } from 'react'; import { @@ -17,6 +16,7 @@ import { transformShipURL } from '../utils/string'; const { UrbitModule } = NativeModules; export type ShipInfo = { + authType: 'self' | 'hosted'; ship: string | undefined; shipUrl: string | undefined; authCookie: string | undefined; @@ -29,7 +29,7 @@ type State = ShipInfo & { }; type ContextValue = State & { - setShip: (shipInfo: ShipInfo, authCookie?: string) => void; + setShip: (shipInfo: ShipInfo) => void; clearShip: () => void; }; @@ -46,6 +46,7 @@ export const useShip = () => { }; const emptyShip: ShipInfo = { + authType: 'hosted', ship: undefined, shipUrl: undefined, authCookie: undefined, @@ -55,64 +56,69 @@ export const ShipProvider = ({ children }: { children: ReactNode }) => { const [isLoading, setIsLoading] = useState(true); const [shipInfo, setShipInfo] = useState(emptyShip); - const setShip = useCallback(({ ship, shipUrl, authCookie }: ShipInfo) => { - // Clear all saved ship info if either required field is empty - if (!ship || !shipUrl) { - // Remove from React Native storage - clearShipInfo(); - - // Clear context state - setShipInfo(emptyShip); - - // Clear native storage - UrbitModule.clearUrbit(); - return; - } - - // The passed shipUrl should already be normalized, but defensively ensure it is - const normalizedShipUrl = transformShipURL(shipUrl); - const nextShipInfo = { ship, shipUrl: normalizedShipUrl, authCookie }; - - // Save to React Native stoage - saveShipInfo(nextShipInfo); - - // Save context state - setShipInfo(nextShipInfo); - - // Configure API - configureApi(ship, normalizedShipUrl); - - // Configure analytics - crashlytics().setAttribute( - 'isHosted', - normalizedShipUrl.includes('.tlon.network') ? 'true' : 'false' - ); - - // If cookie was passed in, use it, otherwise fetch from ship - // TODO: This may not be necessary, as I *believe* auth cookie will always - // be stored on successful login. - if (authCookie) { - // Save to native storage - UrbitModule.setUrbit(ship, normalizedShipUrl, authCookie); - } else { - // Run this in the background - (async () => { - // Fetch the root ship URL and parse headers - const response = await fetch(normalizedShipUrl, { - credentials: 'include', - }); - const fetchedAuthCookie = response.headers.get('set-cookie'); - if (fetchedAuthCookie) { - setShipInfo({ ...nextShipInfo, authCookie: fetchedAuthCookie }); - saveShipInfo({ ...nextShipInfo, authCookie: fetchedAuthCookie }); - // Save to native storage - UrbitModule.setUrbit(ship, normalizedShipUrl, fetchedAuthCookie); - } - })(); - } + const setShip = useCallback( + ({ ship, shipUrl, authCookie, authType }: ShipInfo) => { + // Clear all saved ship info if either required field is empty + if (!ship || !shipUrl) { + // Remove from React Native storage + clearShipInfo(); - setIsLoading(false); - }, []); + // Clear context state + setShipInfo(emptyShip); + + // Clear native storage + UrbitModule.clearUrbit(); + return; + } + + // The passed shipUrl should already be normalized, but defensively ensure it is + const normalizedShipUrl = transformShipURL(shipUrl); + const nextShipInfo = { + ship, + shipUrl: normalizedShipUrl, + authCookie, + authType, + }; + + // Save to React Native stoage + saveShipInfo(nextShipInfo); + + // Save context state + setShipInfo(nextShipInfo); + + // Configure analytics + crashlytics().setAttribute( + 'isHosted', + normalizedShipUrl.includes('.tlon.network') ? 'true' : 'false' + ); + + // If cookie was passed in, use it, otherwise fetch from ship + // TODO: This may not be necessary, as I *believe* auth cookie will always + // be stored on successful login. + if (authCookie) { + // Save to native storage + UrbitModule.setUrbit(ship, normalizedShipUrl, authCookie); + } else { + // Run this in the background + (async () => { + // Fetch the root ship URL and parse headers + const response = await fetch(normalizedShipUrl, { + credentials: 'include', + }); + const fetchedAuthCookie = response.headers.get('set-cookie'); + if (fetchedAuthCookie) { + setShipInfo({ ...nextShipInfo, authCookie: fetchedAuthCookie }); + saveShipInfo({ ...nextShipInfo, authCookie: fetchedAuthCookie }); + // Save to native storage + UrbitModule.setUrbit(ship, normalizedShipUrl, fetchedAuthCookie); + } + })(); + } + + setIsLoading(false); + }, + [] + ); useEffect(() => { const loadConnection = async () => { diff --git a/packages/app/lib/api.ts b/packages/app/lib/api.ts index 57cd791937..ea66dd54d4 100644 --- a/packages/app/lib/api.ts +++ b/packages/app/lib/api.ts @@ -1,5 +1,5 @@ import * as api from '@tloncorp/shared/dist/api'; -import { ChannelStatus } from '@urbit/http-api'; +import { ClientParams } from 'packages/shared/src/api'; //@ts-expect-error no typedefs import { fetch as streamingFetch } from 'react-native-fetch-api'; //@ts-expect-error no typedefs @@ -47,28 +47,9 @@ export const cancelFetch = () => { abortController = new AbortController(); }; -export function configureClient({ - shipName, - shipUrl, - onReset, - onChannelReset, - onChannelStatusChange, - verbose, -}: { - shipName: string; - shipUrl: string; - onReset?: () => void; - onChannelReset?: () => void; - onChannelStatusChange?: (status: ChannelStatus) => void; - verbose?: boolean; -}) { +export function configureClient(params: Omit) { api.configureClient({ - shipName, - shipUrl, + ...params, fetchFn: apiFetch, - onReset, - onChannelReset, - onChannelStatusChange, - verbose, }); } diff --git a/packages/app/lib/hostingApi.ts b/packages/app/lib/hostingApi.ts index 4ba13924a7..a13ee67477 100644 --- a/packages/app/lib/hostingApi.ts +++ b/packages/app/lib/hostingApi.ts @@ -64,10 +64,12 @@ const hostingFetch = async ( const responseText = await response.text(); if (__DEV__) { - console.debug('Response:', responseText); + console.debug('Response:', response.status, responseText); } - const result = JSON.parse(responseText) as HostingError | T; + const result = !responseText + ? { message: 'Empty response' } + : (JSON.parse(responseText) as HostingError | T); if (!response.ok) { throw new Error( 'message' in result ? result.message : 'An unknown error has occurred.' diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 37f5df9f10..31eb049ae0 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -1,15 +1,18 @@ import { deSig, preSig } from '@urbit/aura'; -import { ChannelStatus, Urbit } from '@urbit/http-api'; +import { ChannelStatus, PokeInterface, Urbit } from '@urbit/http-api'; import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; +import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); -const config = { - shipName: '', - shipUrl: '', -}; +interface Config + extends Pick { + client: Urbit | null; + subWatchers: Watchers; + pendingAuth: Promise | null; +} type Predicate = (event: any, mark: string) => boolean; interface Watcher { @@ -21,17 +24,55 @@ interface Watcher { type Watchers = Record>; -let clientInstance: Urbit | null = null; -let subWatchers: Watchers = {}; +export type PokeParams = { + app: string; + mark: string; + json: any; +}; + +export class BadResponseError extends Error { + constructor( + public status: number, + public body: string + ) { + super(); + } +} + +interface UrbitEndpoint { + app: string; + path: string; +} + +export interface ClientParams { + shipName: string; + shipUrl: string; + verbose?: boolean; + fetchFn?: typeof fetch; + getCode?: () => Promise; + handleAuthFailure?: () => void; + onReset?: () => void; + onChannelReset?: () => void; + onChannelStatusChange?: (status: ChannelStatus) => void; +} + +const config: Config = { + client: null, + shipUrl: '', + subWatchers: {}, + pendingAuth: null, + getCode: undefined, + handleAuthFailure: undefined, +}; export const client = new Proxy( {}, { get: function (target, prop, receiver) { - if (!clientInstance) { + if (!config.client) { throw new Error('Database not set.'); } - return Reflect.get(clientInstance, prop, receiver); + return Reflect.get(config.client, prop, receiver); }, } ) as Urbit; @@ -54,187 +95,220 @@ export const getCurrentUserIsHosted = () => { export function configureClient({ shipName, shipUrl, - fetchFn, verbose, + fetchFn, + getCode, + handleAuthFailure, onReset, onChannelReset, onChannelStatusChange, -}: { - shipName: string; - shipUrl: string; - fetchFn?: typeof fetch; - verbose?: boolean; - onReset?: () => void; - onChannelReset?: () => void; - onChannelStatusChange?: (status: ChannelStatus) => void; -}) { +}: ClientParams) { logger.log('configuring client', shipName, shipUrl); - clientInstance = new Urbit(shipUrl, undefined, undefined, fetchFn); - clientInstance.ship = deSig(shipName); - clientInstance.our = preSig(shipName); - clientInstance.verbose = verbose; - clientInstance.on('status-update', (event) => { + config.client = new Urbit(shipUrl, '', '', fetchFn); + config.client.ship = deSig(shipName); + config.client.our = preSig(shipName); + config.client.verbose = verbose; + config.shipUrl = shipUrl; + config.getCode = getCode; + config.handleAuthFailure = handleAuthFailure; + + config.client.on('status-update', (event) => { logger.log('status-update', event); onChannelStatusChange?.(event.status); }); - clientInstance.on('fact', (fact) => { + config.client.on('fact', (fact) => { logger.log( 'received message', runIfDev(() => escapeLog(JSON.stringify(fact))) ); }); - clientInstance.onReconnect = () => { + config.client.onReconnect = () => { logger.log('client reconnect'); }; - clientInstance.on('reset', () => { + config.client.on('reset', () => { logger.log('client reset'); - Object.values(subWatchers).forEach((watchers) => { + Object.values(config.subWatchers).forEach((watchers) => { watchers.forEach((watcher) => watcher.reject('Client reset')); }); - subWatchers = {}; + config.subWatchers = {}; onReset?.(); }); - clientInstance.on('seamless-reset', () => { + config.client.on('seamless-reset', () => { logger.log('client seamless-reset'); }); - clientInstance.on('error', (error) => { + config.client.on('error', (error) => { logger.log('client error', error); }); - clientInstance.on('channel-reaped', () => { + config.client.on('channel-reaped', () => { logger.log('client channel-reaped'); onChannelReset?.(); }); - subWatchers = {}; + config.subWatchers = {}; } export function removeUrbitClient() { - clientInstance = null; -} - -interface UrbitEndpoint { - app: string; - path: string; + config.client = null; } function printEndpoint(endpoint: UrbitEndpoint) { return `${endpoint.app}${endpoint.path}`; } -export function subscribe( +export async function subscribe( endpoint: UrbitEndpoint, handler: (update: T) => void, resubscribing = false -) { - if (!clientInstance) { - throw new Error('Tried to subscribe, but Urbit client is not initialized'); - } - - logger.log( - resubscribing ? 'resubscribing to' : 'subscribing to', - printEndpoint(endpoint) - ); - - return clientInstance.subscribe({ - app: endpoint.app, - path: endpoint.path, - event: (event: any, mark: string, id?: number) => { - logger.debug( - `got subscription event on ${printEndpoint(endpoint)}:`, - event - ); - - // first check if anything is watching the subscription for - // tracked pokes - const endpointKey = printEndpoint(endpoint); - const endpointWatchers = subWatchers[endpointKey]; - if (endpointWatchers) { - endpointWatchers.forEach((watcher) => { - if (watcher.predicate(event, mark)) { - logger.debug(`watcher ${watcher.id} predicate met`, event); - watcher.resolve(); - endpointWatchers.delete(watcher.id); - } else { - logger.debug(`watcher ${watcher.id} predicate failed`, event); - } - }); - } +): Promise { + const doSub = async (err?: (error: any, id: string) => void) => { + if (!config.client) { + throw new Error('Client not initialized'); + } + if (config.pendingAuth) { + await config.pendingAuth; + } + logger.log( + resubscribing ? 'resubscribing to' : 'subscribing to', + printEndpoint(endpoint) + ); + return config.client.subscribe({ + app: endpoint.app, + path: endpoint.path, + event: (event: any, mark: string, id?: number) => { + logger.debug( + `got subscription event on ${printEndpoint(endpoint)}:`, + event + ); + + // first check if anything is watching the subscription for + // tracked pokes + const endpointKey = printEndpoint(endpoint); + const endpointWatchers = config.subWatchers[endpointKey]; + if (endpointWatchers) { + endpointWatchers.forEach((watcher) => { + if (watcher.predicate(event, mark)) { + logger.debug(`watcher ${watcher.id} predicate met`, event); + watcher.resolve(); + endpointWatchers.delete(watcher.id); + } else { + logger.debug(`watcher ${watcher.id} predicate failed`, event); + } + }); + } + + // then pass the event along to the subscription handler + handler(event); + }, + quit: () => { + logger.log('subscription quit on', printEndpoint(endpoint)); + subscribe(endpoint, handler, true); + }, + err: (error, id) => { + logger.error(`subscribe error on ${printEndpoint(endpoint)}:`, error); + + if (err) { + logger.log( + 'calling error handler for subscription', + printEndpoint(endpoint) + ); + err(error, id); + } + }, + }); + }; - // then pass the event along to the subscription handler - handler(event); - }, - quit: () => { - logger.log('subscription quit on', printEndpoint(endpoint)); - subscribe(endpoint, handler, true); - }, - err: (error) => { - logger.error(`subscribe error on ${printEndpoint(endpoint)}:`, error); - }, - }); -} + const retry = async (err: any) => { + logger.error('bad subscribe', printEndpoint(endpoint), err); + config.pendingAuth = auth(); + return doSub(); + }; -export const unsubscribe = (subcriptionId: number) => { - if (!clientInstance) { - throw new Error( - 'Tried to unsubscribe, but Urbit client is not initialized' - ); + try { + return doSub(retry); + } catch (err) { + return retry(err); } - clientInstance.unsubscribe(subcriptionId); -}; +} -export const subscribeOnce = async ( +export async function subscribeOnce( endpoint: UrbitEndpoint, timeout?: number -) => { - if (!clientInstance) { - throw new Error( - 'Tried to subscribe once, but Urbit client is not initialized' - ); +) { + if (!config.client) { + throw new Error('Client not initialized'); + } + if (config.pendingAuth) { + await config.pendingAuth; } logger.log('subscribing once to', printEndpoint(endpoint)); - return clientInstance.subscribeOnce(endpoint.app, endpoint.path, timeout); -}; + try { + return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); + } catch (err) { + logger.error('bad subscribeOnce', printEndpoint(endpoint), err); + await auth(); + return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); + } +} -export const configureApi = (shipName: string, shipUrl: string) => { - config.shipName = deSig(shipName); - config.shipUrl = shipUrl; - logger.debug('Configured new Urbit API for', shipName); -}; +export async function unsubscribe(id: number) { + if (!config.client) { + throw new Error('Client not initialized'); + } + if (config.pendingAuth) { + await config.pendingAuth; + } + try { + return config.client.unsubscribe(id); + } catch (err) { + logger.error('bad unsubscribe', id, err); + await auth(); + return config.client.unsubscribe(id); + } +} -export const poke = async ({ - app, - mark, - json, -}: { - app: string; - mark: string; - json: any; -}) => { +export async function poke({ app, mark, json }: PokeParams) { logger.log('poke', app, mark, json); - return clientInstance?.poke({ - app, - mark, - json, - }); -}; + const doPoke = async (params?: Partial>) => { + if (!config.client) { + throw new Error('Client not initialized'); + } + if (config.pendingAuth) { + await config.pendingAuth; + } + return config.client.poke({ + ...params, + app, + mark, + json, + }); + }; + const retry = async (err: any) => { + logger.log('bad poke', app, mark, json, err); + await auth(); + return doPoke(); + }; -export type PokeParams = { - app: string; - mark: string; - json: any; -}; + try { + return doPoke({ onError: retry }); + } catch (err) { + retry(err); + } +} -export const trackedPoke = async ( +export async function trackedPoke( params: PokeParams, endpoint: UrbitEndpoint, predicate: (event: R) => boolean -) => { +) { + if (config.pendingAuth) { + await config.pendingAuth; + } try { const tracking = track(endpoint, predicate); const poking = poke(params); @@ -243,48 +317,106 @@ export const trackedPoke = async ( logger.error(`tracked poke failed`, e); throw e; } -}; +} -const track = async ( +async function track( endpoint: UrbitEndpoint, predicate: (event: R) => boolean -) => { +) { const endpointKey = printEndpoint(endpoint); return new Promise((resolve, reject) => { - const watchers = subWatchers[endpointKey] || new Map(); + const watchers = config.subWatchers[endpointKey] || new Map(); const id = _.uniqueId(); - subWatchers[endpointKey] = watchers.set(id, { + config.subWatchers[endpointKey] = watchers.set(id, { id, predicate, resolve, reject, }); }); -}; - -export class BadResponseError extends Error { - constructor( - public status: number, - public body: string - ) { - super(); - } } -export const scry = async ({ app, path }: { app: string; path: string }) => { +export async function scry({ app, path }: { app: string; path: string }) { + if (!config.client) { + throw new Error('Client not initialized'); + } + if (config.pendingAuth) { + await config.pendingAuth; + } logger.log('scry', app, path); - const res = await fetch(`${config.shipUrl}/~/scry/${app}${path}.json`, { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - credentials: 'include', - }); - if (!res.ok) { + try { + return await config.client.scry({ app, path }); + } catch (res) { logger.log('bad scry', app, path, res.status); + if (res.status === 403) { + logger.log('scry failed with 403, authing to try again'); + await auth(); + return config.client.scry({ app, path }); + } const body = await res.text(); throw new BadResponseError(res.status, body); } - return (await res.json()) as T; -}; +} + +async function auth() { + if (!config.getCode) { + console.warn('No getCode function provided for auth'); + if (config.handleAuthFailure) { + return config.handleAuthFailure(); + } + + throw new Error('Unable to authenticate with urbit'); + } + + if (config.pendingAuth) { + await config.pendingAuth; + } + + try { + let tries = 0; + logger.log('getting urbit code'); + const code = await config.getCode(); + config.pendingAuth = new Promise((resolve, reject) => { + const tryAuth = async () => { + logger.log('trying to auth with code', code); + const authCookie = await getLandscapeAuthCookie(config.shipUrl, code); + + if (!authCookie && tries < 3) { + logger.log('auth failed, trying again', tries); + tries++; + setTimeout(tryAuth, 1000 + 2 ** tries * 1000); + return; + } + + if (!authCookie) { + if (config.handleAuthFailure) { + logger.log('auth failed, calling auth failure handler'); + config.pendingAuth = null; + return config.handleAuthFailure(); + } + + config.pendingAuth = null; + reject(new Error("Couldn't authenticate with urbit")); + return; + } + + config.pendingAuth = null; + resolve(authCookie); + return; + }; + + tryAuth(); + }); + + return config.pendingAuth; + } catch (e) { + logger.error('error getting urbit code', e); + config.pendingAuth = null; + if (config.handleAuthFailure) { + return config.handleAuthFailure(); + } + + throw e; + } +} From b1e6fbd5062c183cef7c00b6c53d1cbbd60a7760 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 7 Oct 2024 10:27:53 -0700 Subject: [PATCH 017/259] Split collection config into layout type, layout, collection config --- packages/shared/src/index.ts | 6 +- .../src/types/PostCollectionConfiguration.ts | 191 ++++++++++++------ .../ui/src/components/Channel/Scroller.tsx | 37 ++-- packages/ui/src/components/Channel/index.tsx | 20 +- packages/ui/src/utils/channelUtils.tsx | 16 +- 5 files changed, 177 insertions(+), 93 deletions(-) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index eec4c906cb..f39b19f332 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -11,7 +11,11 @@ export type { } from './types/native'; export { PostCollectionConfiguration, - usePostCollectionConfigurationFromChannel, + PostCollectionLayout, + PostCollectionLayoutType, + postCollectionConfigurationFromChannel, + postCollectionLayoutForType, + postCollectionLayoutTypeFromChannel, } from './types/PostCollectionConfiguration'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index c6842ede69..bab8269c9d 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -1,27 +1,111 @@ -import { useMemo } from 'react'; - import * as db from '../db'; import * as ChannelAction from './ChannelActions'; -export interface PostCollectionConfiguration { - shouldMaintainVisibleContentPosition: boolean; +/** + * How do we want to lay out a collection of posts, at a high level? + */ +export type PostCollectionLayoutType = + | 'compact-list-bottom-to-top' // think: chat + | 'comfy-list-top-to-bottom' // think: notebook + | 'grid'; // think: gallery + +// Why overload this function instead of just doing a union? +// If the caller has a non-nullable `channel`, they can then get a +// non-nullable return value - nice, right? +export function postCollectionLayoutTypeFromChannel( + channel: db.Channel +): PostCollectionLayoutType; +export function postCollectionLayoutTypeFromChannel( + channel: db.Channel | null +): PostCollectionLayoutType | null; +export function postCollectionLayoutTypeFromChannel( + channel: db.Channel | null +): PostCollectionLayoutType | null { + switch (channel?.type) { + case null: + // fallthrough + case undefined: + return null; + + case 'chat': + // fallthrough + case 'dm': + // fallthrough + case 'groupDm': + return 'compact-list-bottom-to-top'; + + case 'notebook': + return 'comfy-list-top-to-bottom'; + + case 'gallery': + return 'grid'; + } +} +/** + * Features of a given `PostCollectionLayoutType` - these should be constant + * w.r.t. the layout type (i.e. not change based on whether the channel is a DM + * vs chat). + * If you need to branch based on the channel type, try using + * `PostCollectionConfiguration` instead. + */ +export interface PostCollectionLayout { /** - * High-level type of collection - specificity is to indicate that e.g. - * `comy-list-top-to-bottom` is different from simply a inverted - * `compact-list-bottom-to-top`. + * When new content comes in, should we try to keep the user's scroll position? */ - type: 'compact-list-bottom-to-top' | 'comfy-list-top-to-bottom' | 'grid'; + shouldMaintainVisibleContentPosition: boolean; columnCount: 1 | 2; /** if true, enables day / unread dividers between elements */ dividersEnabled: boolean; - /** Width/height ratio for a collection element; e.g. 1 for square, 2 for - * landscape, 0.5 for portrait. If null, defers to item sizing. */ + /** + * Width/height ratio for a collection element; e.g. 1 for square, 2 for + * landscape, 0.5 for portrait. If null, defers to item sizing. + */ itemAspectRatio: number | null; + /** + * If true, entering channel scrolls to the viewer's first unread post. + */ + enableUnreadAnchor: boolean; +} + +export function postCollectionLayoutForType( + layoutType: PostCollectionLayoutType +): PostCollectionLayout { + switch (layoutType) { + case 'compact-list-bottom-to-top': + return { + shouldMaintainVisibleContentPosition: true, + columnCount: 1, + dividersEnabled: true, + itemAspectRatio: null, + enableUnreadAnchor: true, + }; + + case 'comfy-list-top-to-bottom': + return { + shouldMaintainVisibleContentPosition: false, + columnCount: 1, + dividersEnabled: false, + itemAspectRatio: null, + enableUnreadAnchor: false, + }; + + case 'grid': + return { + shouldMaintainVisibleContentPosition: false, + columnCount: 2, + dividersEnabled: false, + itemAspectRatio: 1, + enableUnreadAnchor: false, + }; + } +} + +export interface PostCollectionConfiguration { /** * If true, in the absence of a given title, the channel will be titled in UI * with a comma-separated list of member names. @@ -29,70 +113,45 @@ export interface PostCollectionConfiguration { usesMemberListAsFallbackTitle: boolean; /** - * If true, entering channel scrolls to the viewer's first unread post. + * What actions should we show in the post context menu? */ - enableUnreadAnchor: boolean; - postActionIds: ChannelAction.Id[]; } -// Why overload this function instead of just doing a union? -// If the caller has a non-nullable `channel`, they can then get a -// non-nullable return value - nice, right? -export function usePostCollectionConfigurationFromChannel( +export function postCollectionConfigurationFromChannel( channel: db.Channel ): PostCollectionConfiguration; -export function usePostCollectionConfigurationFromChannel( +export function postCollectionConfigurationFromChannel( channel: db.Channel | null ): PostCollectionConfiguration | null; -export function usePostCollectionConfigurationFromChannel( +export function postCollectionConfigurationFromChannel( channel: db.Channel | null ): PostCollectionConfiguration | null { - return useMemo(() => { - switch (channel?.type) { - case null: - // fallthrough - case undefined: - return null; - case 'chat': - // fallthrough - case 'dm': - // fallthrough - case 'groupDm': - return { - type: 'compact-list-bottom-to-top', - shouldMaintainVisibleContentPosition: true, - columnCount: 1, - dividersEnabled: true, - itemAspectRatio: null, - postActionIds: ChannelAction.channelActionIdsFor({ channel }), - usesMemberListAsFallbackTitle: channel.type !== 'chat', - enableUnreadAnchor: true, - }; - - case 'notebook': - return { - type: 'comfy-list-top-to-bottom', - shouldMaintainVisibleContentPosition: false, - columnCount: 1, - dividersEnabled: false, - itemAspectRatio: null, - postActionIds: ChannelAction.channelActionIdsFor({ channel }), - usesMemberListAsFallbackTitle: false, - enableUnreadAnchor: false, - }; - - case 'gallery': - return { - type: 'grid', - shouldMaintainVisibleContentPosition: false, - columnCount: 2, - dividersEnabled: false, - itemAspectRatio: 1, - postActionIds: ChannelAction.channelActionIdsFor({ channel }), - usesMemberListAsFallbackTitle: false, - enableUnreadAnchor: false, - }; - } - }, [channel]); + switch (channel?.type) { + case null: + // fallthrough + case undefined: + return null; + case 'chat': + // fallthrough + case 'dm': + // fallthrough + case 'groupDm': + return { + postActionIds: ChannelAction.channelActionIdsFor({ channel }), + usesMemberListAsFallbackTitle: channel.type !== 'chat', + }; + + case 'notebook': + return { + postActionIds: ChannelAction.channelActionIdsFor({ channel }), + usesMemberListAsFallbackTitle: false, + }; + + case 'gallery': + return { + postActionIds: ChannelAction.channelActionIdsFor({ channel }), + usesMemberListAsFallbackTitle: false, + }; + } } diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index a77975e9e4..8285ef1494 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -1,6 +1,8 @@ import { + postCollectionConfigurationFromChannel, + postCollectionLayoutForType, + postCollectionLayoutTypeFromChannel, useMutableCallback, - usePostCollectionConfigurationFromChannel, } from '@tloncorp/shared'; import { createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; @@ -140,7 +142,18 @@ const Scroller = forwardRef( }, ref ) => { - const collectionConfig = usePostCollectionConfigurationFromChannel(channel); + const collectionLayoutType = useMemo( + () => postCollectionLayoutTypeFromChannel(channel), + [channel] + ); + const collectionLayout = useMemo( + () => postCollectionLayoutForType(collectionLayoutType), + [collectionLayoutType] + ); + const collectionConfig = useMemo( + () => postCollectionConfigurationFromChannel(channel), + [channel] + ); const [isAtBottom, setIsAtBottom] = useState(true); @@ -188,7 +201,7 @@ const Scroller = forwardRef( flatListRef, hasNewerPosts, shouldMaintainVisibleContentPosition: - collectionConfig.shouldMaintainVisibleContentPosition, + collectionLayout.shouldMaintainVisibleContentPosition, }); const theme = useTheme(); @@ -261,8 +274,8 @@ const Scroller = forwardRef( onLongPressPost={handlePostLongPressed} activeMessage={activeMessage} messageRef={activeMessageRefs.current[post.id]} - dividersEnabled={collectionConfig.dividersEnabled} - itemAspectRatio={collectionConfig.itemAspectRatio ?? undefined} + dividersEnabled={collectionLayout.dividersEnabled} + itemAspectRatio={collectionLayout.itemAspectRatio ?? undefined} {...anchorScrollLockScrollerItemProps} /> ); @@ -286,8 +299,8 @@ const Scroller = forwardRef( handlePostLongPressed, activeMessage, showDividers, - collectionConfig.dividersEnabled, - collectionConfig.itemAspectRatio, + collectionLayout.dividersEnabled, + collectionLayout.itemAspectRatio, ] ); @@ -299,7 +312,7 @@ const Scroller = forwardRef( return { flex: 1 }; } - switch (collectionConfig.type) { + switch (collectionLayoutType) { case 'compact-list-bottom-to-top': { return { paddingHorizontal: '$m', @@ -324,11 +337,11 @@ const Scroller = forwardRef( }; } } - }, [insets, posts?.length, headerMode, collectionConfig.type]) + }, [insets, posts?.length, headerMode, collectionLayoutType]) ) as StyleProp; const columnWrapperStyle = useStyle( - collectionConfig.columnCount === 1 + collectionLayout.columnCount === 1 ? {} : { gap: '$l', @@ -421,7 +434,7 @@ const Scroller = forwardRef( columnWrapperStyle={ // FlatList raises an error if `columnWrapperStyle` is provided // with numColumns=1, even if the style is empty - collectionConfig.columnCount === 1 + collectionLayout.columnCount === 1 ? undefined : columnWrapperStyle } @@ -435,7 +448,7 @@ const Scroller = forwardRef( initialNumToRender={INITIAL_POSTS_PER_PAGE} maxToRenderPerBatch={8} windowSize={8} - numColumns={collectionConfig.columnCount} + numColumns={collectionLayout.columnCount} style={style} onEndReached={handleEndReached} onEndReachedThreshold={1} diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 2fec200861..4c292cce97 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -1,4 +1,7 @@ -import { usePostCollectionConfigurationFromChannel } from '@tloncorp/shared'; +import { + postCollectionLayoutForType, + postCollectionLayoutTypeFromChannel, +} from '@tloncorp/shared'; import { isChatChannel as getIsChatChannel, useChannel as useChannelFromStore, @@ -133,8 +136,11 @@ export function Channel({ const currentUserId = useCurrentUserId(); const canWrite = utils.useCanWrite(channel, currentUserId); - const postCollectionConfig = - usePostCollectionConfigurationFromChannel(channel); + const collectionLayout = useMemo( + () => + postCollectionLayoutForType(postCollectionLayoutTypeFromChannel(channel)), + [channel] + ); const isChatChannel = channel ? getIsChatChannel(channel) : true; const renderItem = isChatChannel @@ -174,7 +180,7 @@ export function Channel({ return { type: 'selected', postId: selectedPostId }; } - if (postCollectionConfig.enableUnreadAnchor) { + if (collectionLayout.enableUnreadAnchor) { if ( initialChannelUnread?.countWithoutThreads && initialChannelUnread.firstUnreadPostId @@ -188,7 +194,7 @@ export function Channel({ return null; }, [ - postCollectionConfig.enableUnreadAnchor, + collectionLayout.enableUnreadAnchor, selectedPostId, initialChannelUnread, ]); @@ -323,8 +329,8 @@ export function Channel({ editPost={editPost} channel={channel} firstUnreadId={ - initialChannelUnread?.countWithoutThreads ?? - 0 > 0 + (initialChannelUnread?.countWithoutThreads ?? + 0 > 0) ? initialChannelUnread?.firstUnreadPostId : null } diff --git a/packages/ui/src/utils/channelUtils.tsx b/packages/ui/src/utils/channelUtils.tsx index 9e7369012f..bd0f35932c 100644 --- a/packages/ui/src/utils/channelUtils.tsx +++ b/packages/ui/src/utils/channelUtils.tsx @@ -1,4 +1,4 @@ -import { usePostCollectionConfigurationFromChannel } from '@tloncorp/shared'; +import { postCollectionConfigurationFromChannel } from '@tloncorp/shared'; import type * as db from '@tloncorp/shared/dist/db'; import { useMemberRoles } from '@tloncorp/shared/dist/store'; import { useMemo } from 'react'; @@ -37,9 +37,9 @@ function getChannelTitle({ // (There should be no path to titling a 1:1 DM in-app.) return channelTitle ? channelTitle - : members + : (members ?.map((member) => getChannelMemberName(member, disableNicknames)) - .join(', ') ?? 'No title'; + .join(', ') ?? 'No title'); } else { return channelTitle ?? 'Untitled channel'; } @@ -47,10 +47,12 @@ function getChannelTitle({ export function useChannelTitle(channel: db.Channel | null) { const { disableNicknames } = useCalm(); - const usesMemberListAsFallbackTitle = - usePostCollectionConfigurationFromChannel( - channel - )?.usesMemberListAsFallbackTitle; + const usesMemberListAsFallbackTitle = useMemo( + () => + postCollectionConfigurationFromChannel(channel) + ?.usesMemberListAsFallbackTitle, + [channel] + ); return useMemo( () => From a1cdfa2b76cf211cc40fe88c3879a4554f176265 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 7 Oct 2024 10:29:34 -0700 Subject: [PATCH 018/259] gotta cop the sort, you already know the vibes --- .../src/types/PostCollectionConfiguration.ts | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index bab8269c9d..75bd4938b6 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -5,8 +5,8 @@ import * as ChannelAction from './ChannelActions'; * How do we want to lay out a collection of posts, at a high level? */ export type PostCollectionLayoutType = - | 'compact-list-bottom-to-top' // think: chat | 'comfy-list-top-to-bottom' // think: notebook + | 'compact-list-bottom-to-top' // think: chat | 'grid'; // think: gallery // Why overload this function instead of just doing a union? @@ -50,16 +50,16 @@ export function postCollectionLayoutTypeFromChannel( * `PostCollectionConfiguration` instead. */ export interface PostCollectionLayout { - /** - * When new content comes in, should we try to keep the user's scroll position? - */ - shouldMaintainVisibleContentPosition: boolean; - columnCount: 1 | 2; /** if true, enables day / unread dividers between elements */ dividersEnabled: boolean; + /** + * If true, entering channel scrolls to the viewer's first unread post. + */ + enableUnreadAnchor: boolean; + /** * Width/height ratio for a collection element; e.g. 1 for square, 2 for * landscape, 0.5 for portrait. If null, defers to item sizing. @@ -67,9 +67,9 @@ export interface PostCollectionLayout { itemAspectRatio: number | null; /** - * If true, entering channel scrolls to the viewer's first unread post. + * When new content comes in, should we try to keep the user's scroll position? */ - enableUnreadAnchor: boolean; + shouldMaintainVisibleContentPosition: boolean; } export function postCollectionLayoutForType( @@ -78,44 +78,44 @@ export function postCollectionLayoutForType( switch (layoutType) { case 'compact-list-bottom-to-top': return { - shouldMaintainVisibleContentPosition: true, columnCount: 1, dividersEnabled: true, - itemAspectRatio: null, enableUnreadAnchor: true, + itemAspectRatio: null, + shouldMaintainVisibleContentPosition: true, }; case 'comfy-list-top-to-bottom': return { - shouldMaintainVisibleContentPosition: false, columnCount: 1, dividersEnabled: false, - itemAspectRatio: null, enableUnreadAnchor: false, + itemAspectRatio: null, + shouldMaintainVisibleContentPosition: false, }; case 'grid': return { - shouldMaintainVisibleContentPosition: false, columnCount: 2, dividersEnabled: false, - itemAspectRatio: 1, enableUnreadAnchor: false, + itemAspectRatio: 1, + shouldMaintainVisibleContentPosition: false, }; } } export interface PostCollectionConfiguration { /** - * If true, in the absence of a given title, the channel will be titled in UI - * with a comma-separated list of member names. + * What actions should we show in the post context menu? */ - usesMemberListAsFallbackTitle: boolean; + postActionIds: ChannelAction.Id[]; /** - * What actions should we show in the post context menu? + * If true, in the absence of a given title, the channel will be titled in UI + * with a comma-separated list of member names. */ - postActionIds: ChannelAction.Id[]; + usesMemberListAsFallbackTitle: boolean; } export function postCollectionConfigurationFromChannel( From 985ec2dafd5fc980c8b520bc1456148b15dce979 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 7 Oct 2024 10:43:45 -0700 Subject: [PATCH 019/259] Add comment --- packages/shared/src/types/PostCollectionConfiguration.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 75bd4938b6..6df165eece 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -88,7 +88,7 @@ export function postCollectionLayoutForType( case 'comfy-list-top-to-bottom': return { columnCount: 1, - dividersEnabled: false, + dividersEnabled: true, enableUnreadAnchor: false, itemAspectRatio: null, shouldMaintainVisibleContentPosition: false, @@ -105,6 +105,10 @@ export function postCollectionLayoutForType( } } +/** + * Configuration for a post collection which may depend on the channel type or + * other runtime factors. + */ export interface PostCollectionConfiguration { /** * What actions should we show in the post context menu? From ccc41be6272018c57c2fd226f6594cc7b15d4ec3 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 7 Oct 2024 10:59:00 -0700 Subject: [PATCH 020/259] lint --- packages/ui/src/components/Activity/ActivityListItem.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ui/src/components/Activity/ActivityListItem.tsx b/packages/ui/src/components/Activity/ActivityListItem.tsx index a90fd480ed..b91a829f01 100644 --- a/packages/ui/src/components/Activity/ActivityListItem.tsx +++ b/packages/ui/src/components/Activity/ActivityListItem.tsx @@ -61,10 +61,10 @@ export function ActivityListItemContent({ const channel: db.Channel | undefined = newestPost.channel ?? undefined; const modelUnread = summary.type === 'post' - ? newestPost.channel?.unread ?? null + ? (newestPost.channel?.unread ?? null) : summary.type === 'group-ask' - ? newestPost.group?.unread ?? null - : newestPost.parent?.threadUnread ?? null; + ? (newestPost.group?.unread ?? null) + : (newestPost.parent?.threadUnread ?? null); const { data: unread } = store.useLiveUnread(modelUnread); const unreadCount = useMemo(() => { return (isGroupUnread(unread) ? unread.notifyCount : unread?.count) ?? 0; From 7abe0b0de0ccfa60568f1ea6c20471610b4cb089 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 7 Oct 2024 10:59:10 -0700 Subject: [PATCH 021/259] Unfurl title calculation --- .../components/Activity/ActivityListItem.tsx | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/components/Activity/ActivityListItem.tsx b/packages/ui/src/components/Activity/ActivityListItem.tsx index b91a829f01..4cf4f50225 100644 --- a/packages/ui/src/components/Activity/ActivityListItem.tsx +++ b/packages/ui/src/components/Activity/ActivityListItem.tsx @@ -71,16 +71,21 @@ export function ActivityListItemContent({ }, [unread]); const channelTitle = useChannelTitle(channel ?? null); - const title = - channel == null || channelTitle == null - ? group - ? group.title ?? '' - : '' - : channel.type === 'dm' - ? 'Direct message' - : channel.type === 'groupDm' - ? 'Group chat' - : (group?.title ? group.title + ': ' : '') + channelTitle; + const title = useMemo(() => { + if (channel == null || channelTitle == null) { + return group?.title ?? ''; + } + if (channel.type === 'dm') { + return 'Direct message'; + } + if (channel.type === 'groupDm') { + return 'Group chat'; + } + if (group?.title) { + return `${group.title}: ${channelTitle}`; + } + return channelTitle; + }, [channelTitle, channel, group]); return ( Date: Mon, 7 Oct 2024 11:13:58 -0700 Subject: [PATCH 022/259] Unset dividersEnabled on notebook (whoops) --- packages/shared/src/types/PostCollectionConfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 6df165eece..6e46284ab5 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -88,7 +88,7 @@ export function postCollectionLayoutForType( case 'comfy-list-top-to-bottom': return { columnCount: 1, - dividersEnabled: true, + dividersEnabled: false, enableUnreadAnchor: false, itemAspectRatio: null, shouldMaintainVisibleContentPosition: false, From f9c62bc920ee19a7c1a9d86eb54f9eceee3ad749 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 7 Oct 2024 11:32:13 -0700 Subject: [PATCH 023/259] Control Scroller#inverted using post collection layout --- packages/shared/src/types/PostCollectionConfiguration.ts | 5 +++++ packages/ui/src/components/Channel/index.tsx | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 6e46284ab5..8562002f25 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -70,6 +70,8 @@ export interface PostCollectionLayout { * When new content comes in, should we try to keep the user's scroll position? */ shouldMaintainVisibleContentPosition: boolean; + + scrollDirection: 'bottom-to-top' | 'top-to-bottom'; } export function postCollectionLayoutForType( @@ -83,6 +85,7 @@ export function postCollectionLayoutForType( enableUnreadAnchor: true, itemAspectRatio: null, shouldMaintainVisibleContentPosition: true, + scrollDirection: 'bottom-to-top', }; case 'comfy-list-top-to-bottom': @@ -92,6 +95,7 @@ export function postCollectionLayoutForType( enableUnreadAnchor: false, itemAspectRatio: null, shouldMaintainVisibleContentPosition: false, + scrollDirection: 'top-to-bottom', }; case 'grid': @@ -101,6 +105,7 @@ export function postCollectionLayoutForType( enableUnreadAnchor: false, itemAspectRatio: 1, shouldMaintainVisibleContentPosition: false, + scrollDirection: 'top-to-bottom', }; } } diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 4c292cce97..d25cd17f5a 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -317,7 +317,10 @@ export function Channel({ {channel && posts && ( Date: Tue, 8 Oct 2024 16:42:50 -0400 Subject: [PATCH 024/259] store changes --- apps/tlon-mobile/src/types.ts | 2 + packages/app/contexts/signup.tsx | 195 ++++++++++++++++- packages/app/hooks/useSignupBootStatus.ts | 251 ++++++++++++++++++++++ packages/app/lib/bootHelpers.ts | 159 ++++++++++++++ 4 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 packages/app/hooks/useSignupBootStatus.ts create mode 100644 packages/app/lib/bootHelpers.ts diff --git a/apps/tlon-mobile/src/types.ts b/apps/tlon-mobile/src/types.ts index 542b970958..0568c60990 100644 --- a/apps/tlon-mobile/src/types.ts +++ b/apps/tlon-mobile/src/types.ts @@ -123,6 +123,8 @@ export type User = { verified: boolean; }; +export type HostingUser = User; + export type ReservableShip = { id: string; readyForDistribution: boolean; diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index 9b5e3c2427..ea91163a0a 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -1,10 +1,29 @@ -import { createContext, useCallback, useContext, useState } from 'react'; +import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from 'packages/shared/dist'; +import { + createContext, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; + +import { NodeBootPhase } from '../lib/bootHelpers'; +import BootHelpers from '../lib/bootHelpers'; +import { useLureMetadata } from './branch'; +import { useShip } from './ship'; + +const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); interface SignupValues { nickname?: string; notificationToken?: string; telemetry?: boolean; didSignup?: boolean; + + hostingUser: { id: string } | null; + reservedNodeId: string | null; + bootPhase: NodeBootPhase; } interface SignupContext extends SignupValues { @@ -15,8 +34,11 @@ interface SignupContext extends SignupValues { clear: () => void; } -const defaultContext = { +const defaultContext: SignupContext = { nickname: undefined, + hostingUser: null, + reservedNodeId: null, + bootPhase: NodeBootPhase.IDLE, setNickname: () => {}, setNotificationToken: () => {}, setTelemetry: () => {}, @@ -24,10 +46,171 @@ const defaultContext = { clear: () => {}, }; +const logger = createDevLogger('signup', true); + const SignupContext = createContext(defaultContext); export const SignupProvider = ({ children }: { children: React.ReactNode }) => { - const [values, setValues] = useState({}); + const [values, setValues] = useState(defaultContext); + const { setShip } = useShip(); + const lureMeta = useLureMetadata(); + + const setBootPhase = useCallback((bootPhase: NodeBootPhase) => { + setValues((current) => ({ + ...current, + bootPhase, + })); + }, []); + + const initializeBootSequence = useCallback(() => { + if (values.bootPhase === NodeBootPhase.IDLE) { + setValues((current) => ({ + ...current, + bootPhase: NodeBootPhase.RESERVING, + })); + } + }, [values]); + + const runBootSequence = useCallback(async () => { + const { hostingUser, bootPhase } = values; + logger.log(`running boot sequence phase: ${bootPhase}`); + + if (!hostingUser) { + logger.log('no hosting user found, skipping'); + return; + } + + // Step 1: reserve a node + if (bootPhase === NodeBootPhase.RESERVING) { + const reservedNodeId = await BootHelpers.reserveNode(hostingUser.id); + setValues((current) => ({ + ...current, + reservedNodeId, + bootPhase: NodeBootPhase.BOOTING, + })); + logger.log(`reserved node`, reservedNodeId); + return; + } + + if (!values.reservedNodeId) { + throw new Error( + `cannot run boot phase ${bootPhase} without a reserved node` + ); + } + + // Step 2: confirm the node has finished booting on hosting + if (bootPhase === NodeBootPhase.BOOTING) { + const isReady = await BootHelpers.checkNodeBooted(values.reservedNodeId); + if (isReady) { + setValues((current) => ({ + ...current, + bootPhase: NodeBootPhase.AUTHENTICATING, + })); + logger.log('checked hosting, node is ready'); + } else { + logger.log('checked hosting, node still booting'); + } + return; + } + + // Step 3: authenticate with the node itself + if (bootPhase === NodeBootPhase.AUTHENTICATING) { + const auth = await BootHelpers.authenticateNode(values.reservedNodeId); + setShip({ + ship: auth.nodeId, + shipUrl: auth.nodeUrl, + authCookie: auth.authCookie, + }); + + // TODO: connect to the API client? + + const signedUpWithInvite = Boolean(lureMeta?.id); + setValues((current) => ({ + ...current, + bootPhase: signedUpWithInvite + ? NodeBootPhase.CHECKING_FOR_INVITE + : NodeBootPhase.READY, + })); + return; + } + + // Step 4 [optional]: if we used an invite code to signup, see if we got the invites + if (bootPhase === NodeBootPhase.CHECKING_FOR_INVITE) { + const { invitedDm, invitedGroup } = + await BootHelpers.getInvitedGroupAndDm(lureMeta); + + if (invitedDm && invitedGroup) { + setValues((current) => ({ + ...current, + bootPhase: NodeBootPhase.ACCEPTING_INVITES, + })); + logger.log('confirmed node has the invites'); + } else { + logger.log('checked node for invites, not yet found'); + } + return; + } + + // Step 5 [optional]: join the invited groups + if (bootPhase === NodeBootPhase.ACCEPTING_INVITES) { + const { invitedDm, invitedGroup } = + await BootHelpers.getInvitedGroupAndDm(lureMeta); + + if (invitedDm && invitedDm.isDmInvite) { + logger.log(`accepting dm invitation`); + await store.respondToDMInvite({ channel: invitedDm, accept: true }); + } + + if ( + invitedGroup && + !invitedGroup.currentUserIsMember && + invitedGroup.haveInvite + ) { + logger.log('accepting group invitation'); + await store.joinGroup(invitedGroup); + } + + // give the join & accept some time to process, the hard refresh data + await wait(2000); + if (invitedGroup) { + await store.syncGroup(invitedGroup?.id); + } + if (invitedDm) { + await store.syncDms(); + } + + const { invitedDm: updatedDm, invitedGroup: updatedGroup } = + await BootHelpers.getInvitedGroupAndDm(lureMeta); + + const dmIsGood = updatedDm && !updatedDm.isDmInvite; + const groupIsGood = + updatedGroup && + updatedGroup.currentUserIsMember && + updatedGroup.channels && + updatedGroup.channels.length > 0; + + if (dmIsGood && groupIsGood) { + setValues((current) => ({ + ...current, + bootPhase: NodeBootPhase.READY, + })); + logger.log('successfully accepted invites'); + } else { + logger.log('still waiting on invites to be accepted'); + } + return; + } + }, [lureMeta, setShip, values]); + + useEffect(() => { + let timer: NodeJS.Timeout; + if (values.bootPhase !== NodeBootPhase.READY) { + timer = setInterval(() => { + runBootSequence(); + }, 5000); + } + return () => clearInterval(timer); + }, [values.bootPhase, runBootSequence]); const setNickname = useCallback((nickname: string | undefined) => { setValues((current) => ({ @@ -61,7 +244,11 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { }, []); const clear = useCallback(() => { - setValues({}); + setValues({ + bootPhase: NodeBootPhase.IDLE, + hostingUser: null, + reservedNodeId: null, + }); }, []); return ( diff --git a/packages/app/hooks/useSignupBootStatus.ts b/packages/app/hooks/useSignupBootStatus.ts new file mode 100644 index 0000000000..399668d7ca --- /dev/null +++ b/packages/app/hooks/useSignupBootStatus.ts @@ -0,0 +1,251 @@ +import { configureApi } from '@tloncorp/shared/dist/api'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; +import { useCallback, useEffect, useState } from 'react'; + +import { useShip } from '../contexts/ship'; +import { useSignupContext } from '../contexts/signup'; +import * as hostingApi from '../lib/hostingApi'; +import { trackError, trackOnboardingAction } from '../utils/posthog'; +import { getShipFromCookie, getShipUrl } from '../utils/ship'; + +// import { useOnboardingContext } from '../../lib/OnboardingContext'; + +export enum NodeBootPhase { + IDLE = 'idle', + RESERVING = 'reserving', + BOOTING = 'booting', + AUTHENTICATING = 'authenticating', + CHECKING_FOR_INVITE = 'checking-for-invite', + CLAIMING_INVITE = 'claiming-invite', + READY = 'ready', + ERROR = 'error', +} + +export const useShipBoot = (userId: string) => { + const [status, setStatus] = useState(NodeBootPhase.IDLE); + const [error, setError] = useState(null); + const signupContext = useSignupContext(); + const { setShip } = useShip(); + + const startShip = useCallback( + async (shipIds: string[]) => { + // setStatus(NodeBootPhase.LOADING); + try { + const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); + if (!shipsWithStatus) { + setStatus(NodeBootPhase.BOOTING); + return; + } + + const { status: shipStatus, shipId } = shipsWithStatus; + + if (shipStatus !== 'Ready') { + setStatus(NodeBootPhase.BOOTING); + return; + } + + const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); + const shipUrl = getShipUrl(shipId); + const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); + if (!authCookie) { + throw new Error("Couldn't log you into your ship."); + } + + const ship = getShipFromCookie(authCookie); + configureApi(ship, shipUrl); + + setShip({ + ship, + shipUrl, + authCookie, + }); + + setStatus(NodeBootPhase.READY); + } catch (err) { + console.error('Error starting ship:', err); + if (err instanceof Error) { + trackError(err); + setError(err.message); + } + setStatus(NodeBootPhase.ERROR); + } + }, + [getLandscapeAuthCookie, hostingApi, setShip] + ); + + const reserveShip = useCallback( + async (skipShipId?: string) => { + setStatus(NodeBootPhase.RESERVING); + try { + const user = await hostingApi.getHostingUser(userId); + const shipIds = user.ships ?? []; + + if (shipIds.length === 0) { + const ships = await hostingApi.getReservableShips(userId); + const ship = ships.find( + ({ id, readyForDistribution }) => + id !== skipShipId && readyForDistribution + ); + if (!ship) { + throw new Error('No available ships found.'); + } + + const { reservedBy } = await hostingApi.reserveShip(userId, ship.id); + if (reservedBy !== userId) { + return reserveShip(ship.id); + } + + await hostingApi.allocateReservedShip(userId); + shipIds.push(ship.id); + trackOnboardingAction({ + actionName: 'Urbit ID Selected', + ship: ship.id, + }); + } + + await startShip(shipIds); + } catch (err) { + console.error('Error reserving ship:', err); + if (err instanceof Error) { + trackError(err); + setError(err.message); + } + setStatus(NodeBootPhase.ERROR); + } + }, + [userId, hostingApi, startShip] + ); + + const bootShip = useCallback(() => { + reserveShip(); + }, [reserveShip]); + + useEffect(() => { + if (status === NodeBootPhase.BOOTING) { + const timer = setInterval(() => { + reserveShip(); + }, 5000); + + return () => clearInterval(timer); + } + }, [status, reserveShip]); + + return { + status, + error, + bootShip, + }; +}; + +export function useSignupBootStatus() { + const signupContext = useSignupContext(); +} + +async function reserveShip( + hostingUserId: string, + skipShipIds: string[] = [] +): Promise { + try { + const user = await hostingApi.getHostingUser(hostingUserId); + const shipIds = user.ships ?? []; + + if (shipIds.length === 0) { + const ships = await hostingApi.getReservableShips(hostingUserId); + const ship = ships.find( + ({ id, readyForDistribution }) => + !skipShipIds.includes(id) && readyForDistribution + ); + if (!ship) { + throw new Error('No available ships found.'); + } + + const { reservedBy } = await hostingApi.reserveShip( + hostingUserId, + ship.id + ); + if (reservedBy !== hostingUserId) { + return reserveShip(hostingUserId, [ship.id]); + } + + await hostingApi.allocateReservedShip(hostingUserId); + shipIds.push(ship.id); + trackOnboardingAction({ + actionName: 'Urbit ID Selected', + ship: ship.id, + }); + } + + return true; + // await startShip(shipIds); + } catch (err) { + console.error('Error reserving ship:', err); + if (err instanceof Error) { + trackError(err); + // setError(err.message); + } + // setStatus(NodeBootPhase.ERROR); + return false; + } +} + +async function checkShipStatus(shipIds: string[]): Promise { + try { + const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); + if (!shipsWithStatus) { + return NodeBootPhase.BOOTING; + } + + const { status: shipStatus, shipId } = shipsWithStatus; + + if (shipStatus !== 'Ready') { + return NodeBootPhase.BOOTING; + } + + const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); + const shipUrl = getShipUrl(shipId); + const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); + if (!authCookie) { + throw new Error("Couldn't log you into your ship."); + } + + const ship = getShipFromCookie(authCookie); + configureApi(ship, shipUrl); + + // setShip({ + // ship, + // shipUrl, + // authCookie, + // }); + + // setStatus(NodeBootPhase.READY); + return NodeBootPhase.READY; + } catch (err) { + console.error('Error starting ship:', err); + if (err instanceof Error) { + trackError(err); + // setError(err.message); + } + // setStatus(NodeBootPhase.ERROR); + return NodeBootPhase.ERROR; + } +} + +async function getAuthenticationDetails( + nodeId: string +): Promise<{ nodeId: string; nodeUrl: string; authCookie: string }> { + const { code: accessCode } = await hostingApi.getShipAccessCode(nodeId); + const nodeUrl = getShipUrl(nodeId); + const authCookie = await getLandscapeAuthCookie(nodeUrl, accessCode); + if (!authCookie) { + throw new Error("Couldn't log you into your ship."); + } + + // TODO: shouldn't this be the same? + const ship = getShipFromCookie(authCookie); + + return { + nodeId, + nodeUrl, + authCookie, + }; +} diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts new file mode 100644 index 0000000000..9f39eda3d6 --- /dev/null +++ b/packages/app/lib/bootHelpers.ts @@ -0,0 +1,159 @@ +import { configureApi } from '@tloncorp/shared/dist/api'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; +import * as db from '@tloncorp/shared/dist/db'; +import { useCallback, useEffect, useState } from 'react'; + +import { LureData } from '../contexts/branch'; +import { useShip } from '../contexts/ship'; +import { useSignupContext } from '../contexts/signup'; +import * as hostingApi from '../lib/hostingApi'; +import { trackError, trackOnboardingAction } from '../utils/posthog'; +import { getShipFromCookie, getShipUrl } from '../utils/ship'; + +export enum NodeBootPhase { + IDLE = 'idle', + RESERVING = 'reserving', + BOOTING = 'booting', + AUTHENTICATING = 'authenticating', + CHECKING_FOR_INVITE = 'checking-for-invite', + ACCEPTING_INVITES = 'accepting-invites', + READY = 'ready', + ERROR = 'error', +} + +export default { + NodeBootPhase, + reserveNode, + checkNodeBooted, + authenticateNode, + getInvitedGroupAndDm, +}; + +export async function reserveNode( + hostingUserId: string, + skipShipIds: string[] = [] +): Promise { + const user = await hostingApi.getHostingUser(hostingUserId); + // const shipIds = user.ships ?? []; + + // if the hosting user already has a ship tied to their account, use that + if (user.ships?.length) { + return user.ships[0]; + } + + // otherwise reserve a new ship + const ships = await hostingApi.getReservableShips(hostingUserId); + const ship = ships.find( + ({ id, readyForDistribution }) => + !skipShipIds.includes(id) && readyForDistribution + ); + if (!ship) { + throw new Error('No available ships found.'); + } + + const { reservedBy } = await hostingApi.reserveShip(hostingUserId, ship.id); + if (reservedBy !== hostingUserId) { + return reserveNode(hostingUserId, [ship.id]); + } + + await hostingApi.allocateReservedShip(hostingUserId); + // shipIds.push(ship.id); + trackOnboardingAction({ + actionName: 'Urbit ID Selected', + ship: ship.id, + }); + + return ship.id; + // } catch (err) { + // console.error('Error reserving ship:', err); + // if (err instanceof Error) { + // trackError(err); + // // setError(err.message); + // } + // // setStatus(NodeBootPhase.ERROR); + // // return false; + // } +} + +async function checkNodeBooted(nodeId: string): Promise { + // try { + const shipsWithStatus = await hostingApi.getShipsWithStatus([nodeId]); + if (!shipsWithStatus) { + return false; + } + + const { status: shipStatus } = shipsWithStatus; + + if (shipStatus !== 'Ready') { + return false; + } + + return true; + + // const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); + // const shipUrl = getShipUrl(shipId); + // const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); + // if (!authCookie) { + // throw new Error("Couldn't log you into your ship."); + // } + + // const ship = getShipFromCookie(authCookie); + // configureApi(ship, shipUrl); + + // setShip({ + // ship, + // shipUrl, + // authCookie, + // }); + + // setStatus(NodeBootPhase.READY); + // return NodeBootPhase.READY; + // } catch (err) { + // console.error('Error starting ship:', err); + // if (err instanceof Error) { + // trackError(err); + // // setError(err.message); + // } + // // setStatus(NodeBootPhase.ERROR); + // return NodeBootPhase.ERROR; + // } +} + +async function authenticateNode( + nodeId: string +): Promise<{ nodeId: string; nodeUrl: string; authCookie: string }> { + const { code: accessCode } = await hostingApi.getShipAccessCode(nodeId); + const nodeUrl = getShipUrl(nodeId); + const authCookie = await getLandscapeAuthCookie(nodeUrl, accessCode); + if (!authCookie) { + throw new Error("Couldn't log you into your ship."); + } + + // TODO: shouldn't this be the same? + const ship = getShipFromCookie(authCookie); + + return { + nodeId, + nodeUrl, + authCookie, + }; +} + +async function getInvitedGroupAndDm( + lureMeta: LureData | null +): Promise<{ invitedDm: db.Channel | null; invitedGroup: db.Group | null }> { + if (!lureMeta) { + throw new Error('no stored invite found, cannot check'); + } + const { invitedGroupId, inviterUserId } = lureMeta; + if (!invitedGroupId || !inviterUserId) { + throw new Error( + `invalid invite metadata: group[${invitedGroupId}] inviter[${inviterUserId}]` + ); + } + // use api client to see if you have pending DM and group invite + const invitedDm = await db.getChannel({ id: inviterUserId }); + const invitedGroup = await db.getGroup({ id: invitedGroupId }); + + return { invitedDm, invitedGroup }; +} From 77b485a986d43371659510ea036e320c7ee45824 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 9 Oct 2024 00:41:22 -0400 Subject: [PATCH 025/259] finish boot cycle, wire up --- .../src/components/AuthenticatedApp.tsx | 18 +- .../screens/Onboarding/ReserveShipScreen.tsx | 328 +++++++++--------- package.json | 1 + packages/app/contexts/signup.tsx | 146 +++++--- packages/app/lib/bootHelpers.ts | 1 + 5 files changed, 285 insertions(+), 209 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index a31c3b2746..85fca7be1f 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -32,19 +32,23 @@ function AuthenticatedApp({ const currentUserId = useCurrentUserId(); const signupContext = useSignupContext(); const handlePostSignup = usePostSignup(); + const connectionStatus = store.useConnectionStatus(); useNotificationListener(notificationListenerProps); useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); useEffect(() => { - configureClient({ - shipName: ship ?? '', - shipUrl: shipUrl ?? '', - onReset: () => sync.syncStart(), - onChannelReset: () => sync.handleDiscontinuity(), - onChannelStatusChange: sync.handleChannelStatusChange, - }); + // TODO: i think we need a proper idle state? + if (connectionStatus !== 'Connected') { + configureClient({ + shipName: ship ?? '', + shipUrl: shipUrl ?? '', + onReset: () => sync.syncStart(), + onChannelReset: () => sync.handleDiscontinuity(), + onChannelStatusChange: sync.handleChannelStatusChange, + }); + } initializeCrashReporter(crashlytics(), PlatformState); diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index fd461c7799..f1c669b4c7 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -1,6 +1,7 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; import { trackError, trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { getShipFromCookie, getShipUrl } from '@tloncorp/app/utils/ship'; import { configureApi } from '@tloncorp/shared/dist/api'; @@ -25,166 +26,169 @@ export const ReserveShipScreen = ({ }>({ state: 'loading', }); - const { hostingApi, getLandscapeAuthCookie } = useOnboardingContext(); - const signupContext = useSignupContext(); - const { setShip } = useShip(); - - const startShip = useCallback( - async (shipIds: string[]) => { - // Fetch statuses for the user's ships and start any required booting/resuming - const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); - console.log('shipsWithStatus', shipsWithStatus); - if (!shipsWithStatus) { - // you can only have gotten to this screen if a new hosting account was created and ship - // was reserved. If we don't see the ship status, assume it's still booting - return setState({ state: 'booting' }); - } - - const { status, shipId } = shipsWithStatus; - - // If user is in the sign up flow, send them to fill out some extra details - if ( - signupContext.nickname === undefined && - signupContext.telemetry === undefined - ) { - return navigation.navigate('SetNickname', { - user: await hostingApi.getHostingUser(user.id), - }); - } - - // If it's not ready, show the booting message - if (status !== 'Ready') { - return setState({ state: 'booting' }); - } - - // If it's ready, fetch the access code and auth cookie - const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); - const shipUrl = getShipUrl(shipId); - const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); - if (!authCookie) { - return setState({ - state: 'error', - error: "Sorry, we couldn't log you into your ship.", - }); - } - - const ship = getShipFromCookie(authCookie); - configureApi(ship, shipUrl); - - // Set the ship info in the main context to navigate to chat view - setShip({ - ship, - shipUrl, - authCookie, - }); - }, - [ - getLandscapeAuthCookie, - hostingApi, - navigation, - setShip, - signupContext.nickname, - signupContext.telemetry, - user.id, - ] - ); - - const reserveShip = useCallback( - async (skipShipId?: string) => { - const shipIds = user.ships ?? []; - - // User doesn't have any ships assigned to them yet - if (shipIds.length === 0) { - try { - // Get list of reservable ships and choose one that's ready for distribution - const ships = await hostingApi.getReservableShips(user.id); - const ship = ships.find( - ({ id, readyForDistribution }) => - id !== skipShipId && readyForDistribution - ); - if (!ship) { - return setState({ - state: 'error', - error: - 'Sorry, we could no longer find a ship for you. Please try again later.', - }); - } - - // Reserve this ship and check it was successful - const { reservedBy } = await hostingApi.reserveShip(user.id, ship.id); - console.log('reserved', user, reservedBy); - if (reservedBy !== user.id) { - return reserveShip(ship.id); - } - - // Finish allocating this ship to the user - await hostingApi.allocateReservedShip(user.id); - shipIds.push(ship.id); - trackOnboardingAction({ - actionName: 'Urbit ID Selected', - ship: ship.id, - }); - } catch (err) { - console.error('Error reserving ship:', err); - if (err instanceof Error) { - trackError(err); - } - - return setState({ - state: 'error', - error: - 'We were not able to reserve your ship. Please try again later.', - }); - } - } - - // Start the ship - try { - await startShip(shipIds); - } catch (err) { - console.error('Error starting ship:', err); - if (err instanceof Error) { - trackError(err); - } - return setState({ - state: 'error', - error: "Sorry, we couldn't boot your ship. Please try again later.", - }); - } - }, - [user] - ); - - useEffect(() => { - reserveShip(); - }, [reserveShip]); - - useEffect(() => { - let timer: NodeJS.Timeout; - - if (state === 'booting') { - timer = setInterval(reserveShip, 5_000); - } + const signupContext = useSignupContext(); - return () => { - if (timer) { - clearInterval(timer); - } - }; - }, [state]); - - useEffect(() => { - if (error) { - Alert.alert('An error occurred', error, [ - { - text: 'OK', - onPress: () => navigation.popToTop(), - style: 'cancel', - }, - ]); - } - }, [error, navigation]); + // const { hostingApi, getLandscapeAuthCookie } = useOnboardingContext(); + // const signupContext = useSignupContext(); + // const { setShip } = useShip(); + + // const startShip = useCallback( + // async (shipIds: string[]) => { + // // Fetch statuses for the user's ships and start any required booting/resuming + // const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); + // console.log('shipsWithStatus', shipsWithStatus); + // if (!shipsWithStatus) { + // // you can only have gotten to this screen if a new hosting account was created and ship + // // was reserved. If we don't see the ship status, assume it's still booting + // return setState({ state: 'booting' }); + // } + + // const { status, shipId } = shipsWithStatus; + + // // If user is in the sign up flow, send them to fill out some extra details + // if ( + // signupContext.nickname === undefined && + // signupContext.telemetry === undefined + // ) { + // return navigation.navigate('SetNickname', { + // user: await hostingApi.getHostingUser(user.id), + // }); + // } + + // // If it's not ready, show the booting message + // if (status !== 'Ready') { + // return setState({ state: 'booting' }); + // } + + // // If it's ready, fetch the access code and auth cookie + // const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); + // const shipUrl = getShipUrl(shipId); + // const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); + // if (!authCookie) { + // return setState({ + // state: 'error', + // error: "Sorry, we couldn't log you into your ship.", + // }); + // } + + // const ship = getShipFromCookie(authCookie); + // configureApi(ship, shipUrl); + + // // Set the ship info in the main context to navigate to chat view + // setShip({ + // ship, + // shipUrl, + // authCookie, + // }); + // }, + // [ + // getLandscapeAuthCookie, + // hostingApi, + // navigation, + // setShip, + // signupContext.nickname, + // signupContext.telemetry, + // user.id, + // ] + // ); + + // const reserveShip = useCallback( + // async (skipShipId?: string) => { + // const shipIds = user.ships ?? []; + + // // User doesn't have any ships assigned to them yet + // if (shipIds.length === 0) { + // try { + // // Get list of reservable ships and choose one that's ready for distribution + // const ships = await hostingApi.getReservableShips(user.id); + // const ship = ships.find( + // ({ id, readyForDistribution }) => + // id !== skipShipId && readyForDistribution + // ); + // if (!ship) { + // return setState({ + // state: 'error', + // error: + // 'Sorry, we could no longer find a ship for you. Please try again later.', + // }); + // } + + // // Reserve this ship and check it was successful + // const { reservedBy } = await hostingApi.reserveShip(user.id, ship.id); + // console.log('reserved', user, reservedBy); + // if (reservedBy !== user.id) { + // return reserveShip(ship.id); + // } + + // // Finish allocating this ship to the user + // await hostingApi.allocateReservedShip(user.id); + // shipIds.push(ship.id); + // trackOnboardingAction({ + // actionName: 'Urbit ID Selected', + // ship: ship.id, + // }); + // } catch (err) { + // console.error('Error reserving ship:', err); + // if (err instanceof Error) { + // trackError(err); + // } + + // return setState({ + // state: 'error', + // error: + // 'We were not able to reserve your ship. Please try again later.', + // }); + // } + // } + + // // Start the ship + // try { + // await startShip(shipIds); + // } catch (err) { + // console.error('Error starting ship:', err); + // if (err instanceof Error) { + // trackError(err); + // } + + // return setState({ + // state: 'error', + // error: "Sorry, we couldn't boot your ship. Please try again later.", + // }); + // } + // }, + // [user] + // ); + + // useEffect(() => { + // reserveShip(); + // }, [reserveShip]); + + // useEffect(() => { + // let timer: NodeJS.Timeout; + + // if (state === 'booting') { + // timer = setInterval(reserveShip, 5_000); + // } + + // return () => { + // if (timer) { + // clearInterval(timer); + // } + // }; + // }, [state]); + + // useEffect(() => { + // if (error) { + // Alert.alert('An error occurred', error, [ + // { + // text: 'OK', + // onPress: () => navigation.popToTop(), + // style: 'cancel', + // }, + // ]); + // } + // }, [error, navigation]); // Disable back button if no error occurred useEffect( @@ -197,6 +201,12 @@ export const ReserveShipScreen = ({ [navigation, error] ); + useEffect(() => { + if (signupContext.bootPhase === NodeBootPhase.IDLE) { + signupContext.initializeBootSequence(); + } + }, [signupContext]); + return ( {state === 'loading' ? ( @@ -213,7 +223,7 @@ export const ReserveShipScreen = ({ Booting your ship... - This may take a few minutes. + {signupContext.bootPhase} ) : null} diff --git a/package.json b/package.json index 4845f6f64d..167e0c1b01 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dev:shared": "pnpm --filter '@tloncorp/shared' dev", "dev:android": "concurrently \"pnpm run dev:shared\" \"pnpm --filter 'tlon-mobile' dev\" \"pnpm --filter 'tlon-mobile' android\"", "dev:ios": "concurrently \"pnpm run dev:shared\" \"pnpm --filter 'tlon-mobile' dev\" \"pnpm --filter 'tlon-mobile' ios\" \"pnpm --filter '@tloncorp/ui' watch\"", + "dev:ios:preview": "concurrently \"pnpm run dev:shared\" \"pnpm --filter 'tlon-mobile' dev\" \"pnpm --filter 'tlon-mobile' ios:preview\" \"pnpm --filter '@tloncorp/ui' watch\"", "dev:web": "concurrently \"pnpm run dev:shared\" \"pnpm --filter 'tlon-web' dev-no-ssl\"", "test": "pnpm run -r test run -u", "lint:all": "pnpm -r lint" diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index ea91163a0a..9bf41b4f28 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -5,11 +5,14 @@ import { useCallback, useContext, useEffect, + useRef, useState, } from 'react'; +import { configureClient } from '../lib/api'; import { NodeBootPhase } from '../lib/bootHelpers'; import BootHelpers from '../lib/bootHelpers'; +import { getShipFromCookie } from '../utils/ship'; import { useLureMetadata } from './branch'; import { useShip } from './ship'; @@ -31,6 +34,7 @@ interface SignupContext extends SignupValues { setNotificationToken: (notificationToken: string | undefined) => void; setTelemetry: (telemetry: boolean) => void; setDidSignup: (didSignup: boolean) => void; + initializeBootSequence: () => void; clear: () => void; } @@ -43,6 +47,7 @@ const defaultContext: SignupContext = { setNotificationToken: () => {}, setTelemetry: () => {}, setDidSignup: () => {}, + initializeBootSequence: () => {}, clear: () => {}, }; @@ -53,6 +58,7 @@ const SignupContext = createContext(defaultContext); export const SignupProvider = ({ children }: { children: React.ReactNode }) => { const [values, setValues] = useState(defaultContext); const { setShip } = useShip(); + const connectionStatus = store.useConnectionStatus(); const lureMeta = useLureMetadata(); const setBootPhase = useCallback((bootPhase: NodeBootPhase) => { @@ -71,91 +77,115 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { } }, [values]); - const runBootSequence = useCallback(async () => { + const runBootPhase = useCallback(async (): Promise => { const { hostingUser, bootPhase } = values; - logger.log(`running boot sequence phase: ${bootPhase}`); if (!hostingUser) { logger.log('no hosting user found, skipping'); - return; + return bootPhase; } + // // Step 1: reserve a node + // if (bootPhase === NodeBootPhase.RESERVING) { const reservedNodeId = await BootHelpers.reserveNode(hostingUser.id); setValues((current) => ({ ...current, reservedNodeId, - bootPhase: NodeBootPhase.BOOTING, })); logger.log(`reserved node`, reservedNodeId); - return; + return NodeBootPhase.BOOTING; } + // you should not be able to advance past here unless reservedNodeId is set if (!values.reservedNodeId) { throw new Error( `cannot run boot phase ${bootPhase} without a reserved node` ); } + // // Step 2: confirm the node has finished booting on hosting + // if (bootPhase === NodeBootPhase.BOOTING) { const isReady = await BootHelpers.checkNodeBooted(values.reservedNodeId); if (isReady) { - setValues((current) => ({ - ...current, - bootPhase: NodeBootPhase.AUTHENTICATING, - })); logger.log('checked hosting, node is ready'); - } else { - logger.log('checked hosting, node still booting'); + return NodeBootPhase.AUTHENTICATING; } - return; + + logger.log('checked hosting, node still booting'); + return NodeBootPhase.BOOTING; } + // // Step 3: authenticate with the node itself + // if (bootPhase === NodeBootPhase.AUTHENTICATING) { const auth = await BootHelpers.authenticateNode(values.reservedNodeId); + const ship = getShipFromCookie(auth.authCookie); + setShip({ - ship: auth.nodeId, + ship, shipUrl: auth.nodeUrl, authCookie: auth.authCookie, }); // TODO: connect to the API client? + configureClient({ + shipName: ship, + shipUrl: auth.nodeUrl, + onReset: () => store.syncStart(), + onChannelReset: () => store.handleDiscontinuity(), + onChannelStatusChange: store.handleChannelStatusChange, + }); - const signedUpWithInvite = Boolean(lureMeta?.id); - setValues((current) => ({ - ...current, - bootPhase: signedUpWithInvite + logger.log(`authenticated with node`); + return NodeBootPhase.CONNECTING; + } + + // + // finish connecting to the node + // + if (bootPhase === NodeBootPhase.CONNECTING) { + await wait(1000); + if (connectionStatus === 'Connected') { + logger.log(`finished connecting to node`); + const signedUpWithInvite = Boolean(lureMeta?.id); + return signedUpWithInvite ? NodeBootPhase.CHECKING_FOR_INVITE - : NodeBootPhase.READY, - })); - return; + : NodeBootPhase.READY; + } + + logger.log(`still connecting to node`); + return NodeBootPhase.CONNECTING; } + // // Step 4 [optional]: if we used an invite code to signup, see if we got the invites + // if (bootPhase === NodeBootPhase.CHECKING_FOR_INVITE) { const { invitedDm, invitedGroup } = await BootHelpers.getInvitedGroupAndDm(lureMeta); if (invitedDm && invitedGroup) { - setValues((current) => ({ - ...current, - bootPhase: NodeBootPhase.ACCEPTING_INVITES, - })); logger.log('confirmed node has the invites'); - } else { - logger.log('checked node for invites, not yet found'); + return NodeBootPhase.ACCEPTING_INVITES; } - return; + + logger.log('checked node for invites, not yet found'); + return NodeBootPhase.CHECKING_FOR_INVITE; } + // // Step 5 [optional]: join the invited groups + // if (bootPhase === NodeBootPhase.ACCEPTING_INVITES) { const { invitedDm, invitedGroup } = await BootHelpers.getInvitedGroupAndDm(lureMeta); + // if we have invites, accept them if (invitedDm && invitedDm.isDmInvite) { logger.log(`accepting dm invitation`); await store.respondToDMInvite({ channel: invitedDm, accept: true }); @@ -170,7 +200,7 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { await store.joinGroup(invitedGroup); } - // give the join & accept some time to process, the hard refresh data + // give it some time to process, then hard refresh the data await wait(2000); if (invitedGroup) { await store.syncGroup(invitedGroup?.id); @@ -179,6 +209,7 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { await store.syncDms(); } + // check if we successfully joined const { invitedDm: updatedDm, invitedGroup: updatedGroup } = await BootHelpers.getInvitedGroupAndDm(lureMeta); @@ -190,27 +221,55 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { updatedGroup.channels.length > 0; if (dmIsGood && groupIsGood) { - setValues((current) => ({ - ...current, - bootPhase: NodeBootPhase.READY, - })); logger.log('successfully accepted invites'); - } else { - logger.log('still waiting on invites to be accepted'); + return NodeBootPhase.READY; } - return; + + logger.log('still waiting on invites to be accepted'); + return NodeBootPhase.ACCEPTING_INVITES; } - }, [lureMeta, setShip, values]); + return bootPhase; + }, [connectionStatus, lureMeta, setShip, values]); + + const isRunningRef = useRef(false); + const lastRunPhaseRef = useRef(values.bootPhase); + const lastRunErrored = useRef(false); useEffect(() => { - let timer: NodeJS.Timeout; - if (values.bootPhase !== NodeBootPhase.READY) { - timer = setInterval(() => { - runBootSequence(); - }, 5000); + const runBootSequence = async () => { + // prevent simultaneous runs + if (isRunningRef.current) { + return; + } + + isRunningRef.current = true; + + try { + // if rerunning failed step, wait before retry + const lastRunDidNotAdvance = + values.bootPhase === lastRunPhaseRef.current; + if (lastRunDidNotAdvance || lastRunErrored.current) { + await wait(3000); + } + + lastRunPhaseRef.current = values.bootPhase; + lastRunErrored.current = false; + + logger.log(`running boot sequence phase: ${values.bootPhase}`); + const nextBootPhase = await runBootPhase(); // TODO: i'm scared this will lock up if it hangs + setBootPhase(nextBootPhase); + } catch (e) { + lastRunErrored.current = true; + // handle + } finally { + isRunningRef.current = false; + } + }; + + if (![NodeBootPhase.IDLE, NodeBootPhase.READY].includes(values.bootPhase)) { + runBootSequence(); } - return () => clearInterval(timer); - }, [values.bootPhase, runBootSequence]); + }, [runBootPhase, setBootPhase, values.bootPhase]); const setNickname = useCallback((nickname: string | undefined) => { setValues((current) => ({ @@ -259,6 +318,7 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { setNotificationToken, setTelemetry, setDidSignup, + initializeBootSequence, clear, }} > diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts index 9f39eda3d6..db2b7d57bb 100644 --- a/packages/app/lib/bootHelpers.ts +++ b/packages/app/lib/bootHelpers.ts @@ -15,6 +15,7 @@ export enum NodeBootPhase { RESERVING = 'reserving', BOOTING = 'booting', AUTHENTICATING = 'authenticating', + CONNECTING = 'connecting', CHECKING_FOR_INVITE = 'checking-for-invite', ACCEPTING_INVITES = 'accepting-invites', READY = 'ready', From 083bc6ca5de7e745d83392eb2864a72dd690d7a3 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 9 Oct 2024 02:17:04 -0400 Subject: [PATCH 026/259] yay it kind of works --- apps/tlon-mobile/src/App.main.tsx | 13 ++++-- .../src/components/AuthenticatedApp.tsx | 12 ++++- .../src/hooks/useDeepLinkListener.ts | 19 ++++---- .../screens/Onboarding/ReserveShipScreen.tsx | 3 ++ .../Onboarding/SignUpPasswordScreen.tsx | 1 + packages/app/contexts/signup.tsx | 45 ++++++++++++++++--- packages/shared/src/store/session.ts | 4 ++ 7 files changed, 76 insertions(+), 21 deletions(-) diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index a8fe41e7ae..86e412168b 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -12,8 +12,12 @@ import { import ErrorBoundary from '@tloncorp/app/ErrorBoundary'; import { BranchProvider, useBranch } from '@tloncorp/app/contexts/branch'; import { ShipProvider, useShip } from '@tloncorp/app/contexts/ship'; -import { SignupProvider } from '@tloncorp/app/contexts/signup'; +import { + SignupProvider, + useSignupContext, +} from '@tloncorp/app/contexts/signup'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; +import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; import { useMigrations } from '@tloncorp/app/lib/nativeDb'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { FeatureFlagConnectedInstrumentationProvider } from '@tloncorp/app/utils/perf'; @@ -50,7 +54,7 @@ const App = ({ const { isLoading, isAuthenticated } = useShip(); const [connected, setConnected] = useState(true); - const { lure, priorityToken } = useBranch(); + const signupContext = useSignupContext(); usePreloadedEmojis(); @@ -73,7 +77,10 @@ const App = ({ - ) : isAuthenticated ? ( + ) : isAuthenticated && + [NodeBootPhase.IDLE, NodeBootPhase.READY].includes( + signupContext.bootPhase + ) ? ( { // TODO: i think we need a proper idle state? - if (connectionStatus !== 'Connected') { + console.log(`authenticated app connection status: ${connectionStatus}`); + if (connectionStatus === 'Idle') { configureClient({ shipName: ship ?? '', shipUrl: shipUrl ?? '', @@ -62,7 +63,14 @@ function AuthenticatedApp({ } sync.syncStart(); - }, [currentUserId, handlePostSignup, ship, shipUrl, signupContext.didSignup]); + }, [ + connectionStatus, + currentUserId, + handlePostSignup, + ship, + shipUrl, + signupContext.didSignup, + ]); const handleAppStatusChange = useCallback((status: AppStateStatus) => { if (status === 'active') { diff --git a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts index c995ee8669..e6bbed2c5c 100644 --- a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts +++ b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts @@ -26,15 +26,16 @@ export const useDeepLinkListener = () => { try { // if the lure was clicked prior to authenticating, trigger the automatic join & DM if (lure.shouldAutoJoin) { - try { - logger.log(`inviting ship with lure`, ship, signupParams.lureId); - await inviteShipWithLure({ ship, lure: signupParams.lureId }); - } catch (err) { - logger.error('Error inviting ship with lure:', err); - if (err instanceof Error) { - trackError(err); - } - } + // WE DONT ACTUALLY HAVE TO DO ANYTHING HERE — hosting handles + // try { + // logger.log(`inviting ship with lure`, ship, signupParams.lureId); + // await inviteShipWithLure({ ship, lure: signupParams.lureId }); + // } catch (err) { + // logger.error('Error inviting ship with lure:', err); + // if (err instanceof Error) { + // trackError(err); + // } + // } } else { // otherwise, treat it as a deeplink and navigate to the group if (lure.invitedGroupId) { diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index f1c669b4c7..ddeadf81ba 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -215,6 +215,9 @@ export const ReserveShipScreen = ({ Getting your ship ready... + + {signupContext.bootPhase} + ) : state === 'booting' ? ( diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx index 3df706fa2e..fb68f4ead0 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx @@ -126,6 +126,7 @@ export const SignUpPasswordScreen = ({ email, password, }); + signupContext.setHostingUser(user); if (user.requirePhoneNumberVerification) { navigation.navigate('RequestPhoneVerify', { user }); } else { diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index 9bf41b4f28..bbdf68508e 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -1,5 +1,5 @@ +import { createDevLogger } from '@tloncorp/shared/dist'; import * as store from '@tloncorp/shared/dist/store'; -import { createDevLogger } from 'packages/shared/dist'; import { createContext, useCallback, @@ -30,6 +30,7 @@ interface SignupValues { } interface SignupContext extends SignupValues { + setHostingUser: (hostingUser: { id: string }) => void; setNickname: (nickname: string | undefined) => void; setNotificationToken: (notificationToken: string | undefined) => void; setTelemetry: (telemetry: boolean) => void; @@ -48,6 +49,7 @@ const defaultContext: SignupContext = { setTelemetry: () => {}, setDidSignup: () => {}, initializeBootSequence: () => {}, + setHostingUser: () => {}, clear: () => {}, }; @@ -124,7 +126,9 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { // if (bootPhase === NodeBootPhase.AUTHENTICATING) { const auth = await BootHelpers.authenticateNode(values.reservedNodeId); + console.log(`got auth`, auth); const ship = getShipFromCookie(auth.authCookie); + console.log(`ship`, ship, auth.nodeId, auth.authCookie); setShip({ ship, @@ -134,12 +138,13 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { // TODO: connect to the API client? configureClient({ - shipName: ship, + shipName: auth.nodeId, shipUrl: auth.nodeUrl, onReset: () => store.syncStart(), onChannelReset: () => store.handleDiscontinuity(), onChannelStatusChange: store.handleChannelStatusChange, }); + store.syncStart(); logger.log(`authenticated with node`); return NodeBootPhase.CONNECTING; @@ -151,14 +156,14 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { if (bootPhase === NodeBootPhase.CONNECTING) { await wait(1000); if (connectionStatus === 'Connected') { - logger.log(`finished connecting to node`); + logger.log(`connection to node established`); const signedUpWithInvite = Boolean(lureMeta?.id); return signedUpWithInvite ? NodeBootPhase.CHECKING_FOR_INVITE : NodeBootPhase.READY; } - logger.log(`still connecting to node`); + logger.log(`still connecting to node`, connectionStatus); return NodeBootPhase.CONNECTING; } @@ -185,6 +190,9 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { const { invitedDm, invitedGroup } = await BootHelpers.getInvitedGroupAndDm(lureMeta); + console.log(`invitedDm`, invitedDm); + console.log(`invitedGroup`, invitedGroup); + // if we have invites, accept them if (invitedDm && invitedDm.isDmInvite) { logger.log(`accepting dm invitation`); @@ -203,10 +211,18 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { // give it some time to process, then hard refresh the data await wait(2000); if (invitedGroup) { - await store.syncGroup(invitedGroup?.id); + try { + await store.syncGroup(invitedGroup?.id); + } catch (e) { + logger.error('failed to sync group?', e.body); + } } if (invitedDm) { - await store.syncDms(); + try { + await store.syncDms(); + } catch (e) { + logger.error('failed to sync dms?', e); + } } // check if we successfully joined @@ -225,7 +241,11 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { return NodeBootPhase.READY; } - logger.log('still waiting on invites to be accepted'); + logger.log( + 'still waiting on invites to be accepted', + `dm: ${dmIsGood}`, + `group: ${groupIsGood}` + ); return NodeBootPhase.ACCEPTING_INVITES; } @@ -259,7 +279,10 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { const nextBootPhase = await runBootPhase(); // TODO: i'm scared this will lock up if it hangs setBootPhase(nextBootPhase); } catch (e) { + logger.error('boot phase errored', e.message, e); lastRunErrored.current = true; + setBootPhase(values.bootPhase); + // handle } finally { isRunningRef.current = false; @@ -271,6 +294,13 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { } }, [runBootPhase, setBootPhase, values.bootPhase]); + const setHostingUser = useCallback((hostingUser: { id: string }) => { + setValues((current) => ({ + ...current, + hostingUser, + })); + }, []); + const setNickname = useCallback((nickname: string | undefined) => { setValues((current) => ({ ...current, @@ -314,6 +344,7 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { Date: Wed, 9 Oct 2024 12:03:13 -0500 Subject: [PATCH 027/259] urbit-client: update http-api everywhere and use appropriate handlers --- apps/tlon-mobile/package.json | 2 +- .../src/components/AuthenticatedApp.tsx | 13 +- package.json | 2 +- packages/shared/package.json | 5 +- packages/shared/src/api/urbit.ts | 47 +- pnpm-lock.yaml | 1014 ++++++++++++++++- 6 files changed, 1020 insertions(+), 63 deletions(-) diff --git a/apps/tlon-mobile/package.json b/apps/tlon-mobile/package.json index 6c3ca7fdd3..9a8e3707a2 100644 --- a/apps/tlon-mobile/package.json +++ b/apps/tlon-mobile/package.json @@ -62,7 +62,7 @@ "@tloncorp/shared": "workspace:*", "@tloncorp/ui": "workspace:*", "@urbit/aura": "^1.0.0", - "@urbit/http-api": "^3.1.0-dev-3", + "@urbit/http-api": "3.2.0-dev", "classnames": "^2.3.2", "dotenv-expand": "^11.0.6", "expo": "^50.0.6", diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index a31c3b2746..1af8cc280e 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -13,6 +13,7 @@ import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { initializeCrashReporter, sync } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; +import { ENABLED_LOGGERS } from 'packages/app/constants'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; @@ -32,6 +33,7 @@ function AuthenticatedApp({ const currentUserId = useCurrentUserId(); const signupContext = useSignupContext(); const handlePostSignup = usePostSignup(); + const session = store.useCurrentSession(); useNotificationListener(notificationListenerProps); useDeepLinkListener(); useNavigationLogging(); @@ -41,8 +43,15 @@ function AuthenticatedApp({ configureClient({ shipName: ship ?? '', shipUrl: shipUrl ?? '', - onReset: () => sync.syncStart(), - onChannelReset: () => sync.handleDiscontinuity(), + verbose: ENABLED_LOGGERS.includes('urbit'), + onReset: () => sync.syncStart(true), + onChannelReset: () => { + const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours + const lastReconnect = session?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } + }, onChannelStatusChange: sync.handleChannelStatusChange, }); diff --git a/package.json b/package.json index 4845f6f64d..e777bca29c 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@tiptap/suggestion": "2.6.0", "@tiptap/extension-mention": "2.6.0", "@tiptap/extension-hard-break": "2.6.0", - "@urbit/http-api": "3.1.0-dev-3", + "@urbit/http-api": "3.2.0-dev", "@urbit/api": "2.2.0", "prosemirror-model": "1.19.3", "prosemirror-view": "1.33.4", diff --git a/packages/shared/package.json b/packages/shared/package.json index d5ab5aa0fb..d824111a74 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -28,10 +28,11 @@ "dependencies": { "@react-native-async-storage/async-storage": "1.21.0", "@urbit/aura": "^1.0.0", + "@urbit/http-api": "3.2.0-dev", "any-ascii": "^0.3.1", "big-integer": "^1.6.52", - "sorted-btree": "^1.8.1", - "exponential-backoff": "^3.1.1" + "exponential-backoff": "^3.1.1", + "sorted-btree": "^1.8.1" }, "devDependencies": { "@types/better-sqlite3": "^7.6.9", diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 3ad4fbf7c7..48752d2c2d 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -22,6 +22,7 @@ interface Watcher { type Watchers = Record>; let clientInstance: Urbit | null = null; +let handleChannelReset: (() => void) | undefined; let subWatchers: Watchers = {}; export const client = new Proxy( @@ -56,7 +57,7 @@ export function configureClient({ shipUrl, fetchFn, verbose, - onReset, + onReconnect, onChannelReset, onChannelStatusChange, }: { @@ -64,7 +65,7 @@ export function configureClient({ shipUrl: string; fetchFn?: typeof fetch; verbose?: boolean; - onReset?: () => void; + onReconnect?: () => void; onChannelReset?: () => void; onChannelStatusChange?: (status: ChannelStatus) => void; }) { @@ -73,9 +74,23 @@ export function configureClient({ clientInstance.ship = deSig(shipName); clientInstance.our = preSig(shipName); clientInstance.verbose = verbose; + handleChannelReset = onChannelReset; + subWatchers = {}; + + clientInstance.onReconnect = () => { + logger.log('client reconnected'); + onChannelStatusChange?.('reconnected'); + onReconnect?.(); + }; + + clientInstance.onRetry = () => { + logger.log('client retrying'); + onChannelStatusChange?.('reconnecting'); + }; + + // the below event handlers will only fire if verbose is set to true clientInstance.on('status-update', (event) => { logger.log('status-update', event); - onChannelStatusChange?.(event.status); }); clientInstance.on('fact', (fact) => { @@ -85,19 +100,6 @@ export function configureClient({ ); }); - clientInstance.onReconnect = () => { - logger.log('client reconnect'); - }; - - clientInstance.on('reset', () => { - logger.log('client reset'); - Object.values(subWatchers).forEach((watchers) => { - watchers.forEach((watcher) => watcher.reject('Client reset')); - }); - subWatchers = {}; - onReset?.(); - }); - clientInstance.on('seamless-reset', () => { logger.log('client seamless-reset'); }); @@ -108,10 +110,7 @@ export function configureClient({ clientInstance.on('channel-reaped', () => { logger.log('client channel-reaped'); - onChannelReset?.(); }); - - subWatchers = {}; } export async function removeUrbitClient() { @@ -131,17 +130,13 @@ function printEndpoint(endpoint: UrbitEndpoint) { export function subscribe( endpoint: UrbitEndpoint, - handler: (update: T) => void, - resubscribing = false + handler: (update: T) => void ) { if (!clientInstance) { throw new Error('Tried to subscribe, but Urbit client is not initialized'); } - logger.log( - resubscribing ? 'resubscribing to' : 'subscribing to', - printEndpoint(endpoint) - ); + logger.log('subscribing to', printEndpoint(endpoint)); return clientInstance.subscribe({ app: endpoint.app, @@ -173,7 +168,7 @@ export function subscribe( }, quit: () => { logger.log('subscription quit on', printEndpoint(endpoint)); - subscribe(endpoint, handler, true); + handleChannelReset?.(); }, err: (error) => { logger.error(`subscribe error on ${printEndpoint(endpoint)}:`, error); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3db8c4cee5..4a98e8e1c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ overrides: '@tiptap/suggestion': 2.6.0 '@tiptap/extension-mention': 2.6.0 '@tiptap/extension-hard-break': 2.6.0 - '@urbit/http-api': 3.1.0-dev-3 + '@urbit/http-api': 3.2.0-dev '@urbit/api': 2.2.0 prosemirror-model: 1.19.3 prosemirror-view: 1.33.4 @@ -172,8 +172,8 @@ importers: specifier: ^1.0.0 version: 1.0.0(big-integer@1.6.52) '@urbit/http-api': - specifier: 3.1.0-dev-3 - version: 3.1.0-dev-3(patch_hash=a4psibisxhh5q6cyjn3nbiaogm) + specifier: 3.2.0-dev + version: 3.2.0-dev classnames: specifier: ^2.3.2 version: 2.5.1 @@ -342,7 +342,7 @@ importers: version: 29.7.0 '@react-native/metro-config': specifier: ^0.73.5 - version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13) + version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) '@tamagui/babel-plugin': specifier: ~1.112.12 version: 1.112.12(@swc/helpers@0.5.13)(encoding@0.1.13)(react@18.2.0) @@ -590,8 +590,8 @@ importers: specifier: ^1.0.0 version: 1.0.0(big-integer@1.6.52) '@urbit/http-api': - specifier: 3.1.0-dev-3 - version: 3.1.0-dev-3(patch_hash=a4psibisxhh5q6cyjn3nbiaogm) + specifier: 3.2.0-dev + version: 3.2.0-dev '@urbit/sigil-js': specifier: ^2.2.0 version: 2.2.0 @@ -1134,8 +1134,8 @@ importers: specifier: ^1.0.0 version: 1.0.0(big-integer@1.6.52) '@urbit/http-api': - specifier: 3.1.0-dev-3 - version: 3.1.0-dev-3(patch_hash=a4psibisxhh5q6cyjn3nbiaogm) + specifier: 3.2.0-dev + version: 3.2.0-dev '@urbit/sigil-js': specifier: ^2.2.0 version: 2.2.0 @@ -1560,7 +1560,7 @@ importers: dependencies: '@10play/tentap-editor': specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1628,6 +1628,9 @@ importers: '@urbit/aura': specifier: ^1.0.0 version: 1.0.0(big-integer@1.6.52) + '@urbit/http-api': + specifier: 3.2.0-dev + version: 3.2.0-dev any-ascii: specifier: ^0.3.1 version: 0.3.2(patch_hash=5ofxtlxe6za2xqrbq5pqbz7wb4) @@ -6621,8 +6624,8 @@ packages: peerDependencies: big-integer: ^1.6.51 - '@urbit/http-api@3.1.0-dev-3': - resolution: {integrity: sha512-Gjik6915zPI+gwel+KsEsZck78ghZwqT25FWveESS3USzNhmR/N/kbHB5tNombseLrnyFcvFringjP0nhyvzJA==} + '@urbit/http-api@3.2.0-dev': + resolution: {integrity: sha512-phG35u7Uhlg4ZIRt/7mVum9KuR0j7XrxMnYsRUlRk3XgsXgDDNOgT7tvKeY6+L2PTblUOBqcVqNWNtzAOsy3hQ==} '@urbit/sigil-js@2.2.0': resolution: {integrity: sha512-UNtRJ0K4CAXe+IP4wARNRMjuI5GTF2MNj9FL5l4RSMddCPJqSWSpkrYcREBI4AOB+80AEyN1kK/jtzhlm5WW+w==} @@ -13655,6 +13658,43 @@ packages: snapshots: + '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bold': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bullet-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code-block': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) + '@tiptap/extension-document': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-heading': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-history': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-horizontal-rule': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-italic': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-link': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-list-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-ordered-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-placeholder': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-strike': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-task-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-task-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/pm': 2.6.6 + '@tiptap/react': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) + lodash: 4.17.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview: 13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + transitivePeerDependencies: + - '@tiptap/core' + '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) @@ -14548,6 +14588,19 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14561,6 +14614,13 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14568,6 +14628,17 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14579,6 +14650,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14625,6 +14707,16 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14643,6 +14735,13 @@ snapshots: '@babel/helper-plugin-utils@7.24.8': {} + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14650,6 +14749,13 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14732,11 +14838,23 @@ snapshots: dependencies: '@babel/types': 7.25.6 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14744,12 +14862,26 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.25.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14758,6 +14890,12 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14771,6 +14909,12 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14783,18 +14927,39 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -14804,12 +14969,25 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14817,10 +14995,19 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14831,11 +15018,21 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14846,41 +15043,81 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14891,67 +15128,136 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14960,6 +15266,15 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14969,22 +15284,45 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14992,6 +15330,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15004,58 +15354,117 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/template': 7.25.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15063,28 +15472,58 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15093,6 +15532,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-simple-access': 7.22.5 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15102,6 +15550,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-identifier': 7.22.20 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15112,6 +15570,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15120,29 +15586,61 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15152,18 +15650,37 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.25.2) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15171,17 +15688,36 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15190,11 +15726,21 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15236,6 +15782,17 @@ snapshots: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) '@babel/types': 7.25.6 + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15253,17 +15810,40 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + regenerator-transform: 0.15.2 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15276,32 +15856,66 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15310,29 +15924,138 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/preset-env@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + core-js-compat: 3.35.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/preset-env@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15426,6 +16149,13 @@ snapshots: '@babel/helper-validator-option': 7.24.8 '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.25.2) + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.25.6 + esutils: 2.0.3 + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15583,7 +16313,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-module-imports': 7.24.7 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@emotion/hash': 0.9.0 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.0 @@ -15983,7 +16713,7 @@ snapshots: '@expo/cli@0.17.5(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)(expo-modules-autolinking@1.10.3)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@expo/code-signing-certificates': 0.0.5 '@expo/config': 8.5.4 '@expo/config-plugins': 7.8.4 @@ -16796,14 +17526,14 @@ snapshots: '@radix-ui/react-arrow@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) '@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -17260,7 +17990,7 @@ snapshots: '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 @@ -17281,13 +18011,13 @@ snapshots: '@radix-ui/react-use-escape-keydown@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 optionalDependencies: @@ -17314,13 +18044,13 @@ snapshots: '@radix-ui/react-use-rect@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/rect': 1.0.0 react: 18.2.0 '@radix-ui/react-use-rect@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/rect': 1.0.1 react: 18.2.0 optionalDependencies: @@ -17328,7 +18058,7 @@ snapshots: '@radix-ui/react-use-size@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) react: 18.2.0 @@ -17349,11 +18079,11 @@ snapshots: '@radix-ui/rect@1.0.0': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/rect@1.0.1': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@react-dnd/asap@4.0.1': {} @@ -17802,6 +18532,13 @@ snapshots: '@react-native/assets-registry@0.73.1': {} + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -17809,6 +18546,54 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-react-jsx': 7.25.2(@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) + '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/template': 7.25.0 + '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.23.7) + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17857,6 +18642,19 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/parser': 7.25.3 + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + flow-parser: 0.206.0 + glob: 7.2.3 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/parser': 7.25.3 @@ -17891,6 +18689,27 @@ snapshots: - supports-color - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-tools': 12.3.7(encoding@0.1.13) + '@react-native/dev-middleware': 0.73.8(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + chalk: 4.1.2 + execa: 5.1.1 + metro: 0.80.5(encoding@0.1.13) + metro-config: 0.80.5(encoding@0.1.13) + metro-core: 0.80.5 + node-fetch: 2.6.12(encoding@0.1.13) + readline: 1.3.0 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) @@ -17937,6 +18756,16 @@ snapshots: '@react-native/js-polyfills@0.73.1': {} + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@react-native/babel-preset': 0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + hermes-parser: 0.15.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17947,7 +18776,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': + '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/js-polyfills': 0.73.1 '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -17956,10 +18785,7 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - - bufferutil - - encoding - supports-color - - utf-8-validate '@react-native/normalize-color@2.1.0': {} @@ -17967,6 +18793,12 @@ snapshots: '@react-native/normalize-colors@0.74.84': {} + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))': dependencies: invariant: 2.2.4 @@ -20285,9 +21117,10 @@ snapshots: dependencies: big-integer: 1.6.52 - '@urbit/http-api@3.1.0-dev-3(patch_hash=a4psibisxhh5q6cyjn3nbiaogm)': + '@urbit/http-api@3.2.0-dev': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 + '@types/node': 20.14.10 browser-or-node: 1.3.0 core-js: 3.24.1 @@ -20802,6 +21635,15 @@ snapshots: cosmiconfig: 7.1.0 resolve: 1.22.4 + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.7): + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.25.2): dependencies: '@babel/compat-data': 7.25.2 @@ -20811,6 +21653,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20819,6 +21669,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20827,6 +21685,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20838,6 +21703,12 @@ snapshots: babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.23.7): + dependencies: + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + transitivePeerDependencies: + - '@babel/core' + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2): dependencies: '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) @@ -21846,7 +22717,7 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 csstype: 3.1.0 dom-serializer@2.0.0: @@ -24366,6 +25237,31 @@ snapshots: jsc-safe-url@0.2.4: {} + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)): + dependencies: + '@babel/core': 7.25.2 + '@babel/parser': 7.25.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.25.2) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.25.2) + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + '@babel/preset-flow': 7.23.3(@babel/core@7.25.2) + '@babel/preset-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/register': 7.23.7(@babel/core@7.25.2) + babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) + chalk: 4.1.2 + flow-parser: 0.206.0 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.21.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.25.2)): dependencies: '@babel/core': 7.25.2 @@ -24929,7 +25825,7 @@ snapshots: metro-runtime@0.80.5: dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 metro-source-map@0.80.5: dependencies: @@ -26399,6 +27295,13 @@ snapshots: transitivePeerDependencies: - encoding + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): + dependencies: + escape-string-regexp: 2.0.0 + invariant: 2.2.4 + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: escape-string-regexp: 2.0.0 @@ -26460,6 +27363,55 @@ snapshots: - supports-color - utf-8-validate + react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-android': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 12.3.7(encoding@0.1.13) + '@react-native/assets-registry': 0.73.1 + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13) + '@react-native/gradle-plugin': 0.73.4 + '@react-native/js-polyfills': 0.73.1 + '@react-native/normalize-colors': 0.73.2 + '@react-native/virtualized-lists': 0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0)) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + deprecated-react-native-prop-types: 5.0.0 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.5 + metro-source-map: 0.80.5 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 4.28.5 + react-refresh: 0.14.0 + react-shallow-renderer: 16.15.0(react@18.2.0) + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0): dependencies: '@jest/create-cache-key-function': 29.7.0 From 76bddd277c76b7faf523119ef08a2f2741d6f6b7 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 9 Oct 2024 12:15:37 -0500 Subject: [PATCH 028/259] authenticated-app: correct import --- apps/tlon-mobile/src/components/AuthenticatedApp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 1af8cc280e..d1b3e7c54c 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -1,4 +1,5 @@ import crashlytics from '@react-native-firebase/crashlytics'; +import { ENABLED_LOGGERS } from '@tloncorp/app/constants'; import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; @@ -13,7 +14,6 @@ import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { initializeCrashReporter, sync } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; -import { ENABLED_LOGGERS } from 'packages/app/constants'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; From 978d57a27740fd5b59421333134f57373307d469 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 9 Oct 2024 14:11:39 -0500 Subject: [PATCH 029/259] urbit: correct types/callsites --- apps/tlon-mobile/src/components/AuthenticatedApp.tsx | 2 +- apps/tlon-web-new/src/app.tsx | 11 +++++++++-- packages/app/lib/api.ts | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index d1b3e7c54c..35a13bbb1a 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -44,7 +44,7 @@ function AuthenticatedApp({ shipName: ship ?? '', shipUrl: shipUrl ?? '', verbose: ENABLED_LOGGERS.includes('urbit'), - onReset: () => sync.syncStart(true), + onReconnect: () => sync.syncStart(true), onChannelReset: () => { const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours const lastReconnect = session?.startTime ?? 0; diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index b54d788537..d14da7fe32 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -119,6 +119,7 @@ const App = React.memo(function AppComponent() { const handleError = useErrorHandler(); const isDarkMode = useIsDark(); const currentUserId = useCurrentUserId(); + const session = store.useCurrentSession(); const [dbIsLoaded, setDbIsLoaded] = useState(false); const [startedSync, setStartedSync] = useState(false); @@ -132,8 +133,14 @@ const App = React.memo(function AppComponent() { api.configureClient({ shipName: currentUserId, shipUrl: '', - onReset: () => sync.syncStart(), - onChannelReset: () => sync.handleDiscontinuity(), + onReconnect: () => sync.syncStart(true), + onChannelReset: () => { + const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours + const lastReconnect = session?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } + }, }); const syncStart = async () => { await sync.syncStart(startedSync); diff --git a/packages/app/lib/api.ts b/packages/app/lib/api.ts index 57cd791937..c8e2b90cd1 100644 --- a/packages/app/lib/api.ts +++ b/packages/app/lib/api.ts @@ -50,14 +50,14 @@ export const cancelFetch = () => { export function configureClient({ shipName, shipUrl, - onReset, + onReconnect, onChannelReset, onChannelStatusChange, verbose, }: { shipName: string; shipUrl: string; - onReset?: () => void; + onReconnect?: () => void; onChannelReset?: () => void; onChannelStatusChange?: (status: ChannelStatus) => void; verbose?: boolean; @@ -66,7 +66,7 @@ export function configureClient({ shipName, shipUrl, fetchFn: apiFetch, - onReset, + onReconnect, onChannelReset, onChannelStatusChange, verbose, From c76f015b10b470106a88d308dfc9dc1f29d6bff2 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 10 Oct 2024 10:05:40 -0500 Subject: [PATCH 030/259] urbit: responding to pr feedback --- .../src/components/AuthenticatedApp.tsx | 20 +++++++++++-------- packages/shared/src/api/urbit.ts | 16 +++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 426893e63a..5053b8f6f0 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -21,6 +21,8 @@ import { } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; +import { useHandleLogout } from 'packages/app/hooks/useHandleLogout.native'; +import { useResetDb } from 'packages/app/hooks/useResetDb.native'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; @@ -48,6 +50,13 @@ function AuthenticatedApp({ useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); + const resetDb = useResetDb(); + const logout = useHandleLogout({ + resetDb: () => { + appLogger.log('Resetting db on logout'); + resetDb(); + }, + }); const navigation = useNavigation< NativeStackNavigationProp< @@ -73,13 +82,8 @@ function AuthenticatedApp({ const { code } = await getShipAccessCode(ship); return code; }, - handleAuthFailure: () => { - setShip({ - ship: undefined, - shipUrl, - authType, - authCookie: undefined, - }); + handleAuthFailure: async () => { + await logout(); if (authType === 'self') { navigation.navigate('ShipLogin'); return; @@ -87,7 +91,7 @@ function AuthenticatedApp({ navigation.navigate('TlonLogin'); }, - onReconnect: () => sync.syncStart(true), + onReconnect: () => sync.handleDiscontinuity(), onChannelReset: () => { const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours const lastReconnect = session?.startTime ?? 0; diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 6df0b2e7c9..cedd535e41 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -223,7 +223,7 @@ export async function subscribe( const retry = async (err: any) => { logger.error('bad subscribe', printEndpoint(endpoint), err); - config.pendingAuth = auth(); + config.pendingAuth = reauth(); return doSub(); }; @@ -249,7 +249,7 @@ export async function subscribeOnce( return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); } catch (err) { logger.error('bad subscribeOnce', printEndpoint(endpoint), err); - await auth(); + await reauth(); return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); } } @@ -265,7 +265,7 @@ export async function unsubscribe(id: number) { return config.client.unsubscribe(id); } catch (err) { logger.error('bad unsubscribe', id, err); - await auth(); + await reauth(); return config.client.unsubscribe(id); } } @@ -288,7 +288,7 @@ export async function poke({ app, mark, json }: PokeParams) { }; const retry = async (err: any) => { logger.log('bad poke', app, mark, json, err); - await auth(); + await reauth(); return doPoke(); }; @@ -349,7 +349,7 @@ export async function scry({ app, path }: { app: string; path: string }) { logger.log('bad scry', app, path, res.status); if (res.status === 403) { logger.log('scry failed with 403, authing to try again'); - await auth(); + await reauth(); return config.client.scry({ app, path }); } const body = await res.text(); @@ -357,7 +357,7 @@ export async function scry({ app, path }: { app: string; path: string }) { } } -async function auth() { +async function reauth() { if (!config.getCode) { console.warn('No getCode function provided for auth'); if (config.handleAuthFailure) { @@ -368,7 +368,7 @@ async function auth() { } if (config.pendingAuth) { - await config.pendingAuth; + return config.pendingAuth; } try { @@ -407,7 +407,7 @@ async function auth() { tryAuth(); }); - return config.pendingAuth; + return await config.pendingAuth; } catch (e) { logger.error('error getting urbit code', e); config.pendingAuth = null; From 22aab4d3f877b1c645d6dfa184afe100200eb025 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 10 Oct 2024 15:22:57 -0500 Subject: [PATCH 031/259] client: make reusable hook --- .../src/components/AuthenticatedApp.tsx | 34 ++++++++----------- apps/tlon-web-new/src/app.tsx | 14 ++------ packages/app/hooks/useConfigureUrbitClient.ts | 32 +++++++++++++++++ packages/shared/src/api/urbit.ts | 6 +++- 4 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 packages/app/hooks/useConfigureUrbitClient.ts diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 5053b8f6f0..9b5b20d66d 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -1,16 +1,15 @@ import crashlytics from '@react-native-firebase/crashlytics'; import { useNavigation } from '@react-navigation/native'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; -import { ENABLED_LOGGERS } from '@tloncorp/app/constants'; import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; +import { useConfigureUrbitClient } from '@tloncorp/app/hooks/useConfigureUrbitClient'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; import { usePostSignup } from '@tloncorp/app/hooks/usePostSignup'; -import { cancelFetch, configureClient } from '@tloncorp/app/lib/api'; -import { getShipAccessCode } from '@tloncorp/app/lib/hostingApi'; +import { cancelFetch } from '@tloncorp/app/lib/api'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; @@ -21,8 +20,9 @@ import { } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; -import { useHandleLogout } from 'packages/app/hooks/useHandleLogout.native'; -import { useResetDb } from 'packages/app/hooks/useResetDb.native'; +import { useHandleLogout } from 'packages/app/hooks/useHandleLogout'; +import { useResetDb } from 'packages/app/hooks/useResetDb'; +import { getShipAccessCode } from 'packages/app/lib/hostingApi'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; @@ -32,20 +32,21 @@ import useNotificationListener, { } from '../hooks/useNotificationListener'; import { OnboardingStackParamList } from '../types'; -const appLogger = createDevLogger('app', false); - export interface AuthenticatedAppProps { notificationListenerProps: NotificationListenerProps; } +const appLogger = createDevLogger('app', false); + function AuthenticatedApp({ notificationListenerProps, }: AuthenticatedAppProps) { - const { ship, shipUrl, authType, setShip } = useShip(); + const shipInfo = useShip(); + const { ship, shipUrl, authType } = shipInfo; const currentUserId = useCurrentUserId(); const signupContext = useSignupContext(); const handlePostSignup = usePostSignup(); - const session = store.useCurrentSession(); + const configureClient = useConfigureUrbitClient(); useNotificationListener(notificationListenerProps); useDeepLinkListener(); useNavigationLogging(); @@ -69,12 +70,14 @@ function AuthenticatedApp({ configureClient({ shipName: ship ?? '', shipUrl: shipUrl ?? '', - verbose: ENABLED_LOGGERS.includes('urbit'), getCode: authType === 'self' ? undefined : async () => { - appLogger.log('Getting ship access code', { ship, authType }); + appLogger.log('Getting ship access code', { + ship, + authType, + }); if (!ship) { throw new Error('Trying to retrieve +code, no ship set'); } @@ -91,15 +94,6 @@ function AuthenticatedApp({ navigation.navigate('TlonLogin'); }, - onReconnect: () => sync.handleDiscontinuity(), - onChannelReset: () => { - const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours - const lastReconnect = session?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } - }, - onChannelStatusChange: sync.handleChannelStatusChange, }); initializeCrashReporter(crashlytics(), PlatformState); diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index d14da7fe32..d606469e88 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -6,6 +6,7 @@ import { NavigationContainer, useNavigationContainerRef, } from '@react-navigation/native'; +import { useConfigureUrbitClient } from '@tloncorp/app/hooks/useConfigureUrbitClient'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; import { checkDb, useMigrations } from '@tloncorp/app/lib/webDb'; @@ -13,7 +14,6 @@ import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { sync } from '@tloncorp/shared'; -import * as api from '@tloncorp/shared/dist/api'; import * as store from '@tloncorp/shared/dist/store'; import cookies from 'browser-cookies'; import { usePostHog } from 'posthog-js/react'; @@ -119,9 +119,9 @@ const App = React.memo(function AppComponent() { const handleError = useErrorHandler(); const isDarkMode = useIsDark(); const currentUserId = useCurrentUserId(); - const session = store.useCurrentSession(); const [dbIsLoaded, setDbIsLoaded] = useState(false); const [startedSync, setStartedSync] = useState(false); + const configureClient = useConfigureUrbitClient(); useEffect(() => { handleError(() => { @@ -130,17 +130,9 @@ const App = React.memo(function AppComponent() { }, [handleError]); useEffect(() => { - api.configureClient({ + configureClient({ shipName: currentUserId, shipUrl: '', - onReconnect: () => sync.syncStart(true), - onChannelReset: () => { - const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours - const lastReconnect = session?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } - }, }); const syncStart = async () => { await sync.syncStart(startedSync); diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts new file mode 100644 index 0000000000..2341be018a --- /dev/null +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -0,0 +1,32 @@ +import { sync, useCurrentSession } from '@tloncorp/shared/dist'; +import { ClientParams } from '@tloncorp/shared/dist/api'; +import { useCallback } from 'react'; + +import { ENABLED_LOGGERS } from '../constants'; +import { configureClient } from '../lib/api'; + +type PickPartial = Pick & Partial>; + +export function useConfigureUrbitClient() { + const session = useCurrentSession(); + + return useCallback( + (params: PickPartial) => { + configureClient({ + verbose: ENABLED_LOGGERS.includes('urbit'), + onReconnect: () => sync.handleDiscontinuity(), + onChannelReset: () => { + const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours + const lastReconnect = session?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } + }, + onChannelStatusChange: sync.handleChannelStatusChange, + // override any defaults with params + ...params, + }); + }, + [session] + ); +} diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index cedd535e41..8d78cc4540 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -96,6 +96,7 @@ export const getCurrentUserIsHosted = () => { return client.url.endsWith('tlon.network'); }; +let configureCount = 0; export function configureClient({ shipName, shipUrl, @@ -108,7 +109,10 @@ export function configureClient({ onChannelStatusChange, }: ClientParams) { logger.log('configuring client', shipName, shipUrl); - config.client = new Urbit(shipUrl, '', '', fetchFn); + if (configureCount++ > 0) { + logger.error('client already configured'); + } + config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.ship = deSig(shipName); config.client.our = preSig(shipName); config.client.verbose = verbose; From b7e0a457bf742f8a495fc89075b5f718b37d70f6 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 10 Oct 2024 15:25:47 -0500 Subject: [PATCH 032/259] app: track auth failures --- apps/tlon-mobile/src/components/AuthenticatedApp.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 9b5b20d66d..c2d1a804b8 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -23,6 +23,7 @@ import { ZStack } from '@tloncorp/ui'; import { useHandleLogout } from 'packages/app/hooks/useHandleLogout'; import { useResetDb } from 'packages/app/hooks/useResetDb'; import { getShipAccessCode } from 'packages/app/lib/hostingApi'; +import { trackError } from 'packages/app/utils/posthog'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; @@ -78,6 +79,10 @@ function AuthenticatedApp({ ship, authType, }); + trackError({ + message: + 'Hosted ship logged out of urbit, getting ship access code', + }); if (!ship) { throw new Error('Trying to retrieve +code, no ship set'); } @@ -86,6 +91,9 @@ function AuthenticatedApp({ return code; }, handleAuthFailure: async () => { + trackError({ + message: 'Failed to authenticate with ship, redirecting to login', + }); await logout(); if (authType === 'self') { navigation.navigate('ShipLogin'); From 6d3a457e6ff1ff2532fbc9a0433ba526018fe6d4 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 10 Oct 2024 15:28:05 -0500 Subject: [PATCH 033/259] ops: fixing imports --- apps/tlon-mobile/src/components/AuthenticatedApp.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index c2d1a804b8..7f33d6ae53 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -6,13 +6,17 @@ import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; import { useConfigureUrbitClient } from '@tloncorp/app/hooks/useConfigureUrbitClient'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; +import { useHandleLogout } from '@tloncorp/app/hooks/useHandleLogout'; import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; import { usePostSignup } from '@tloncorp/app/hooks/usePostSignup'; +import { useResetDb } from '@tloncorp/app/hooks/useResetDb'; import { cancelFetch } from '@tloncorp/app/lib/api'; +import { getShipAccessCode } from '@tloncorp/app/lib/hostingApi'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; +import { trackError } from '@tloncorp/app/utils/posthog'; import { createDevLogger, initializeCrashReporter, @@ -20,10 +24,6 @@ import { } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; -import { useHandleLogout } from 'packages/app/hooks/useHandleLogout'; -import { useResetDb } from 'packages/app/hooks/useResetDb'; -import { getShipAccessCode } from 'packages/app/lib/hostingApi'; -import { trackError } from 'packages/app/utils/posthog'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; From d1828989bff617d85ed77259a71602caf9aeaf4c Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 10 Oct 2024 16:19:39 -0500 Subject: [PATCH 034/259] client: refining reconnect logic and session accessing --- packages/app/hooks/useConfigureUrbitClient.ts | 18 ++++++++++++------ packages/shared/src/store/session.ts | 7 +++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 2341be018a..9082736219 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -1,4 +1,4 @@ -import { sync, useCurrentSession } from '@tloncorp/shared/dist'; +import { getSession, sync, updateSession } from '@tloncorp/shared/dist'; import { ClientParams } from '@tloncorp/shared/dist/api'; import { useCallback } from 'react'; @@ -8,16 +8,22 @@ import { configureClient } from '../lib/api'; type PickPartial = Pick & Partial>; export function useConfigureUrbitClient() { - const session = useCurrentSession(); - return useCallback( (params: PickPartial) => { configureClient({ verbose: ENABLED_LOGGERS.includes('urbit'), - onReconnect: () => sync.handleDiscontinuity(), + onReconnect: () => { + const threshold = 5 * 60 * 1000; // 5 minutes + const lastReconnect = getSession()?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } else { + updateSession({ startTime: Date.now() }); + } + }, onChannelReset: () => { const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours - const lastReconnect = session?.startTime ?? 0; + const lastReconnect = getSession()?.startTime ?? 0; if (Date.now() - lastReconnect >= threshold) { sync.handleDiscontinuity(); } @@ -27,6 +33,6 @@ export function useConfigureUrbitClient() { ...params, }); }, - [session] + [] ); } diff --git a/packages/shared/src/store/session.ts b/packages/shared/src/store/session.ts index 2f92282739..e946f4fad1 100644 --- a/packages/shared/src/store/session.ts +++ b/packages/shared/src/store/session.ts @@ -65,6 +65,9 @@ export function useSyncing() { export function useConnectionStatus() { const currentSession = useCurrentSession(); const syncing = useSyncing(); + if (syncing) { + return 'Syncing'; + } if (!currentSession) { return 'Connecting'; @@ -74,9 +77,5 @@ export function useConnectionStatus() { return 'Reconnecting'; } - if (syncing) { - return 'Syncing'; - } - return 'Connected'; } From 4457f0892451d1e189f0ced6e080aa811af2ba77 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 10 Oct 2024 19:31:47 -0400 Subject: [PATCH 035/259] refactor --- apps/tlon-mobile/src/App.main.tsx | 8 +- .../src/components/AuthenticatedApp.tsx | 34 +- .../screens/Onboarding/CheckVerifyScreen.tsx | 7 +- .../screens/Onboarding/ReserveShipScreen.tsx | 8 +- .../Onboarding/SignUpPasswordScreen.tsx | 9 +- packages/app/contexts/signup.tsx | 301 +++--------------- packages/app/hooks/useBootSequence.ts | 290 +++++++++++++++++ packages/app/lib/api.ts | 26 +- packages/app/lib/bootHelpers.ts | 10 +- packages/shared/src/store/session.ts | 34 +- 10 files changed, 421 insertions(+), 306 deletions(-) create mode 100644 packages/app/hooks/useBootSequence.ts diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 86e412168b..1b98221403 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -10,14 +10,13 @@ import { useNavigationContainerRef, } from '@react-navigation/native'; import ErrorBoundary from '@tloncorp/app/ErrorBoundary'; -import { BranchProvider, useBranch } from '@tloncorp/app/contexts/branch'; +import { BranchProvider } from '@tloncorp/app/contexts/branch'; import { ShipProvider, useShip } from '@tloncorp/app/contexts/ship'; import { SignupProvider, useSignupContext, } from '@tloncorp/app/contexts/signup'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; -import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; import { useMigrations } from '@tloncorp/app/lib/nativeDb'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { FeatureFlagConnectedInstrumentationProvider } from '@tloncorp/app/utils/perf'; @@ -77,10 +76,7 @@ const App = ({ - ) : isAuthenticated && - [NodeBootPhase.IDLE, NodeBootPhase.READY].includes( - signupContext.bootPhase - ) ? ( + ) : isAuthenticated && !signupContext.isOngoing ? ( { // TODO: i think we need a proper idle state? - console.log(`authenticated app connection status: ${connectionStatus}`); - if (connectionStatus === 'Idle') { - configureClient({ - shipName: ship ?? '', - shipUrl: shipUrl ?? '', - onReset: () => sync.syncStart(), - onChannelReset: () => sync.handleDiscontinuity(), - onChannelStatusChange: sync.handleChannelStatusChange, - }); - } + // configureClient({ + // shipName: ship ?? '', + // shipUrl: shipUrl ?? '', + // onReset: () => sync.syncStart(), + // onChannelReset: () => sync.handleDiscontinuity(), + // onChannelStatusChange: sync.handleChannelStatusChange, + // }); initializeCrashReporter(crashlytics(), PlatformState); @@ -58,19 +55,12 @@ function AuthenticatedApp({ store.setErrorTrackingUserId(currentUserId); } - if (signupContext.didSignup) { - handlePostSignup(); - } + // if (signupContext.didSignup) { + // handlePostSignup(); + // } - sync.syncStart(); - }, [ - connectionStatus, - currentUserId, - handlePostSignup, - ship, - shipUrl, - signupContext.didSignup, - ]); + // sync.syncStart(); + }, [currentUserId, handlePostSignup, ship, shipUrl]); const handleAppStatusChange = useCallback((status: AppStateStatus) => { if (status === 'active') { diff --git a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx index a22f19b756..0a780747ce 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx @@ -1,4 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { trackError, trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { Field, @@ -33,6 +34,7 @@ export const CheckVerifyScreen = ({ const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(); const { hostingApi } = useOnboardingContext(); + const signupContext = useSignupContext(); const handleSubmit = useCallback( async (code: string) => { @@ -49,7 +51,8 @@ export const CheckVerifyScreen = ({ actionName: 'Verification Submitted', }); - navigation.navigate('ReserveShip', { user }); + signupContext.setHostingUser(user); + navigation.navigate('SetNickname', { user }); } catch (err) { console.error('Error submitting verification:', err); if (err instanceof Error) { @@ -60,7 +63,7 @@ export const CheckVerifyScreen = ({ setIsSubmitting(false); }, - [hostingApi, isEmail, navigation, user] + [hostingApi, isEmail, navigation, signupContext, user] ); const handleCodeChanged = useCallback( diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index ddeadf81ba..cd543533db 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -202,8 +202,12 @@ export const ReserveShipScreen = ({ ); useEffect(() => { - if (signupContext.bootPhase === NodeBootPhase.IDLE) { - signupContext.initializeBootSequence(); + // if (signupContext.bootPhase === NodeBootPhase.IDLE) { + // signupContext.initializeBootSequence(); + // } + + if (!signupContext.didCompleteSignup) { + signupContext.setDidCompleteSignup(true); } }, [signupContext]); diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx index fb68f4ead0..becdc19d12 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx @@ -126,7 +126,7 @@ export const SignUpPasswordScreen = ({ email, password, }); - signupContext.setHostingUser(user); + // signupContext.setHostingUser(user); if (user.requirePhoneNumberVerification) { navigation.navigate('RequestPhoneVerify', { user }); } else { @@ -188,12 +188,17 @@ export const SignUpPasswordScreen = ({ } }, [recaptchaError]); + const goBackHandler = useCallback(() => { + signupContext.setDidSignup(false); + navigation.goBack(); + }, [navigation, signupContext]); + return ( navigation.goBack()} + backAction={goBackHandler} isLoading={isSubmitting} rightControls={ diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index bbdf68508e..11cdab1ae0 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -1,299 +1,82 @@ import { createDevLogger } from '@tloncorp/shared/dist'; -import * as store from '@tloncorp/shared/dist/store'; import { createContext, useCallback, useContext, - useEffect, - useRef, + useMemo, useState, } from 'react'; -import { configureClient } from '../lib/api'; +import { useBootSequence } from '../hooks/useBootSequence'; import { NodeBootPhase } from '../lib/bootHelpers'; -import BootHelpers from '../lib/bootHelpers'; -import { getShipFromCookie } from '../utils/ship'; -import { useLureMetadata } from './branch'; -import { useShip } from './ship'; const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); -interface SignupValues { +const logger = createDevLogger('signup', true); + +export interface SignupParams { nickname?: string; notificationToken?: string; telemetry?: boolean; - didSignup?: boolean; - + didBeginSignup?: boolean; + didCompleteSignup?: boolean; + isOngoing?: boolean; hostingUser: { id: string } | null; reservedNodeId: string | null; bootPhase: NodeBootPhase; } -interface SignupContext extends SignupValues { +type SignupValues = Omit; +const defaultValues: SignupValues = { + nickname: undefined, + hostingUser: null, + reservedNodeId: null, +}; + +interface SignupContext extends SignupParams { setHostingUser: (hostingUser: { id: string }) => void; setNickname: (nickname: string | undefined) => void; setNotificationToken: (notificationToken: string | undefined) => void; setTelemetry: (telemetry: boolean) => void; setDidSignup: (didSignup: boolean) => void; - initializeBootSequence: () => void; + setDidCompleteSignup: (value: boolean) => void; clear: () => void; } -const defaultContext: SignupContext = { - nickname: undefined, - hostingUser: null, - reservedNodeId: null, - bootPhase: NodeBootPhase.IDLE, +const defaultMethods = { setNickname: () => {}, setNotificationToken: () => {}, setTelemetry: () => {}, setDidSignup: () => {}, - initializeBootSequence: () => {}, setHostingUser: () => {}, + setDidCompleteSignup: () => {}, clear: () => {}, }; -const logger = createDevLogger('signup', true); - -const SignupContext = createContext(defaultContext); +const SignupContext = createContext({ + ...defaultValues, + ...defaultMethods, + bootPhase: NodeBootPhase.IDLE, +}); export const SignupProvider = ({ children }: { children: React.ReactNode }) => { - const [values, setValues] = useState(defaultContext); - const { setShip } = useShip(); - const connectionStatus = store.useConnectionStatus(); - const lureMeta = useLureMetadata(); + const [values, setValues] = useState(defaultValues); + const { bootPhase } = useBootSequence(values.hostingUser); + + const isOngoing = useMemo(() => { + return ( + values.didBeginSignup && + (!values.didCompleteSignup || bootPhase !== NodeBootPhase.READY) + ); + }, [values.didBeginSignup, values.didCompleteSignup, bootPhase]); - const setBootPhase = useCallback((bootPhase: NodeBootPhase) => { + const setDidCompleteSignup = useCallback((value: boolean) => { setValues((current) => ({ ...current, - bootPhase, + didCompleteSignup: value, })); }, []); - const initializeBootSequence = useCallback(() => { - if (values.bootPhase === NodeBootPhase.IDLE) { - setValues((current) => ({ - ...current, - bootPhase: NodeBootPhase.RESERVING, - })); - } - }, [values]); - - const runBootPhase = useCallback(async (): Promise => { - const { hostingUser, bootPhase } = values; - - if (!hostingUser) { - logger.log('no hosting user found, skipping'); - return bootPhase; - } - - // - // Step 1: reserve a node - // - if (bootPhase === NodeBootPhase.RESERVING) { - const reservedNodeId = await BootHelpers.reserveNode(hostingUser.id); - setValues((current) => ({ - ...current, - reservedNodeId, - })); - logger.log(`reserved node`, reservedNodeId); - return NodeBootPhase.BOOTING; - } - - // you should not be able to advance past here unless reservedNodeId is set - if (!values.reservedNodeId) { - throw new Error( - `cannot run boot phase ${bootPhase} without a reserved node` - ); - } - - // - // Step 2: confirm the node has finished booting on hosting - // - if (bootPhase === NodeBootPhase.BOOTING) { - const isReady = await BootHelpers.checkNodeBooted(values.reservedNodeId); - if (isReady) { - logger.log('checked hosting, node is ready'); - return NodeBootPhase.AUTHENTICATING; - } - - logger.log('checked hosting, node still booting'); - return NodeBootPhase.BOOTING; - } - - // - // Step 3: authenticate with the node itself - // - if (bootPhase === NodeBootPhase.AUTHENTICATING) { - const auth = await BootHelpers.authenticateNode(values.reservedNodeId); - console.log(`got auth`, auth); - const ship = getShipFromCookie(auth.authCookie); - console.log(`ship`, ship, auth.nodeId, auth.authCookie); - - setShip({ - ship, - shipUrl: auth.nodeUrl, - authCookie: auth.authCookie, - }); - - // TODO: connect to the API client? - configureClient({ - shipName: auth.nodeId, - shipUrl: auth.nodeUrl, - onReset: () => store.syncStart(), - onChannelReset: () => store.handleDiscontinuity(), - onChannelStatusChange: store.handleChannelStatusChange, - }); - store.syncStart(); - - logger.log(`authenticated with node`); - return NodeBootPhase.CONNECTING; - } - - // - // finish connecting to the node - // - if (bootPhase === NodeBootPhase.CONNECTING) { - await wait(1000); - if (connectionStatus === 'Connected') { - logger.log(`connection to node established`); - const signedUpWithInvite = Boolean(lureMeta?.id); - return signedUpWithInvite - ? NodeBootPhase.CHECKING_FOR_INVITE - : NodeBootPhase.READY; - } - - logger.log(`still connecting to node`, connectionStatus); - return NodeBootPhase.CONNECTING; - } - - // - // Step 4 [optional]: if we used an invite code to signup, see if we got the invites - // - if (bootPhase === NodeBootPhase.CHECKING_FOR_INVITE) { - const { invitedDm, invitedGroup } = - await BootHelpers.getInvitedGroupAndDm(lureMeta); - - if (invitedDm && invitedGroup) { - logger.log('confirmed node has the invites'); - return NodeBootPhase.ACCEPTING_INVITES; - } - - logger.log('checked node for invites, not yet found'); - return NodeBootPhase.CHECKING_FOR_INVITE; - } - - // - // Step 5 [optional]: join the invited groups - // - if (bootPhase === NodeBootPhase.ACCEPTING_INVITES) { - const { invitedDm, invitedGroup } = - await BootHelpers.getInvitedGroupAndDm(lureMeta); - - console.log(`invitedDm`, invitedDm); - console.log(`invitedGroup`, invitedGroup); - - // if we have invites, accept them - if (invitedDm && invitedDm.isDmInvite) { - logger.log(`accepting dm invitation`); - await store.respondToDMInvite({ channel: invitedDm, accept: true }); - } - - if ( - invitedGroup && - !invitedGroup.currentUserIsMember && - invitedGroup.haveInvite - ) { - logger.log('accepting group invitation'); - await store.joinGroup(invitedGroup); - } - - // give it some time to process, then hard refresh the data - await wait(2000); - if (invitedGroup) { - try { - await store.syncGroup(invitedGroup?.id); - } catch (e) { - logger.error('failed to sync group?', e.body); - } - } - if (invitedDm) { - try { - await store.syncDms(); - } catch (e) { - logger.error('failed to sync dms?', e); - } - } - - // check if we successfully joined - const { invitedDm: updatedDm, invitedGroup: updatedGroup } = - await BootHelpers.getInvitedGroupAndDm(lureMeta); - - const dmIsGood = updatedDm && !updatedDm.isDmInvite; - const groupIsGood = - updatedGroup && - updatedGroup.currentUserIsMember && - updatedGroup.channels && - updatedGroup.channels.length > 0; - - if (dmIsGood && groupIsGood) { - logger.log('successfully accepted invites'); - return NodeBootPhase.READY; - } - - logger.log( - 'still waiting on invites to be accepted', - `dm: ${dmIsGood}`, - `group: ${groupIsGood}` - ); - return NodeBootPhase.ACCEPTING_INVITES; - } - - return bootPhase; - }, [connectionStatus, lureMeta, setShip, values]); - - const isRunningRef = useRef(false); - const lastRunPhaseRef = useRef(values.bootPhase); - const lastRunErrored = useRef(false); - useEffect(() => { - const runBootSequence = async () => { - // prevent simultaneous runs - if (isRunningRef.current) { - return; - } - - isRunningRef.current = true; - - try { - // if rerunning failed step, wait before retry - const lastRunDidNotAdvance = - values.bootPhase === lastRunPhaseRef.current; - if (lastRunDidNotAdvance || lastRunErrored.current) { - await wait(3000); - } - - lastRunPhaseRef.current = values.bootPhase; - lastRunErrored.current = false; - - logger.log(`running boot sequence phase: ${values.bootPhase}`); - const nextBootPhase = await runBootPhase(); // TODO: i'm scared this will lock up if it hangs - setBootPhase(nextBootPhase); - } catch (e) { - logger.error('boot phase errored', e.message, e); - lastRunErrored.current = true; - setBootPhase(values.bootPhase); - - // handle - } finally { - isRunningRef.current = false; - } - }; - - if (![NodeBootPhase.IDLE, NodeBootPhase.READY].includes(values.bootPhase)) { - runBootSequence(); - } - }, [runBootPhase, setBootPhase, values.bootPhase]); - const setHostingUser = useCallback((hostingUser: { id: string }) => { setValues((current) => ({ ...current, @@ -325,31 +108,29 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { })); }, []); - const setDidSignup = useCallback((didSignup: boolean) => { + const setDidSignup = useCallback((didBeginSignup: boolean) => { setValues((current) => ({ ...current, - didSignup, + didBeginSignup, })); }, []); const clear = useCallback(() => { - setValues({ - bootPhase: NodeBootPhase.IDLE, - hostingUser: null, - reservedNodeId: null, - }); + setValues(defaultValues); }, []); return ( diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts new file mode 100644 index 0000000000..d4a1bed229 --- /dev/null +++ b/packages/app/hooks/useBootSequence.ts @@ -0,0 +1,290 @@ +import { createDevLogger } from '@tloncorp/shared/dist'; +import * as store from '@tloncorp/shared/dist/store'; +import { useCallback, useEffect, useRef, useState } from 'react'; + +import { useLureMetadata } from '../contexts/branch'; +import { useShip } from '../contexts/ship'; +import { configureClient } from '../lib/api'; +import { NodeBootPhase } from '../lib/bootHelpers'; +import BootHelpers from '../lib/bootHelpers'; +import { getShipFromCookie } from '../utils/ship'; + +const HANDLE_INVITES_TIMEOUT = 1000 * 30; + +const logger = createDevLogger('boot sequence', true); + +const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +/* + Handles making sure hosted nodes are ready to go during signup. Two main components: + + runBootPhase — executes a single step of the boot process, returns the next step in the sequence + runBootSequence — repeatedly executes runBootPhase until the sequence is complete + + The hook remains idle until passed a hosted user. Gives up after HANDLE_INVITES_TIMEOUT seconds if + we're stuck processing invites, but the node is otherwise ready. Exposes the current boot phase to + the caller. +*/ +export function useBootSequence(hostingUser: { id: string } | null) { + const { setShip } = useShip(); + const connectionStatus = store.useConnectionStatus(); + const lureMeta = useLureMetadata(); + + const [bootPhase, setBootPhase] = useState(NodeBootPhase.IDLE); + const [reservedNodeId, setReservedNodeId] = useState(null); + + const isRunningRef = useRef(false); + const lastRunPhaseRef = useRef(bootPhase); + const lastRunErrored = useRef(false); + const sequenceStartTimeRef = useRef(0); + + // detect when we're ready to start the sequence, kick things off + // by advancing past IDLE + useEffect(() => { + if (bootPhase === NodeBootPhase.IDLE && hostingUser?.id) { + setBootPhase(NodeBootPhase.RESERVING); + } + }, [bootPhase, hostingUser]); + + const runBootPhase = useCallback(async (): Promise => { + if (!hostingUser) { + logger.log('no hosting user found, skipping'); + return bootPhase; + } + + // + // RESERVING: reserve a node for the hosting account, or get one if it already exists + // + if (bootPhase === NodeBootPhase.RESERVING) { + const reservedNodeId = await BootHelpers.reserveNode(hostingUser.id); + setReservedNodeId(reservedNodeId); + logger.log(`reserved node`, reservedNodeId); + return NodeBootPhase.BOOTING; + } + + // you should not be able to advance past here unless reservedNodeId is set + if (!reservedNodeId) { + throw new Error( + `cannot run boot phase ${bootPhase} without a reserved node` + ); + } + + // + // BOOTING: confirm the node has finished booting on hosting + // + if (bootPhase === NodeBootPhase.BOOTING) { + const isReady = await BootHelpers.checkNodeBooted(reservedNodeId); + if (isReady) { + logger.log('checked hosting, node is ready'); + return NodeBootPhase.AUTHENTICATING; + } + + logger.log('checked hosting, node still booting'); + return NodeBootPhase.BOOTING; + } + + // + // AUTHENTICATING: authenticate with the node itself + // + if (bootPhase === NodeBootPhase.AUTHENTICATING) { + const auth = await BootHelpers.authenticateNode(reservedNodeId); + console.log(`got auth`, auth); + const ship = getShipFromCookie(auth.authCookie); + console.log(`ship`, ship, auth.nodeId, auth.authCookie); + + setShip({ + ship, + shipUrl: auth.nodeUrl, + authCookie: auth.authCookie, + }); + + configureClient({ + shipName: auth.nodeId, + shipUrl: auth.nodeUrl, + onReset: () => store.syncStart(), + onChannelReset: () => store.handleDiscontinuity(), + onChannelStatusChange: store.handleChannelStatusChange, + }); + store.syncStart(); + + logger.log(`authenticated with node`); + return NodeBootPhase.CONNECTING; + } + + // + // CONNECTING: make sure the connection is established + // + if (bootPhase === NodeBootPhase.CONNECTING) { + await wait(1000); + if (connectionStatus === 'Connected') { + logger.log(`connection to node established`); + const signedUpWithInvite = Boolean(lureMeta?.id); + return signedUpWithInvite + ? NodeBootPhase.CHECKING_FOR_INVITE + : NodeBootPhase.READY; + } + + logger.log(`still connecting to node`, connectionStatus); + return NodeBootPhase.CONNECTING; + } + + // + // CHECKING_FOR_INVITE [optional]: if we used an invite code to signup, see if we got the invites + // + if (bootPhase === NodeBootPhase.CHECKING_FOR_INVITE) { + const { invitedDm, invitedGroup } = + await BootHelpers.getInvitedGroupAndDm(lureMeta); + + if (invitedDm && invitedGroup) { + logger.log('confirmed node has the invites'); + return NodeBootPhase.ACCEPTING_INVITES; + } + + logger.log('checked node for invites, not yet found'); + return NodeBootPhase.CHECKING_FOR_INVITE; + } + + // + // ACCEPTING_INVITES [optional]: join the invited groups + // + if (bootPhase === NodeBootPhase.ACCEPTING_INVITES) { + const { invitedDm, invitedGroup, tlonTeamDM } = + await BootHelpers.getInvitedGroupAndDm(lureMeta); + + // if we have invites, accept them + if (tlonTeamDM && tlonTeamDM.isDmInvite) { + logger.log(`accepting dm invitation`); + await store.respondToDMInvite({ channel: tlonTeamDM, accept: true }); + } + + if (invitedDm && invitedDm.isDmInvite) { + logger.log(`accepting dm invitation`); + await store.respondToDMInvite({ channel: invitedDm, accept: true }); + } + + if ( + invitedGroup && + !invitedGroup.currentUserIsMember && + invitedGroup.haveInvite + ) { + logger.log('accepting group invitation'); + await store.joinGroup(invitedGroup); + } + + // give it some time to process, then hard refresh the data + await wait(2000); + if (invitedGroup) { + try { + await store.syncGroup(invitedGroup?.id); + } catch (e) { + logger.error('failed to sync group?', e.body); + } + } + if (invitedDm) { + try { + await store.syncDms(); + } catch (e) { + logger.error('failed to sync dms?', e); + } + } + + // check if we successfully joined + const { + invitedDm: updatedDm, + invitedGroup: updatedGroup, + tlonTeamDM: updatedTlonTeamDm, + } = await BootHelpers.getInvitedGroupAndDm(lureMeta); + + const dmIsGood = updatedDm && !updatedDm.isDmInvite; + const tlonTeamIsGood = updatedTlonTeamDm && !updatedTlonTeamDm.isDmInvite; + const groupIsGood = + updatedGroup && + updatedGroup.currentUserIsMember && + updatedGroup.channels && + updatedGroup.channels.length > 0; + + if (dmIsGood && groupIsGood) { + logger.log('successfully accepted invites'); + if (updatedTlonTeamDm) { + store.pinItem(updatedTlonTeamDm); + } + return NodeBootPhase.READY; + } + + logger.log( + 'still waiting on invites to be accepted', + `dm: ${dmIsGood}`, + `group: ${groupIsGood}`, + `tlonTeam: ${tlonTeamIsGood}` + ); + return NodeBootPhase.ACCEPTING_INVITES; + } + + return bootPhase; + }, [ + bootPhase, + connectionStatus, + hostingUser, + lureMeta, + reservedNodeId, + setShip, + ]); + + useEffect(() => { + const runBootSequence = async () => { + // prevent simultaneous runs + if (isRunningRef.current) { + return; + } + + isRunningRef.current = true; + if (!sequenceStartTimeRef.current) { + sequenceStartTimeRef.current = Date.now(); + } + + try { + // if rerunning failed step, wait before retry + const lastRunDidNotAdvance = bootPhase === lastRunPhaseRef.current; + if (lastRunDidNotAdvance || lastRunErrored.current) { + await wait(3000); + } + + lastRunPhaseRef.current = bootPhase; + lastRunErrored.current = false; + logger.log(`running boot sequence phase: ${bootPhase}`); + + const nextBootPhase = await runBootPhase(); + setBootPhase(nextBootPhase); + } catch (e) { + logger.error(`${bootPhase} errored`, e.message, e); + lastRunErrored.current = true; + setBootPhase(bootPhase); + + // handle + } finally { + isRunningRef.current = false; + } + }; + + // if we're stuck trying to handle invites afte user finishes signing up, bail + const beenRunningTooLong = + Date.now() - sequenceStartTimeRef.current > HANDLE_INVITES_TIMEOUT; + const isInOptionalPhase = [ + NodeBootPhase.ACCEPTING_INVITES, + NodeBootPhase.CHECKING_FOR_INVITE, + ].includes(bootPhase); + if (isInOptionalPhase && beenRunningTooLong) { + logger.log('timed out waiting for invites, proceeding'); + setBootPhase(NodeBootPhase.READY); + return; + } + + if (![NodeBootPhase.IDLE, NodeBootPhase.READY].includes(bootPhase)) { + runBootSequence(); + } + }, [runBootPhase, setBootPhase, bootPhase]); + + return { + bootPhase, + }; +} diff --git a/packages/app/lib/api.ts b/packages/app/lib/api.ts index 57cd791937..f6a79a3667 100644 --- a/packages/app/lib/api.ts +++ b/packages/app/lib/api.ts @@ -1,4 +1,8 @@ import * as api from '@tloncorp/shared/dist/api'; +import { + getInitializedClient, + updateInitializedClient, +} from '@tloncorp/shared/dist/store'; import { ChannelStatus } from '@urbit/http-api'; //@ts-expect-error no typedefs import { fetch as streamingFetch } from 'react-native-fetch-api'; @@ -62,13 +66,17 @@ export function configureClient({ onChannelStatusChange?: (status: ChannelStatus) => void; verbose?: boolean; }) { - api.configureClient({ - shipName, - shipUrl, - fetchFn: apiFetch, - onReset, - onChannelReset, - onChannelStatusChange, - verbose, - }); + const clientInitialized = getInitializedClient(); + if (!clientInitialized) { + api.configureClient({ + shipName, + shipUrl, + fetchFn: apiFetch, + onReset, + onChannelReset, + onChannelStatusChange, + verbose, + }); + updateInitializedClient(true); + } } diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts index db2b7d57bb..6d13750baf 100644 --- a/packages/app/lib/bootHelpers.ts +++ b/packages/app/lib/bootHelpers.ts @@ -142,11 +142,16 @@ async function authenticateNode( async function getInvitedGroupAndDm( lureMeta: LureData | null -): Promise<{ invitedDm: db.Channel | null; invitedGroup: db.Group | null }> { +): Promise<{ + invitedDm: db.Channel | null; + tlonTeamDM: db.Channel | null; + invitedGroup: db.Group | null; +}> { if (!lureMeta) { throw new Error('no stored invite found, cannot check'); } const { invitedGroupId, inviterUserId } = lureMeta; + const tlonTeam = `~wittyr-witbes`; if (!invitedGroupId || !inviterUserId) { throw new Error( `invalid invite metadata: group[${invitedGroupId}] inviter[${inviterUserId}]` @@ -154,7 +159,8 @@ async function getInvitedGroupAndDm( } // use api client to see if you have pending DM and group invite const invitedDm = await db.getChannel({ id: inviterUserId }); + const tlonTeamDM = await db.getChannel({ id: tlonTeam }); const invitedGroup = await db.getGroup({ id: invitedGroupId }); - return { invitedDm, invitedGroup }; + return { invitedDm, invitedGroup, tlonTeamDM }; } diff --git a/packages/shared/src/store/session.ts b/packages/shared/src/store/session.ts index 925cb9a3d6..fe3a596713 100644 --- a/packages/shared/src/store/session.ts +++ b/packages/shared/src/store/session.ts @@ -62,11 +62,43 @@ export function useSyncing() { return useSyncExternalStore(subscribeToIsSyncing, getSyncing); } +// Initialized Client — whether the client has been initialized +let initializedClient: boolean = false; +type InitializedClientListener = (initialized: boolean) => void; +const initializedClientListeners: InitializedClientListener[] = []; + +export function getInitializedClient() { + return initializedClient; +} + +export function updateInitializedClient(newValue: boolean) { + initializedClient = newValue; + initializedClientListeners.forEach((listener) => listener(newValue)); +} + +function subscribeToInitializedClient(listener: InitializedClientListener) { + initializedClientListeners.push(listener); + return () => { + initializedClientListeners.splice( + initializedClientListeners.indexOf(listener), + 1 + ); + }; +} + +export function useInitializedClient() { + return useSyncExternalStore( + subscribeToInitializedClient, + getInitializedClient + ); +} + export function useConnectionStatus() { const currentSession = useCurrentSession(); const syncing = useSyncing(); + const initializedClient = useInitializedClient(); - if (!syncing && !currentSession) { + if (!initializedClient) { return 'Idle'; } From 83c4398c3e66c1652d1fa4f0768ed147492e2e1b Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 00:58:53 -0400 Subject: [PATCH 036/259] log everything, cleanup --- packages/app/contexts/signup.tsx | 92 ++++++++++++++++++++++++--- packages/app/hooks/useBootSequence.ts | 78 +++++++++++++++-------- packages/app/lib/bootHelpers.ts | 50 +-------------- packages/shared/src/debug.ts | 19 +++++- 4 files changed, 151 insertions(+), 88 deletions(-) diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index 11cdab1ae0..67b46bde2c 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -1,16 +1,18 @@ import { createDevLogger } from '@tloncorp/shared/dist'; +import * as api from '@tloncorp/shared/dist/api'; +import * as store from '@tloncorp/shared/dist/store'; import { createContext, useCallback, useContext, + useEffect, useMemo, useState, } from 'react'; import { useBootSequence } from '../hooks/useBootSequence'; import { NodeBootPhase } from '../lib/bootHelpers'; - -const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +import { connectNotifyProvider } from '../lib/notificationsApi'; const logger = createDevLogger('signup', true); @@ -24,6 +26,7 @@ export interface SignupParams { hostingUser: { id: string } | null; reservedNodeId: string | null; bootPhase: NodeBootPhase; + userWasReadyAt?: number; } type SignupValues = Omit; @@ -61,7 +64,7 @@ const SignupContext = createContext({ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { const [values, setValues] = useState(defaultValues); - const { bootPhase } = useBootSequence(values.hostingUser); + const { bootPhase, bootReport } = useBootSequence(values); const isOngoing = useMemo(() => { return ( @@ -70,10 +73,18 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { ); }, [values.didBeginSignup, values.didCompleteSignup, bootPhase]); + const setDidSignup = useCallback((didBeginSignup: boolean) => { + setValues((current) => ({ + ...current, + didBeginSignup, + })); + }, []); + const setDidCompleteSignup = useCallback((value: boolean) => { setValues((current) => ({ ...current, didCompleteSignup: value, + userWasReadyAt: Date.now(), })); }, []); @@ -108,17 +119,37 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { })); }, []); - const setDidSignup = useCallback((didBeginSignup: boolean) => { - setValues((current) => ({ - ...current, - didBeginSignup, - })); - }, []); - const clear = useCallback(() => { + logger.log('clearing signup context'); setValues(defaultValues); }, []); + useEffect(() => { + if ( + values.didBeginSignup && + values.didCompleteSignup && + bootPhase === NodeBootPhase.READY + ) { + logger.log('running post-signup actions'); + const postSignupParams = { + nickname: values.nickname, + telemetry: values.telemetry, + notificationToken: values.notificationToken, + }; + handlePostSignup(postSignupParams); + clear(); + logger.trackEvent('hosted signup report', { + bootDuration: bootReport + ? bootReport.completedAt - bootReport.startedAt + : null, + userSatWaitingFor: values.userWasReadyAt + ? Date.now() - values.userWasReadyAt + : null, + timeUnit: 'ms', + }); + } + }, [values, bootPhase, clear, bootReport]); + return ( new Promise((resolve) => setTimeout(resolve, ms)); +interface BootSequenceReport { + startedAt: number; + completedAt: number; +} + /* - Handles making sure hosted nodes are ready to go during signup. Two main components: - - runBootPhase — executes a single step of the boot process, returns the next step in the sequence + Takes a fresh hosting account and holds its hand until it has a node that's ready to transition + to a logged in state. + + Two main components: + runBootPhase — executes a single boot step, returns the next step in the sequence runBootSequence — repeatedly executes runBootPhase until the sequence is complete The hook remains idle until passed a hosted user. Gives up after HANDLE_INVITES_TIMEOUT seconds if we're stuck processing invites, but the node is otherwise ready. Exposes the current boot phase to the caller. */ -export function useBootSequence(hostingUser: { id: string } | null) { +export function useBootSequence({ + hostingUser, +}: { + hostingUser: { id: string } | null; +}) { const { setShip } = useShip(); const connectionStatus = store.useConnectionStatus(); const lureMeta = useLureMetadata(); const [bootPhase, setBootPhase] = useState(NodeBootPhase.IDLE); const [reservedNodeId, setReservedNodeId] = useState(null); + const [report, setReport] = useState(null); const isRunningRef = useRef(false); const lastRunPhaseRef = useRef(bootPhase); @@ -48,7 +60,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { const runBootPhase = useCallback(async (): Promise => { if (!hostingUser) { - logger.log('no hosting user found, skipping'); + logger.crumb('no hosting user found, skipping'); return bootPhase; } @@ -58,7 +70,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { if (bootPhase === NodeBootPhase.RESERVING) { const reservedNodeId = await BootHelpers.reserveNode(hostingUser.id); setReservedNodeId(reservedNodeId); - logger.log(`reserved node`, reservedNodeId); + logger.crumb(`reserved node`, reservedNodeId); return NodeBootPhase.BOOTING; } @@ -75,11 +87,11 @@ export function useBootSequence(hostingUser: { id: string } | null) { if (bootPhase === NodeBootPhase.BOOTING) { const isReady = await BootHelpers.checkNodeBooted(reservedNodeId); if (isReady) { - logger.log('checked hosting, node is ready'); + logger.crumb('checked hosting, node is ready'); return NodeBootPhase.AUTHENTICATING; } - logger.log('checked hosting, node still booting'); + logger.crumb('checked hosting, node still booting'); return NodeBootPhase.BOOTING; } @@ -88,9 +100,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { // if (bootPhase === NodeBootPhase.AUTHENTICATING) { const auth = await BootHelpers.authenticateNode(reservedNodeId); - console.log(`got auth`, auth); const ship = getShipFromCookie(auth.authCookie); - console.log(`ship`, ship, auth.nodeId, auth.authCookie); setShip({ ship, @@ -107,7 +117,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { }); store.syncStart(); - logger.log(`authenticated with node`); + logger.crumb(`authenticated with node`); return NodeBootPhase.CONNECTING; } @@ -117,14 +127,14 @@ export function useBootSequence(hostingUser: { id: string } | null) { if (bootPhase === NodeBootPhase.CONNECTING) { await wait(1000); if (connectionStatus === 'Connected') { - logger.log(`connection to node established`); + logger.crumb(`connection to node established`); const signedUpWithInvite = Boolean(lureMeta?.id); return signedUpWithInvite ? NodeBootPhase.CHECKING_FOR_INVITE : NodeBootPhase.READY; } - logger.log(`still connecting to node`, connectionStatus); + logger.crumb(`still connecting to node`, connectionStatus); return NodeBootPhase.CONNECTING; } @@ -136,11 +146,11 @@ export function useBootSequence(hostingUser: { id: string } | null) { await BootHelpers.getInvitedGroupAndDm(lureMeta); if (invitedDm && invitedGroup) { - logger.log('confirmed node has the invites'); + logger.crumb('confirmed node has the invites'); return NodeBootPhase.ACCEPTING_INVITES; } - logger.log('checked node for invites, not yet found'); + logger.crumb('checked node for invites, not yet found'); return NodeBootPhase.CHECKING_FOR_INVITE; } @@ -153,12 +163,12 @@ export function useBootSequence(hostingUser: { id: string } | null) { // if we have invites, accept them if (tlonTeamDM && tlonTeamDM.isDmInvite) { - logger.log(`accepting dm invitation`); + logger.crumb(`accepting dm invitation`); await store.respondToDMInvite({ channel: tlonTeamDM, accept: true }); } if (invitedDm && invitedDm.isDmInvite) { - logger.log(`accepting dm invitation`); + logger.crumb(`accepting dm invitation`); await store.respondToDMInvite({ channel: invitedDm, accept: true }); } @@ -167,7 +177,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { !invitedGroup.currentUserIsMember && invitedGroup.haveInvite ) { - logger.log('accepting group invitation'); + logger.crumb('accepting group invitation'); await store.joinGroup(invitedGroup); } @@ -204,18 +214,18 @@ export function useBootSequence(hostingUser: { id: string } | null) { updatedGroup.channels.length > 0; if (dmIsGood && groupIsGood) { - logger.log('successfully accepted invites'); + logger.crumb('successfully accepted invites'); if (updatedTlonTeamDm) { store.pinItem(updatedTlonTeamDm); } return NodeBootPhase.READY; } - logger.log( + logger.crumb( 'still waiting on invites to be accepted', - `dm: ${dmIsGood}`, - `group: ${groupIsGood}`, - `tlonTeam: ${tlonTeamIsGood}` + `dm is ready: ${dmIsGood}`, + `group is ready: ${groupIsGood}`, + `tlonTeam is ready: ${tlonTeamIsGood}` ); return NodeBootPhase.ACCEPTING_INVITES; } @@ -246,6 +256,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { // if rerunning failed step, wait before retry const lastRunDidNotAdvance = bootPhase === lastRunPhaseRef.current; if (lastRunDidNotAdvance || lastRunErrored.current) { + logger.crumb('waiting before retrying last phase'); await wait(3000); } @@ -256,11 +267,13 @@ export function useBootSequence(hostingUser: { id: string } | null) { const nextBootPhase = await runBootPhase(); setBootPhase(nextBootPhase); } catch (e) { - logger.error(`${bootPhase} errored`, e.message, e); + logger.trackError('runBootPhase error', { + bootPhase, + errorMessage: e.message, + errorStack: e.stack, + }); lastRunErrored.current = true; setBootPhase(bootPhase); - - // handle } finally { isRunningRef.current = false; } @@ -274,7 +287,7 @@ export function useBootSequence(hostingUser: { id: string } | null) { NodeBootPhase.CHECKING_FOR_INVITE, ].includes(bootPhase); if (isInOptionalPhase && beenRunningTooLong) { - logger.log('timed out waiting for invites, proceeding'); + logger.trackError('accept invites abort'); setBootPhase(NodeBootPhase.READY); return; } @@ -284,7 +297,18 @@ export function useBootSequence(hostingUser: { id: string } | null) { } }, [runBootPhase, setBootPhase, bootPhase]); + // once finished, set the report + useEffect(() => { + if (bootPhase === NodeBootPhase.READY && report === null) { + setReport({ + startedAt: sequenceStartTimeRef.current, + completedAt: Date.now(), + }); + } + }, [bootPhase, report]); + return { bootPhase, + bootReport: report, }; } diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts index 6d13750baf..df1d06ec85 100644 --- a/packages/app/lib/bootHelpers.ts +++ b/packages/app/lib/bootHelpers.ts @@ -1,13 +1,9 @@ -import { configureApi } from '@tloncorp/shared/dist/api'; import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; -import { useCallback, useEffect, useState } from 'react'; import { LureData } from '../contexts/branch'; -import { useShip } from '../contexts/ship'; -import { useSignupContext } from '../contexts/signup'; import * as hostingApi from '../lib/hostingApi'; -import { trackError, trackOnboardingAction } from '../utils/posthog'; +import { trackOnboardingAction } from '../utils/posthog'; import { getShipFromCookie, getShipUrl } from '../utils/ship'; export enum NodeBootPhase { @@ -35,7 +31,6 @@ export async function reserveNode( skipShipIds: string[] = [] ): Promise { const user = await hostingApi.getHostingUser(hostingUserId); - // const shipIds = user.ships ?? []; // if the hosting user already has a ship tied to their account, use that if (user.ships?.length) { @@ -58,26 +53,15 @@ export async function reserveNode( } await hostingApi.allocateReservedShip(hostingUserId); - // shipIds.push(ship.id); trackOnboardingAction({ actionName: 'Urbit ID Selected', ship: ship.id, }); return ship.id; - // } catch (err) { - // console.error('Error reserving ship:', err); - // if (err instanceof Error) { - // trackError(err); - // // setError(err.message); - // } - // // setStatus(NodeBootPhase.ERROR); - // // return false; - // } } async function checkNodeBooted(nodeId: string): Promise { - // try { const shipsWithStatus = await hostingApi.getShipsWithStatus([nodeId]); if (!shipsWithStatus) { return false; @@ -90,34 +74,6 @@ async function checkNodeBooted(nodeId: string): Promise { } return true; - - // const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); - // const shipUrl = getShipUrl(shipId); - // const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); - // if (!authCookie) { - // throw new Error("Couldn't log you into your ship."); - // } - - // const ship = getShipFromCookie(authCookie); - // configureApi(ship, shipUrl); - - // setShip({ - // ship, - // shipUrl, - // authCookie, - // }); - - // setStatus(NodeBootPhase.READY); - // return NodeBootPhase.READY; - // } catch (err) { - // console.error('Error starting ship:', err); - // if (err instanceof Error) { - // trackError(err); - // // setError(err.message); - // } - // // setStatus(NodeBootPhase.ERROR); - // return NodeBootPhase.ERROR; - // } } async function authenticateNode( @@ -140,9 +96,7 @@ async function authenticateNode( }; } -async function getInvitedGroupAndDm( - lureMeta: LureData | null -): Promise<{ +async function getInvitedGroupAndDm(lureMeta: LureData | null): Promise<{ invitedDm: db.Channel | null; tlonTeamDM: db.Channel | null; invitedGroup: db.Group | null; diff --git a/packages/shared/src/debug.ts b/packages/shared/src/debug.ts index 4999c38667..9ff94917da 100644 --- a/packages/shared/src/debug.ts +++ b/packages/shared/src/debug.ts @@ -15,6 +15,7 @@ export type Logger = Console & { crumb: (...args: unknown[]) => void; sensitiveCrumb: (...args: unknown[]) => void; trackError: (message: string, data?: Record) => void; + trackEvent: (eventId: string, data?: Record) => void; }; const debugBreadcrumbs: Breadcrumb[] = []; @@ -42,10 +43,10 @@ interface ErrorLoggerStub { capture: (event: string, data: Record) => void; } -let errorLoggerInstance: ErrorLoggerStub | null = null; +let remoteLoggerInstance: ErrorLoggerStub | null = null; export function initializeErrorLogger(errorLoggerInput: ErrorLoggerStub) { if (errorLoggerInput) { - errorLoggerInstance = errorLoggerInput; + remoteLoggerInstance = errorLoggerInput; } } @@ -82,7 +83,7 @@ export function createDevLogger(tag: string, enabled: boolean) { if (prop === 'trackError') { const customProps = args[1] && typeof args[1] === 'object' ? args[1] : {}; - errorLoggerInstance?.capture('app_error', { + remoteLoggerInstance?.capture('app_error', { ...customProps, message: typeof args[0] === 'string' @@ -93,6 +94,18 @@ export function createDevLogger(tag: string, enabled: boolean) { resolvedProp = 'error'; } + if (prop == 'trackEvent') { + if (args[0] && typeof args[0] === 'string') { + const customProps = + args[1] && typeof args[1] === 'object' ? args[1] : {}; + remoteLoggerInstance?.capture('app_error', { + ...customProps, + message: `[${tag}] ${args[0]}`, + }); + } + resolvedProp = 'log'; + } + if ( (enabled || customLoggers.has(tag)) && process.env.NODE_ENV !== 'production' From 05b4e807765c6854187e02fce98ff2ea80cf2212 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 01:07:12 -0400 Subject: [PATCH 037/259] remove stale file --- packages/app/hooks/useSignupBootStatus.ts | 251 ---------------------- 1 file changed, 251 deletions(-) delete mode 100644 packages/app/hooks/useSignupBootStatus.ts diff --git a/packages/app/hooks/useSignupBootStatus.ts b/packages/app/hooks/useSignupBootStatus.ts deleted file mode 100644 index 399668d7ca..0000000000 --- a/packages/app/hooks/useSignupBootStatus.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { configureApi } from '@tloncorp/shared/dist/api'; -import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; -import { useCallback, useEffect, useState } from 'react'; - -import { useShip } from '../contexts/ship'; -import { useSignupContext } from '../contexts/signup'; -import * as hostingApi from '../lib/hostingApi'; -import { trackError, trackOnboardingAction } from '../utils/posthog'; -import { getShipFromCookie, getShipUrl } from '../utils/ship'; - -// import { useOnboardingContext } from '../../lib/OnboardingContext'; - -export enum NodeBootPhase { - IDLE = 'idle', - RESERVING = 'reserving', - BOOTING = 'booting', - AUTHENTICATING = 'authenticating', - CHECKING_FOR_INVITE = 'checking-for-invite', - CLAIMING_INVITE = 'claiming-invite', - READY = 'ready', - ERROR = 'error', -} - -export const useShipBoot = (userId: string) => { - const [status, setStatus] = useState(NodeBootPhase.IDLE); - const [error, setError] = useState(null); - const signupContext = useSignupContext(); - const { setShip } = useShip(); - - const startShip = useCallback( - async (shipIds: string[]) => { - // setStatus(NodeBootPhase.LOADING); - try { - const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); - if (!shipsWithStatus) { - setStatus(NodeBootPhase.BOOTING); - return; - } - - const { status: shipStatus, shipId } = shipsWithStatus; - - if (shipStatus !== 'Ready') { - setStatus(NodeBootPhase.BOOTING); - return; - } - - const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); - const shipUrl = getShipUrl(shipId); - const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); - if (!authCookie) { - throw new Error("Couldn't log you into your ship."); - } - - const ship = getShipFromCookie(authCookie); - configureApi(ship, shipUrl); - - setShip({ - ship, - shipUrl, - authCookie, - }); - - setStatus(NodeBootPhase.READY); - } catch (err) { - console.error('Error starting ship:', err); - if (err instanceof Error) { - trackError(err); - setError(err.message); - } - setStatus(NodeBootPhase.ERROR); - } - }, - [getLandscapeAuthCookie, hostingApi, setShip] - ); - - const reserveShip = useCallback( - async (skipShipId?: string) => { - setStatus(NodeBootPhase.RESERVING); - try { - const user = await hostingApi.getHostingUser(userId); - const shipIds = user.ships ?? []; - - if (shipIds.length === 0) { - const ships = await hostingApi.getReservableShips(userId); - const ship = ships.find( - ({ id, readyForDistribution }) => - id !== skipShipId && readyForDistribution - ); - if (!ship) { - throw new Error('No available ships found.'); - } - - const { reservedBy } = await hostingApi.reserveShip(userId, ship.id); - if (reservedBy !== userId) { - return reserveShip(ship.id); - } - - await hostingApi.allocateReservedShip(userId); - shipIds.push(ship.id); - trackOnboardingAction({ - actionName: 'Urbit ID Selected', - ship: ship.id, - }); - } - - await startShip(shipIds); - } catch (err) { - console.error('Error reserving ship:', err); - if (err instanceof Error) { - trackError(err); - setError(err.message); - } - setStatus(NodeBootPhase.ERROR); - } - }, - [userId, hostingApi, startShip] - ); - - const bootShip = useCallback(() => { - reserveShip(); - }, [reserveShip]); - - useEffect(() => { - if (status === NodeBootPhase.BOOTING) { - const timer = setInterval(() => { - reserveShip(); - }, 5000); - - return () => clearInterval(timer); - } - }, [status, reserveShip]); - - return { - status, - error, - bootShip, - }; -}; - -export function useSignupBootStatus() { - const signupContext = useSignupContext(); -} - -async function reserveShip( - hostingUserId: string, - skipShipIds: string[] = [] -): Promise { - try { - const user = await hostingApi.getHostingUser(hostingUserId); - const shipIds = user.ships ?? []; - - if (shipIds.length === 0) { - const ships = await hostingApi.getReservableShips(hostingUserId); - const ship = ships.find( - ({ id, readyForDistribution }) => - !skipShipIds.includes(id) && readyForDistribution - ); - if (!ship) { - throw new Error('No available ships found.'); - } - - const { reservedBy } = await hostingApi.reserveShip( - hostingUserId, - ship.id - ); - if (reservedBy !== hostingUserId) { - return reserveShip(hostingUserId, [ship.id]); - } - - await hostingApi.allocateReservedShip(hostingUserId); - shipIds.push(ship.id); - trackOnboardingAction({ - actionName: 'Urbit ID Selected', - ship: ship.id, - }); - } - - return true; - // await startShip(shipIds); - } catch (err) { - console.error('Error reserving ship:', err); - if (err instanceof Error) { - trackError(err); - // setError(err.message); - } - // setStatus(NodeBootPhase.ERROR); - return false; - } -} - -async function checkShipStatus(shipIds: string[]): Promise { - try { - const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); - if (!shipsWithStatus) { - return NodeBootPhase.BOOTING; - } - - const { status: shipStatus, shipId } = shipsWithStatus; - - if (shipStatus !== 'Ready') { - return NodeBootPhase.BOOTING; - } - - const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); - const shipUrl = getShipUrl(shipId); - const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); - if (!authCookie) { - throw new Error("Couldn't log you into your ship."); - } - - const ship = getShipFromCookie(authCookie); - configureApi(ship, shipUrl); - - // setShip({ - // ship, - // shipUrl, - // authCookie, - // }); - - // setStatus(NodeBootPhase.READY); - return NodeBootPhase.READY; - } catch (err) { - console.error('Error starting ship:', err); - if (err instanceof Error) { - trackError(err); - // setError(err.message); - } - // setStatus(NodeBootPhase.ERROR); - return NodeBootPhase.ERROR; - } -} - -async function getAuthenticationDetails( - nodeId: string -): Promise<{ nodeId: string; nodeUrl: string; authCookie: string }> { - const { code: accessCode } = await hostingApi.getShipAccessCode(nodeId); - const nodeUrl = getShipUrl(nodeId); - const authCookie = await getLandscapeAuthCookie(nodeUrl, accessCode); - if (!authCookie) { - throw new Error("Couldn't log you into your ship."); - } - - // TODO: shouldn't this be the same? - const ship = getShipFromCookie(authCookie); - - return { - nodeId, - nodeUrl, - authCookie, - }; -} From 575f12cf4a4957e4a45b01ff74a46a448941d882 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 01:33:41 -0400 Subject: [PATCH 038/259] allow override to send to staging posthog in dev --- apps/tlon-mobile/app.config.ts | 1 + packages/app/utils/posthog.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/app.config.ts b/apps/tlon-mobile/app.config.ts index 0c2b6eb1f2..5ab6d07cd8 100644 --- a/apps/tlon-mobile/app.config.ts +++ b/apps/tlon-mobile/app.config.ts @@ -20,6 +20,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ projectId, }, postHogApiKey: process.env.POST_HOG_API_KEY, + postHogInDev: process.env.POST_HOG_IN_DEV, notifyProvider: process.env.NOTIFY_PROVIDER, notifyService: process.env.NOTIFY_SERVICE, apiUrl: process.env.API_URL, diff --git a/packages/app/utils/posthog.ts b/packages/app/utils/posthog.ts index 81213d46b5..adee85053a 100644 --- a/packages/app/utils/posthog.ts +++ b/packages/app/utils/posthog.ts @@ -15,7 +15,7 @@ export type OnboardingProperties = { export let posthog: PostHog | undefined; export const posthogAsync = - process.env.NODE_ENV === 'test' + process.env.NODE_ENV === 'test' && !process.env.POST_HOG_IN_DEV ? undefined : PostHog.initAsync(POST_HOG_API_KEY, { host: 'https://eu.posthog.com', From 480501ee5aa682b14f3e12bc63b1b05f344a4b94 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 11:52:46 -0400 Subject: [PATCH 039/259] more cleanup, show friendly boot process messages --- .../src/components/AuthenticatedApp.tsx | 23 +- .../src/hooks/useDeepLinkListener.ts | 11 +- .../screens/Onboarding/ReserveShipScreen.tsx | 227 ++---------------- packages/app/lib/api.ts | 2 + packages/app/lib/bootHelpers.ts | 13 + 5 files changed, 39 insertions(+), 237 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index aac8e405bb..205244e873 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -30,23 +30,20 @@ function AuthenticatedApp({ }: AuthenticatedAppProps) { const { ship, shipUrl } = useShip(); const currentUserId = useCurrentUserId(); - const signupContext = useSignupContext(); const handlePostSignup = usePostSignup(); - const connectionStatus = store.useConnectionStatus(); useNotificationListener(notificationListenerProps); useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); useEffect(() => { - // TODO: i think we need a proper idle state? - // configureClient({ - // shipName: ship ?? '', - // shipUrl: shipUrl ?? '', - // onReset: () => sync.syncStart(), - // onChannelReset: () => sync.handleDiscontinuity(), - // onChannelStatusChange: sync.handleChannelStatusChange, - // }); + configureClient({ + shipName: ship ?? '', + shipUrl: shipUrl ?? '', + onReset: () => sync.syncStart(), + onChannelReset: () => sync.handleDiscontinuity(), + onChannelStatusChange: sync.handleChannelStatusChange, + }); initializeCrashReporter(crashlytics(), PlatformState); @@ -55,11 +52,7 @@ function AuthenticatedApp({ store.setErrorTrackingUserId(currentUserId); } - // if (signupContext.didSignup) { - // handlePostSignup(); - // } - - // sync.syncStart(); + sync.syncStart(); }, [currentUserId, handlePostSignup, ship, shipUrl]); const handleAppStatusChange = useCallback((status: AppStateStatus) => { diff --git a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts index e6bbed2c5c..3bb798bcae 100644 --- a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts +++ b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts @@ -26,16 +26,7 @@ export const useDeepLinkListener = () => { try { // if the lure was clicked prior to authenticating, trigger the automatic join & DM if (lure.shouldAutoJoin) { - // WE DONT ACTUALLY HAVE TO DO ANYTHING HERE — hosting handles - // try { - // logger.log(`inviting ship with lure`, ship, signupParams.lureId); - // await inviteShipWithLure({ ship, lure: signupParams.lureId }); - // } catch (err) { - // logger.error('Error inviting ship with lure:', err); - // if (err instanceof Error) { - // trackError(err); - // } - // } + // no-op for now, hosting will handle } else { // otherwise, treat it as a deeplink and navigate to the group if (lure.invitedGroupId) { diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index cd543533db..7ce4e50558 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -1,211 +1,26 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; -import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; -import { trackError, trackOnboardingAction } from '@tloncorp/app/utils/posthog'; -import { getShipFromCookie, getShipUrl } from '@tloncorp/app/utils/ship'; -import { configureApi } from '@tloncorp/shared/dist/api'; +import { BootPhaseExplanations } from '@tloncorp/app/lib/bootHelpers'; import { Spinner, Text, View, YStack } from '@tloncorp/ui'; -import { useCallback, useEffect, useState } from 'react'; -import { Alert } from 'react-native'; +import { useEffect } from 'react'; -import { useOnboardingContext } from '../../lib/OnboardingContext'; import type { OnboardingStackParamList } from '../../types'; type Props = NativeStackScreenProps; -export const ReserveShipScreen = ({ - navigation, - route: { - params: { user }, - }, -}: Props) => { - const [{ state, error }, setState] = useState<{ - state: 'loading' | 'booting' | 'error'; - error?: string; - }>({ - state: 'loading', - }); - +export const ReserveShipScreen = ({ navigation }: Props) => { const signupContext = useSignupContext(); - // const { hostingApi, getLandscapeAuthCookie } = useOnboardingContext(); - // const signupContext = useSignupContext(); - // const { setShip } = useShip(); - - // const startShip = useCallback( - // async (shipIds: string[]) => { - // // Fetch statuses for the user's ships and start any required booting/resuming - // const shipsWithStatus = await hostingApi.getShipsWithStatus(shipIds); - // console.log('shipsWithStatus', shipsWithStatus); - // if (!shipsWithStatus) { - // // you can only have gotten to this screen if a new hosting account was created and ship - // // was reserved. If we don't see the ship status, assume it's still booting - // return setState({ state: 'booting' }); - // } - - // const { status, shipId } = shipsWithStatus; - - // // If user is in the sign up flow, send them to fill out some extra details - // if ( - // signupContext.nickname === undefined && - // signupContext.telemetry === undefined - // ) { - // return navigation.navigate('SetNickname', { - // user: await hostingApi.getHostingUser(user.id), - // }); - // } - - // // If it's not ready, show the booting message - // if (status !== 'Ready') { - // return setState({ state: 'booting' }); - // } - - // // If it's ready, fetch the access code and auth cookie - // const { code: accessCode } = await hostingApi.getShipAccessCode(shipId); - // const shipUrl = getShipUrl(shipId); - // const authCookie = await getLandscapeAuthCookie(shipUrl, accessCode); - // if (!authCookie) { - // return setState({ - // state: 'error', - // error: "Sorry, we couldn't log you into your ship.", - // }); - // } - - // const ship = getShipFromCookie(authCookie); - // configureApi(ship, shipUrl); - - // // Set the ship info in the main context to navigate to chat view - // setShip({ - // ship, - // shipUrl, - // authCookie, - // }); - // }, - // [ - // getLandscapeAuthCookie, - // hostingApi, - // navigation, - // setShip, - // signupContext.nickname, - // signupContext.telemetry, - // user.id, - // ] - // ); - - // const reserveShip = useCallback( - // async (skipShipId?: string) => { - // const shipIds = user.ships ?? []; - - // // User doesn't have any ships assigned to them yet - // if (shipIds.length === 0) { - // try { - // // Get list of reservable ships and choose one that's ready for distribution - // const ships = await hostingApi.getReservableShips(user.id); - // const ship = ships.find( - // ({ id, readyForDistribution }) => - // id !== skipShipId && readyForDistribution - // ); - // if (!ship) { - // return setState({ - // state: 'error', - // error: - // 'Sorry, we could no longer find a ship for you. Please try again later.', - // }); - // } - - // // Reserve this ship and check it was successful - // const { reservedBy } = await hostingApi.reserveShip(user.id, ship.id); - // console.log('reserved', user, reservedBy); - // if (reservedBy !== user.id) { - // return reserveShip(ship.id); - // } - - // // Finish allocating this ship to the user - // await hostingApi.allocateReservedShip(user.id); - // shipIds.push(ship.id); - // trackOnboardingAction({ - // actionName: 'Urbit ID Selected', - // ship: ship.id, - // }); - // } catch (err) { - // console.error('Error reserving ship:', err); - // if (err instanceof Error) { - // trackError(err); - // } - - // return setState({ - // state: 'error', - // error: - // 'We were not able to reserve your ship. Please try again later.', - // }); - // } - // } - - // // Start the ship - // try { - // await startShip(shipIds); - // } catch (err) { - // console.error('Error starting ship:', err); - // if (err instanceof Error) { - // trackError(err); - // } - - // return setState({ - // state: 'error', - // error: "Sorry, we couldn't boot your ship. Please try again later.", - // }); - // } - // }, - // [user] - // ); - - // useEffect(() => { - // reserveShip(); - // }, [reserveShip]); - - // useEffect(() => { - // let timer: NodeJS.Timeout; - - // if (state === 'booting') { - // timer = setInterval(reserveShip, 5_000); - // } - - // return () => { - // if (timer) { - // clearInterval(timer); - // } - // }; - // }, [state]); - - // useEffect(() => { - // if (error) { - // Alert.alert('An error occurred', error, [ - // { - // text: 'OK', - // onPress: () => navigation.popToTop(), - // style: 'cancel', - // }, - // ]); - // } - // }, [error, navigation]); - - // Disable back button if no error occurred + // Disable back button once you reach this screen useEffect( () => navigation.addListener('beforeRemove', (e) => { - if (!error) { - e.preventDefault(); - } + e.preventDefault(); }), - [navigation, error] + [navigation] ); useEffect(() => { - // if (signupContext.bootPhase === NodeBootPhase.IDLE) { - // signupContext.initializeBootSequence(); - // } - if (!signupContext.didCompleteSignup) { signupContext.setDidCompleteSignup(true); } @@ -213,27 +28,15 @@ export const ReserveShipScreen = ({ return ( - {state === 'loading' ? ( - - - - Getting your ship ready... - - - {signupContext.bootPhase} - - - ) : state === 'booting' ? ( - - - - Booting your ship... - - - {signupContext.bootPhase} - - - ) : null} + + + + Setting up your new p2p node + + + {BootPhaseExplanations[signupContext.bootPhase]} + + ); }; diff --git a/packages/app/lib/api.ts b/packages/app/lib/api.ts index f6a79a3667..d3b074a162 100644 --- a/packages/app/lib/api.ts +++ b/packages/app/lib/api.ts @@ -78,5 +78,7 @@ export function configureClient({ verbose, }); updateInitializedClient(true); + } else { + console.log(`skippingn client configuration, already initialized`); } } diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts index df1d06ec85..4c0dfa47f7 100644 --- a/packages/app/lib/bootHelpers.ts +++ b/packages/app/lib/bootHelpers.ts @@ -18,6 +18,19 @@ export enum NodeBootPhase { ERROR = 'error', } +export const BootPhaseExplanations: Record = { + [NodeBootPhase.IDLE]: 'Waiting to start', + [NodeBootPhase.RESERVING]: 'Reserving your p2p node', + [NodeBootPhase.BOOTING]: 'Booting your p2p node', + [NodeBootPhase.AUTHENTICATING]: 'Authenticating with your node', + [NodeBootPhase.CONNECTING]: 'Establishing a connection to your node', + [NodeBootPhase.CHECKING_FOR_INVITE]: 'Confirming your invites were received', + [NodeBootPhase.ACCEPTING_INVITES]: + 'Initializing the conversations you were invited to', + [NodeBootPhase.READY]: 'Your node is ready', + [NodeBootPhase.ERROR]: 'Your node errored while initializing', +}; + export default { NodeBootPhase, reserveNode, From a8d92e99661add2a3ffabb5a402bbb09d09a4167 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 12:28:21 -0400 Subject: [PATCH 040/259] remove unused post-signup hook --- .../src/components/AuthenticatedApp.tsx | 5 +-- packages/app/hooks/usePostSignup.ts | 45 ------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 packages/app/hooks/usePostSignup.ts diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 205244e873..236a3eda81 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -1,11 +1,9 @@ import crashlytics from '@react-native-firebase/crashlytics'; import { useShip } from '@tloncorp/app/contexts/ship'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; -import { usePostSignup } from '@tloncorp/app/hooks/usePostSignup'; import { cancelFetch, configureClient } from '@tloncorp/app/lib/api'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; @@ -30,7 +28,6 @@ function AuthenticatedApp({ }: AuthenticatedAppProps) { const { ship, shipUrl } = useShip(); const currentUserId = useCurrentUserId(); - const handlePostSignup = usePostSignup(); useNotificationListener(notificationListenerProps); useDeepLinkListener(); useNavigationLogging(); @@ -53,7 +50,7 @@ function AuthenticatedApp({ } sync.syncStart(); - }, [currentUserId, handlePostSignup, ship, shipUrl]); + }, [currentUserId, ship, shipUrl]); const handleAppStatusChange = useCallback((status: AppStateStatus) => { if (status === 'active') { diff --git a/packages/app/hooks/usePostSignup.ts b/packages/app/hooks/usePostSignup.ts deleted file mode 100644 index 87778ea6e1..0000000000 --- a/packages/app/hooks/usePostSignup.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createDevLogger } from '@tloncorp/shared/dist'; -import { updateTelemetrySetting } from '@tloncorp/shared/dist/api'; -import * as store from '@tloncorp/shared/dist/store'; -import { useCallback } from 'react'; - -import { useSignupContext } from '../contexts/signup'; -import { connectNotifyProvider } from '../lib/notificationsApi'; - -const logger = createDevLogger('postSignup', true); - -export function usePostSignup() { - const signupContext = useSignupContext(); - - const handlePostSignup = useCallback(async () => { - if (signupContext.nickname) { - try { - await store.updateCurrentUserProfile({ - nickname: signupContext.nickname, - }); - } catch (e) { - logger.error('Failed to set nickname', e); - } - } - - if (typeof signupContext.telemetry !== 'undefined') { - try { - await updateTelemetrySetting(signupContext.telemetry); - } catch (e) { - logger.error('Failed to set telemetry', e); - } - } - - if (signupContext.notificationToken) { - try { - await connectNotifyProvider(signupContext.notificationToken); - } catch (e) { - logger.error('Failed to connect notify provider', e); - } - } - - signupContext.clear(); - }, [signupContext]); - - return handlePostSignup; -} From 5e5f993f889c5f36ffc8240829e0856325757447 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 11 Oct 2024 11:30:04 -0500 Subject: [PATCH 041/259] session: revert syncing move --- packages/shared/src/store/session.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/store/session.ts b/packages/shared/src/store/session.ts index e946f4fad1..2f92282739 100644 --- a/packages/shared/src/store/session.ts +++ b/packages/shared/src/store/session.ts @@ -65,9 +65,6 @@ export function useSyncing() { export function useConnectionStatus() { const currentSession = useCurrentSession(); const syncing = useSyncing(); - if (syncing) { - return 'Syncing'; - } if (!currentSession) { return 'Connecting'; @@ -77,5 +74,9 @@ export function useConnectionStatus() { return 'Reconnecting'; } + if (syncing) { + return 'Syncing'; + } + return 'Connected'; } From 04319a351c187c8bd9a14c64ddcd4fb6f6c00b76 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 11 Oct 2024 13:32:26 -0500 Subject: [PATCH 042/259] notebooks: fix title focus and toolbar issues --- .../ui/src/components/BigInput.native.tsx | 1 - .../MessageInput/MessageInputBase.tsx | 1 - .../components/MessageInput/index.native.tsx | 44 +++++++------------ 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/packages/ui/src/components/BigInput.native.tsx b/packages/ui/src/components/BigInput.native.tsx index 03f082e709..c285f0660a 100644 --- a/packages/ui/src/components/BigInput.native.tsx +++ b/packages/ui/src/components/BigInput.native.tsx @@ -38,7 +38,6 @@ export function BigInput({ const [showAttachmentSheet, setShowAttachmentSheet] = useState(false); const editorRef = useRef<{ editor: TlonEditorBridge | null; - setEditor: (editor: EditorBridge) => void; }>(null); const { top } = useSafeAreaInsets(); const { width } = Dimensions.get('screen'); diff --git a/packages/ui/src/components/MessageInput/MessageInputBase.tsx b/packages/ui/src/components/MessageInput/MessageInputBase.tsx index 5c7a7d7188..0a8691c188 100644 --- a/packages/ui/src/components/MessageInput/MessageInputBase.tsx +++ b/packages/ui/src/components/MessageInput/MessageInputBase.tsx @@ -58,7 +58,6 @@ export interface MessageInputProps { shouldAutoFocus?: boolean; ref?: React.RefObject<{ editor: EditorBridge | null; - setEditor: (editor: EditorBridge) => void; }>; } diff --git a/packages/ui/src/components/MessageInput/index.native.tsx b/packages/ui/src/components/MessageInput/index.native.tsx index 58a3c2b7ad..2d1a049c33 100644 --- a/packages/ui/src/components/MessageInput/index.native.tsx +++ b/packages/ui/src/components/MessageInput/index.native.tsx @@ -107,7 +107,6 @@ export const DEFAULT_MESSAGE_INPUT_HEIGHT = 44; export interface MessageInputHandle { editor: EditorBridge | null; - setEditor: (editor: EditorBridge) => void; } export const MessageInput = forwardRef( @@ -144,19 +143,11 @@ export const MessageInput = forwardRef( }, ref ) => { - const localEditorRef = useRef(null); - - useImperativeHandle(ref, () => ({ - editor: localEditorRef.current, - setEditor: (editor: EditorBridge) => { - localEditorRef.current = editor; - }, - })); - const branchDomain = useBranchDomain(); const branchKey = useBranchKey(); const [isSending, setIsSending] = useState(false); const [hasSetInitialContent, setHasSetInitialContent] = useState(false); + const [hasAutoFocused, setHasAutoFocused] = useState(false); const [editorCrashed, setEditorCrashed] = useState(); const [containerHeight, setContainerHeight] = useState(initialHeight); const { bottom, top } = useSafeAreaInsets(); @@ -217,6 +208,10 @@ export const MessageInput = forwardRef( const editorState = useBridgeState(editor); const webviewRef = editor.webviewRef; + useImperativeHandle(ref, () => ({ + editor, + })); + const reloadWebview = useCallback( (reason: string) => { webviewRef.current?.reload(); @@ -226,16 +221,6 @@ export const MessageInput = forwardRef( [webviewRef] ); - useEffect(() => { - if (editor) { - localEditorRef.current = editor; - } - - if (ref && typeof ref === 'object' && ref.current) { - ref.current.setEditor(editor); - } - }, [editor, ref]); - const lastEditingPost = useRef(editingPost); useEffect(() => { @@ -353,21 +338,29 @@ export const MessageInput = forwardRef( }, [editingPost]); useEffect(() => { - if (editor && !shouldBlur && shouldAutoFocus && !editorState.isFocused) { + if ( + editor && + editorState.isReady && + !shouldBlur && + shouldAutoFocus && + !editorState.isFocused && + !hasAutoFocused + ) { editor.focus(); + messageInputLogger.log('Auto focused editor'); + setHasAutoFocused(true); } - }, [shouldAutoFocus, editor, editorState, shouldBlur]); + }, [shouldAutoFocus, editor, editorState, shouldBlur, hasAutoFocused]); useEffect(() => { if (editor && shouldBlur && editorState.isFocused) { editor.blur(); + messageInputLogger.log('Blurred editor'); setShouldBlur(false); } }, [shouldBlur, editor, editorState, setShouldBlur]); useEffect(() => { - messageInputLogger.log('Checking if editor is empty'); - editor.getJSON().then((json: JSONContent) => { const inlines = tiptap .JSONToInlines(json) @@ -392,10 +385,7 @@ export const MessageInput = forwardRef( blocks.length === 0 && attachments.length === 0; - messageInputLogger.log('Editor is empty?', isEmpty); - if (isEmpty !== editorIsEmpty) { - messageInputLogger.log('Setting editorIsEmpty', isEmpty); setEditorIsEmpty(isEmpty); setContainerHeight(initialHeight); } From bbd631d5f8941634db580209cae97da898c5f504 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 18:08:36 -0400 Subject: [PATCH 043/259] streamline urbit client hook, fix client instantiation in boot sequence --- .../src/components/AuthenticatedApp.tsx | 36 +------ packages/app/hooks/useBootSequence.ts | 18 ++-- packages/app/hooks/useConfigureUrbitClient.ts | 97 +++++++++++++------ packages/app/lib/api.ts | 1 + 4 files changed, 81 insertions(+), 71 deletions(-) diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 147baaf69a..90d261f7fb 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -64,41 +64,7 @@ function AuthenticatedApp({ >(); useEffect(() => { - configureClient({ - shipName: ship ?? '', - shipUrl: shipUrl ?? '', - getCode: - authType === 'self' - ? undefined - : async () => { - appLogger.log('Getting ship access code', { - ship, - authType, - }); - trackError({ - message: - 'Hosted ship logged out of urbit, getting ship access code', - }); - if (!ship) { - throw new Error('Trying to retrieve +code, no ship set'); - } - - const { code } = await getShipAccessCode(ship); - return code; - }, - handleAuthFailure: async () => { - trackError({ - message: 'Failed to authenticate with ship, redirecting to login', - }); - await logout(); - if (authType === 'self') { - navigation.navigate('ShipLogin'); - return; - } - - navigation.navigate('TlonLogin'); - }, - }); + configureClient(); initializeCrashReporter(crashlytics(), PlatformState); diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index e7ef995faf..e54b9ba7af 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -8,6 +8,7 @@ import { configureClient } from '../lib/api'; import { NodeBootPhase } from '../lib/bootHelpers'; import BootHelpers from '../lib/bootHelpers'; import { getShipFromCookie } from '../utils/ship'; +import { useConfigureUrbitClient } from './useConfigureUrbitClient'; const HANDLE_INVITES_TIMEOUT = 1000 * 30; @@ -40,6 +41,7 @@ export function useBootSequence({ const { setShip } = useShip(); const connectionStatus = store.useConnectionStatus(); const lureMeta = useLureMetadata(); + const configureUrbitClient = useConfigureUrbitClient(); const [bootPhase, setBootPhase] = useState(NodeBootPhase.IDLE); const [reservedNodeId, setReservedNodeId] = useState(null); @@ -106,15 +108,17 @@ export function useBootSequence({ ship, shipUrl: auth.nodeUrl, authCookie: auth.authCookie, + authType: 'hosted', }); - configureClient({ - shipName: auth.nodeId, - shipUrl: auth.nodeUrl, - onReset: () => store.syncStart(), - onChannelReset: () => store.handleDiscontinuity(), - onChannelStatusChange: store.handleChannelStatusChange, - }); + // configureClient({ + // shipName: auth.nodeId, + // shipUrl: auth.nodeUrl, + // onReset: () => store.syncStart(), + // onChannelReset: () => store.handleDiscontinuity(), + // onChannelStatusChange: store.handleChannelStatusChange, + // }); + configureUrbitClient(); store.syncStart(); logger.crumb(`authenticated with node`); diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 9082736219..8493f70664 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -1,38 +1,77 @@ -import { getSession, sync, updateSession } from '@tloncorp/shared/dist'; -import { ClientParams } from '@tloncorp/shared/dist/api'; +import { + createDevLogger, + getSession, + sync, + updateSession, +} from '@tloncorp/shared/dist'; import { useCallback } from 'react'; import { ENABLED_LOGGERS } from '../constants'; +import { useShip } from '../contexts/ship'; import { configureClient } from '../lib/api'; +import { getShipAccessCode } from '../lib/hostingApi'; +import { resetDb } from '../lib/nativeDb'; +import { useHandleLogout } from './useHandleLogout'; -type PickPartial = Pick & Partial>; +const appLogger = createDevLogger('configure client', false); export function useConfigureUrbitClient() { - return useCallback( - (params: PickPartial) => { - configureClient({ - verbose: ENABLED_LOGGERS.includes('urbit'), - onReconnect: () => { - const threshold = 5 * 60 * 1000; // 5 minutes - const lastReconnect = getSession()?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } else { - updateSession({ startTime: Date.now() }); - } - }, - onChannelReset: () => { - const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours - const lastReconnect = getSession()?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } - }, - onChannelStatusChange: sync.handleChannelStatusChange, - // override any defaults with params - ...params, - }); + const shipInfo = useShip(); + const { ship, shipUrl, authType } = shipInfo; + const logout = useHandleLogout({ + resetDb: () => { + appLogger.log('Resetting db on logout'); + resetDb(); }, - [] - ); + }); + + return useCallback(() => { + configureClient({ + shipName: ship ?? '', + shipUrl: shipUrl ?? '', + verbose: ENABLED_LOGGERS.includes('urbit'), + onReconnect: () => { + const threshold = 5 * 60 * 1000; // 5 minutes + const lastReconnect = getSession()?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } else { + updateSession({ startTime: Date.now() }); + } + }, + onChannelReset: () => { + const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours + const lastReconnect = getSession()?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } + }, + onChannelStatusChange: sync.handleChannelStatusChange, + getCode: + authType === 'self' + ? undefined + : async () => { + appLogger.log('Getting ship access code', { + ship, + authType, + }); + appLogger.trackError( + 'Hosted ship logged out of urbit, getting ship access code' + ); + if (!ship) { + throw new Error('Trying to retrieve +code, no ship set'); + } + + const { code } = await getShipAccessCode(ship); + return code; + }, + handleAuthFailure: async () => { + appLogger.trackError( + 'Failed to authenticate with ship, redirecting to login' + ); + await logout(); + // TODO: route them to hosted sign in vs log in? + }, + }); + }, [authType, logout, ship, shipUrl]); } diff --git a/packages/app/lib/api.ts b/packages/app/lib/api.ts index bb1ba45f69..0a95b48571 100644 --- a/packages/app/lib/api.ts +++ b/packages/app/lib/api.ts @@ -52,6 +52,7 @@ export const cancelFetch = () => { abortController = new AbortController(); }; +// TODO: can this just get moved into the hook? export function configureClient(params: Omit) { const clientInitialized = getInitializedClient(); if (!clientInitialized) { From c7aa28d3973d5f5db7a4ce0aa4bcd02fd69b435f Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 11 Oct 2024 18:39:19 -0400 Subject: [PATCH 044/259] fix merge issues --- apps/tlon-mobile/src/App.main.tsx | 5 + .../src/components/AuthenticatedApp.tsx | 2 - packages/app/hooks/useBootSequence.ts | 2 +- packages/app/hooks/useConfigureUrbitClient.ts | 100 +++++++++--------- 4 files changed, 58 insertions(+), 51 deletions(-) diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 1b98221403..99f74c05eb 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -2,6 +2,7 @@ import { useAsyncStorageDevTools } from '@dev-plugins/async-storage'; import { useReactNavigationDevTools } from '@dev-plugins/react-navigation'; import { useReactQueryDevTools } from '@dev-plugins/react-query'; import NetInfo from '@react-native-community/netinfo'; +import crashlytics from '@react-native-firebase/crashlytics'; import { DarkTheme, DefaultTheme, @@ -18,9 +19,11 @@ import { } from '@tloncorp/app/contexts/signup'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; import { useMigrations } from '@tloncorp/app/lib/nativeDb'; +import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { FeatureFlagConnectedInstrumentationProvider } from '@tloncorp/app/utils/perf'; import { posthogAsync } from '@tloncorp/app/utils/posthog'; +import { initializeCrashReporter } from '@tloncorp/shared/dist'; import { QueryClientProvider, queryClient } from '@tloncorp/shared/dist/api'; import { LoadingSpinner, @@ -39,6 +42,8 @@ import { SafeAreaProvider } from 'react-native-safe-area-context'; import { OnboardingStack } from './OnboardingStack'; import AuthenticatedApp from './components/AuthenticatedApp'; +initializeCrashReporter(crashlytics(), PlatformState); + type Props = { wer?: string; channelId?: string; diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 90d261f7fb..a176657fe9 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -66,8 +66,6 @@ function AuthenticatedApp({ useEffect(() => { configureClient(); - initializeCrashReporter(crashlytics(), PlatformState); - // TODO: remove, for use in Beta testing only if (currentUserId) { store.setErrorTrackingUserId(currentUserId); diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index e54b9ba7af..6c200112f7 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -118,7 +118,7 @@ export function useBootSequence({ // onChannelReset: () => store.handleDiscontinuity(), // onChannelStatusChange: store.handleChannelStatusChange, // }); - configureUrbitClient(); + configureUrbitClient({ shipName: auth.nodeId, shipUrl: auth.nodeUrl }); store.syncStart(); logger.crumb(`authenticated with node`); diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 8493f70664..b66430e136 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -4,6 +4,7 @@ import { sync, updateSession, } from '@tloncorp/shared/dist'; +import { ClientParams } from '@tloncorp/shared/dist/api'; import { useCallback } from 'react'; import { ENABLED_LOGGERS } from '../constants'; @@ -25,53 +26,56 @@ export function useConfigureUrbitClient() { }, }); - return useCallback(() => { - configureClient({ - shipName: ship ?? '', - shipUrl: shipUrl ?? '', - verbose: ENABLED_LOGGERS.includes('urbit'), - onReconnect: () => { - const threshold = 5 * 60 * 1000; // 5 minutes - const lastReconnect = getSession()?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } else { - updateSession({ startTime: Date.now() }); - } - }, - onChannelReset: () => { - const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours - const lastReconnect = getSession()?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } - }, - onChannelStatusChange: sync.handleChannelStatusChange, - getCode: - authType === 'self' - ? undefined - : async () => { - appLogger.log('Getting ship access code', { - ship, - authType, - }); - appLogger.trackError( - 'Hosted ship logged out of urbit, getting ship access code' - ); - if (!ship) { - throw new Error('Trying to retrieve +code, no ship set'); - } + return useCallback( + (params?: Partial) => { + configureClient({ + shipName: params?.shipName ?? ship ?? '', + shipUrl: params?.shipUrl ?? shipUrl ?? '', + verbose: ENABLED_LOGGERS.includes('urbit'), + onReconnect: () => { + const threshold = 5 * 60 * 1000; // 5 minutes + const lastReconnect = getSession()?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } else { + updateSession({ startTime: Date.now() }); + } + }, + onChannelReset: () => { + const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours + const lastReconnect = getSession()?.startTime ?? 0; + if (Date.now() - lastReconnect >= threshold) { + sync.handleDiscontinuity(); + } + }, + onChannelStatusChange: sync.handleChannelStatusChange, + getCode: + authType === 'self' + ? undefined + : async () => { + appLogger.log('Getting ship access code', { + ship, + authType, + }); + appLogger.trackError( + 'Hosted ship logged out of urbit, getting ship access code' + ); + if (!ship) { + throw new Error('Trying to retrieve +code, no ship set'); + } - const { code } = await getShipAccessCode(ship); - return code; - }, - handleAuthFailure: async () => { - appLogger.trackError( - 'Failed to authenticate with ship, redirecting to login' - ); - await logout(); - // TODO: route them to hosted sign in vs log in? - }, - }); - }, [authType, logout, ship, shipUrl]); + const { code } = await getShipAccessCode(ship); + return code; + }, + handleAuthFailure: async () => { + appLogger.trackError( + 'Failed to authenticate with ship, redirecting to login' + ); + await logout(); + // TODO: route them to hosted sign in vs log in? + }, + }); + }, + [authType, logout, ship, shipUrl] + ); } From 4ba931b2b125c4b2242fd8bbc6d680cbecc83298 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 14 Oct 2024 09:35:31 -0700 Subject: [PATCH 045/259] Remove unused props --- apps/tlon-mobile/src/App.main.tsx | 21 ++++--------------- .../src/components/AuthenticatedApp.tsx | 20 +++++------------- .../src/hooks/useNotificationListener.ts | 10 +-------- 3 files changed, 10 insertions(+), 41 deletions(-) diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index a8fe41e7ae..3955edb749 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -36,16 +36,8 @@ import { SafeAreaProvider } from 'react-native-safe-area-context'; import { OnboardingStack } from './OnboardingStack'; import AuthenticatedApp from './components/AuthenticatedApp'; -type Props = { - wer?: string; - channelId?: string; -}; - // Android notification tap handler passes initial params here -const App = ({ - wer: notificationPath, - channelId: notificationChannelId, -}: Props) => { +const App = () => { const isDarkMode = useIsDarkMode(); const { isLoading, isAuthenticated } = useShip(); @@ -74,12 +66,7 @@ const App = ({ ) : isAuthenticated ? ( - + ) : ( ) @@ -114,7 +101,7 @@ function MigrationCheck({ children }: PropsWithChildren) { return <>{children}; } -export default function ConnectedApp(props: Props) { +export default function ConnectedApp() { const isDarkMode = useIsDarkMode(); const navigationContainerRef = useNavigationContainerRef(); @@ -141,7 +128,7 @@ export default function ConnectedApp(props: Props) { - + {__DEV__ && ( diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index a31c3b2746..ceb22c1289 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -17,22 +17,14 @@ import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; import { useDeepLinkListener } from '../hooks/useDeepLinkListener'; -import useNotificationListener, { - type Props as NotificationListenerProps, -} from '../hooks/useNotificationListener'; +import useNotificationListener from '../hooks/useNotificationListener'; -export interface AuthenticatedAppProps { - notificationListenerProps: NotificationListenerProps; -} - -function AuthenticatedApp({ - notificationListenerProps, -}: AuthenticatedAppProps) { +function AuthenticatedApp() { const { ship, shipUrl } = useShip(); const currentUserId = useCurrentUserId(); const signupContext = useSignupContext(); const handlePostSignup = usePostSignup(); - useNotificationListener(notificationListenerProps); + useNotificationListener(); useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); @@ -78,12 +70,10 @@ function AuthenticatedApp({ ); } -export default function ConnectedAuthenticatedApp( - props: AuthenticatedAppProps -) { +export default function ConnectedAuthenticatedApp() { return ( - + ); } diff --git a/apps/tlon-mobile/src/hooks/useNotificationListener.ts b/apps/tlon-mobile/src/hooks/useNotificationListener.ts index 0507c7b637..45bcce56b8 100644 --- a/apps/tlon-mobile/src/hooks/useNotificationListener.ts +++ b/apps/tlon-mobile/src/hooks/useNotificationListener.ts @@ -38,11 +38,6 @@ interface UnrecognizedNotificationData extends BaseNotificationData { type NotificationData = WerNotificationData | UnrecognizedNotificationData; -export type Props = { - notificationPath?: string; - notificationChannelId?: string; -}; - function payloadFromNotification( notification: Notification ): NotificationData | null { @@ -80,10 +75,7 @@ function payloadFromNotification( }; } -export default function useNotificationListener({ - notificationPath, - notificationChannelId, -}: Props) { +export default function useNotificationListener() { const navigation = useNavigation>(); const { data: isTlonEmployee } = store.useIsTlonEmployee(); const [channelSwitcherEnabled] = useFeatureFlag('channelSwitcher'); From e002d119d5b3133d66d18917204ca2f1597df261 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 05:48:45 -0500 Subject: [PATCH 046/259] notebook/gallery: scroll to bottom of detail view when reply input is focused --- packages/ui/src/components/DetailView.tsx | 12 +++++++++++- packages/ui/src/components/PostScreenView.tsx | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/DetailView.tsx b/packages/ui/src/components/DetailView.tsx index 4e52e2c7fc..c7d0707f29 100644 --- a/packages/ui/src/components/DetailView.tsx +++ b/packages/ui/src/components/DetailView.tsx @@ -1,6 +1,6 @@ import * as db from '@tloncorp/shared/dist/db'; import * as urbit from '@tloncorp/shared/dist/urbit'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useRef } from 'react'; import { FlatList } from 'react-native'; import { View, YStack } from 'tamagui'; @@ -24,6 +24,7 @@ export interface DetailViewProps { setActiveMessage: (post: db.Post | null) => void; activeMessage: db.Post | null; headerMode: 'default' | 'next'; + editorIsFocused: boolean; } export const DetailView = ({ @@ -38,6 +39,7 @@ export const DetailView = ({ setActiveMessage, activeMessage, headerMode, + editorIsFocused, }: DetailViewProps) => { const channelType = useMemo( () => urbit.getChannelType(post.channelId), @@ -47,6 +49,13 @@ export const DetailView = ({ const resolvedPosts = useMemo(() => { return isChat && posts ? [...posts, post] : posts; }, [posts, post, isChat]); + const flatListRef = useRef(null); + + useEffect(() => { + if (editorIsFocused) { + flatListRef.current?.scrollToIndex({ index: 1, animated: true }); + } + }, [editorIsFocused]); const scroller = useMemo(() => { return ( @@ -97,6 +106,7 @@ export const DetailView = ({ ) : ( { if (item === 'header') { return ( diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index e3f5440e1f..3acfe43636 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -3,7 +3,7 @@ import type * as db from '@tloncorp/shared/dist/db'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { Story } from '@tloncorp/shared/dist/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Text, View, YStack } from 'tamagui'; @@ -16,6 +16,7 @@ import { ChannelHeader } from './Channel/ChannelHeader'; import { DetailView } from './DetailView'; import KeyboardAvoidingView from './KeyboardAvoidingView'; import { MessageInput } from './MessageInput'; +import { TlonEditorBridge } from './MessageInput/toolbarActions.native'; export function PostScreenView({ channel, @@ -81,6 +82,16 @@ export function PostScreenView({ () => posts?.filter((p) => p.id !== parentPost?.id) ?? [], [posts, parentPost] ); + const editorRef = useRef<{ + editor: TlonEditorBridge | null; + }>(null); + const [editorIsFocused, setEditorIsFocused] = useState(false); + + // We track the editor focus state to determine when we need to scroll to the + // bottom of the screen when the keyboard is opened/editor is focused. + editorRef.current?.editor?._subscribeToEditorStateUpdate((editorState) => { + setEditorIsFocused(editorState.isFocused); + }); const { bottom } = useSafeAreaInsets(); @@ -131,6 +142,7 @@ export function PostScreenView({ activeMessage={activeMessage} setActiveMessage={setActiveMessage} headerMode={headerMode} + editorIsFocused={editorIsFocused} /> ) : null} @@ -153,6 +165,7 @@ export function PostScreenView({ (channel.type === 'chat' && parentPost?.replyCount === 0) || !!editingPost } + ref={editorRef} /> )} {!negotiationMatch && channel && canWrite && ( From cd8344a7c2e3b601f3c63b19880acae617c8e708 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 10:40:39 -0500 Subject: [PATCH 047/259] gallery: insert old image link posts as image posts in local db --- packages/shared/src/api/postsApi.ts | 44 +++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/packages/shared/src/api/postsApi.ts b/packages/shared/src/api/postsApi.ts index 82894710fe..3b01680221 100644 --- a/packages/shared/src/api/postsApi.ts +++ b/packages/shared/src/api/postsApi.ts @@ -3,6 +3,7 @@ import { Poke } from '@urbit/http-api'; import * as db from '../db'; import { createDevLogger } from '../debug'; +import { IMAGE_URL_REGEX } from '../logic'; import * as ub from '../urbit'; import { ClubAction, @@ -824,16 +825,12 @@ export function toPostData( channelId: string, post: ub.Post | ub.Writ | ub.PostDataResponse ): db.Post { - const getPostType = ( - channelId: string, - post: ub.Post | ub.PostDataResponse - ) => { + const channelType = channelId.split('/')[0]; + const getPostType = (post: ub.Post | ub.PostDataResponse) => { if (isNotice(post)) { return 'notice'; } - const channelType = channelId.split('/')[0]; - if (channelType === 'chat') { return 'chat'; } else if (channelType === 'diary') { @@ -844,7 +841,7 @@ export function toPostData( return 'chat'; } }; - const type = getPostType(channelId, post); + const type = getPostType(post); const kindData = post?.essay['kind-data']; const [content, flags] = toPostContent(post?.essay.content); const metadata = parseKindData(kindData); @@ -858,6 +855,35 @@ export function toPostData( ? getReplyData(id, channelId, post) : null; + // This is used for backwards compatibility with older gallery posts from + // the old web frontend, where a user could just link an image that would be + // rendered as a an image post in a gallery. This is not a feature that is + // supported by the current frontend, but we still need to be able to render + // these posts correctly. + const galleryImageLink = + channelType === 'heap' && + content && + content.length === 1 && + 'inline' in content[0] && + content[0].inline.length === 1 && + typeof content[0].inline[0] === 'object' && + 'link' in content[0].inline[0] && + content[0].inline[0].link.href.match(IMAGE_URL_REGEX) + ? content[0].inline[0].link.href + : null; + + const galleryImageLinkContent: ub.Verse[] = [ + { + block: { + // @ts-expect-error - we don't know image size + image: { + src: galleryImageLink ?? '', + alt: 'heap image', + }, + }, + }, + ]; + return { id, channelId, @@ -868,7 +894,9 @@ export function toPostData( image: metadata?.image ?? '', authorId: post.essay.author, isEdited: 'revision' in post && post.revision !== '0', - content: JSON.stringify(content), + content: galleryImageLink + ? JSON.stringify(galleryImageLinkContent) + : JSON.stringify(content), textContent: getTextContent(post?.essay.content), sentAt: post.essay.sent, receivedAt: getReceivedAtFromId(id), From 6c22a46f9d78b219fad4331084d8bd4062421561 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 12:36:52 -0500 Subject: [PATCH 048/259] delete: only show when appropriate --- .../ChatMessageActions/MessageActions.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx index 9a09a83962..921d85ccb0 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx @@ -33,6 +33,16 @@ export default function MessageActions({ const currentUserId = useCurrentUserId(); const { addAttachment } = useAttachmentContext(); const channel = useChannelContext(); + const { data: group } = store.useGroup({ id: post.groupId ?? '' }); + const currenUserIsAdmin = useMemo( + () => + group?.members?.some( + (member) => + member?.contactId === currentUserId && + member.roles.some((role) => role.roleId === 'admin') + ), + [group?.members, currentUserId] + ); const postActions = useMemo(() => { return getPostActions({ post, @@ -51,13 +61,16 @@ export default function MessageActions({ case 'edit': // only show edit for current user's posts return post.authorId === currentUserId; + case 'delete': + // only show delete for current user's posts + return post.authorId === currentUserId || currenUserIsAdmin; case 'viewReactions': return (post.reactions?.length ?? 0) > 0; default: return true; } }); - }, [post, channelType, currentUserId]); + }, [post, channelType, currentUserId, currenUserIsAdmin]); return ( // arbitrary width that looks reasonable given labels From fb1858465645a46375828cb99c79d4ac47688ff2 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 15 Oct 2024 13:37:55 -0500 Subject: [PATCH 049/259] wip: debug tools --- apps/tlon-mobile/index.js | 3 + .../app/features/settings/AppInfoScreen.tsx | 34 ++- packages/app/lib/debug.ts | 210 ++++++++++++++++++ packages/shared/src/debug.ts | 14 +- .../src/store/storage/storageActions.ts | 62 +++--- .../shared/src/store/storage/storageUtils.ts | 24 +- 6 files changed, 299 insertions(+), 48 deletions(-) create mode 100644 packages/app/lib/debug.ts diff --git a/apps/tlon-mobile/index.js b/apps/tlon-mobile/index.js index bbffb198d4..f1977428f7 100644 --- a/apps/tlon-mobile/index.js +++ b/apps/tlon-mobile/index.js @@ -1,5 +1,6 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; import { ENABLED_LOGGERS } from '@tloncorp/app/constants'; +import { initializeDebug } from '@tloncorp/app/lib/debug'; // Setup custom dev menu items import '@tloncorp/app/lib/devMenuItems'; import { setupDb } from '@tloncorp/app/lib/nativeDb'; @@ -13,6 +14,8 @@ import { TailwindProvider } from 'tailwind-rn'; import App from './src/App'; import utilities from './tailwind.json'; +initializeDebug(); + // Modifies fetch to support server sent events which // are required for Urbit client subscriptions setupDb(); diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index daeb29defd..7e8af5a3d5 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -2,11 +2,14 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; import * as store from '@tloncorp/shared/dist/store'; import { AppSetting, + Button, ListItem, ScreenHeader, SizableText, Stack, + Text, View, + XStack, YStack, } from '@tloncorp/ui'; import { preSig } from '@urbit/aura'; @@ -14,10 +17,11 @@ import * as Application from 'expo-application'; import * as Updates from 'expo-updates'; import { useMemo } from 'react'; import { useCallback } from 'react'; -import { Platform } from 'react-native'; +import { Platform, Switch } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; import { NOTIFY_PROVIDER, NOTIFY_SERVICE } from '../../constants'; +import { toggleDebug, uploadLogs, useDebugStore } from '../../lib/debug'; import { getEasUpdateDisplay } from '../../lib/platformHelpers'; import { RootStackParamList } from '../../navigation/types'; @@ -27,6 +31,7 @@ type Props = NativeStackScreenProps; export function AppInfoScreen(props: Props) { const { data: appInfo } = store.useAppInfo(); + const { enabled, logs, logsUrl } = useDebugStore(); const easUpdateDisplay = useMemo(() => getEasUpdateDisplay(Updates), []); const onPressPreviewFeatures = useCallback(() => { @@ -75,6 +80,33 @@ export function AppInfoScreen(props: Props) { )} + + Enable Developer Logs + + + + {enabled && logs.length > 0 && ( + + + {logsUrl} + + )} + diff --git a/packages/app/lib/debug.ts b/packages/app/lib/debug.ts new file mode 100644 index 0000000000..49068b6f3e --- /dev/null +++ b/packages/app/lib/debug.ts @@ -0,0 +1,210 @@ +import { + createDevLogger, + initializeLogger, + toggleAllLogs, +} from '@tloncorp/shared/dist'; +import { performUpload } from '@tloncorp/shared/dist/store'; +import { format } from 'date-fns'; +import * as FileSystem from 'expo-file-system'; +import { Alert, Platform } from 'react-native'; +import create from 'zustand'; + +import storage from './storage'; + +const DEBUG_STORAGE_KEY = 'debug'; +const DEBUG_LOG_STORAGE_KEY = 'debug-log'; +const devLogger = createDevLogger('debug-tools', false); + +interface Log { + timestamp: number; + message: string; +} + +interface DebugStore { + enabled: boolean; + logs: Log[]; + logsUrl: string | null; + appendLog: (log: Log) => void; + toggle: (enabled: boolean) => void; +} + +export const useDebugStore = create((set, get) => ({ + enabled: false, + logs: [], + logsUrl: null, + appendLog: (log: Log) => { + set((state) => ({ + logs: [...state.logs, log], + })); + }, + toggle: (enabled) => { + set(() => ({ + enabled, + })); + }, +})); + +storage + .load({ + key: DEBUG_STORAGE_KEY, + }) + .then((enabled) => { + useDebugStore.getState().toggle(enabled); + toggleAllLogs(enabled); + }); + +// we clear logs on every app start +// storage.save({ key: DEBUG_LOG_STORAGE_KEY, data: [] }); + +const write = (...args: unknown[]) => { + const message = args + .map((arg) => { + if (!arg) { + return JSON.stringify(arg); + } + if (typeof arg === 'string') { + return arg; + } + + if (typeof arg === 'object' && 'toString' in arg) { + return arg.toString(); + } + + return JSON.stringify(arg); + }) + .join(' '); + + useDebugStore.getState().appendLog({ + timestamp: Date.now(), + message, + }); + // storage.load({ key: DEBUG_LOG_STORAGE_KEY }).then((logs) => { + // logs.push({ + // timestamp: Date.now(), + // message, + // }); + // storage.save({ + // key: DEBUG_LOG_STORAGE_KEY, + // data: logs, + // }); + // }); +}; + +const logger = { + log: (...args: unknown[]) => { + if (useDebugStore.getState().enabled) { + write(args); + } + + if (!__DEV__) { + return; + } + + console.log(...args); + }, + warn: (...args: unknown[]) => { + if (useDebugStore.getState().enabled) { + write(args); + } + + if (!__DEV__) { + return; + } + + console.warn(...args); + }, + debug: (...args: unknown[]) => { + if (useDebugStore.getState().enabled) { + write(args); + } + + if (!__DEV__) { + return; + } + + console.debug(...args); + }, + error: (...args: unknown[]) => { + if (useDebugStore.getState().enabled) { + write(args); + } + + if (!__DEV__) { + return; + } + + console.error(...args); + }, +} as Console; + +export const initializeDebug = () => { + initializeLogger(logger); +}; + +export const toggleDebug = async (enabled: boolean) => { + useDebugStore.getState().toggle(enabled); + await storage.save({ + key: DEBUG_STORAGE_KEY, + data: enabled, + }); + + toggleAllLogs(enabled); + + if (enabled) { + console.log('Debug mode enabled'); + + Alert.alert( + 'Debug mode enabled', + 'Debug mode is now enabled. You may experience some degraded performance, because logs will be captured as you use the app. To get the best capture, you should kill the app and open it again.', + [ + { + text: 'OK', + }, + ] + ); + } else { + console.log('Debug mode disabled'); + } +}; + +export async function uploadLogs() { + const filename = `tlon-debug-log-${format(new Date(), 'M-d-yy-HH-mm')}`; + const contents = ( + await storage.load({ key: DEBUG_LOG_STORAGE_KEY }) + ).join('\n'); + if (Platform.OS === 'ios') { + if (!FileSystem.documentDirectory) { + logger.log(); + return; + } + const uri = FileSystem.documentDirectory + filename + '.txt'; + // await FileSystem. + await FileSystem.writeAsStringAsync(uri, contents, { + encoding: FileSystem.EncodingType.UTF8, + }); + + const url = await performUpload({ uri }, false); + useDebugStore.setState({ logsUrl: url }); + } else if (Platform.OS === 'android') { + const permissions = + await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync(); + if (!permissions.granted) { + return; + } + + if (!FileSystem.documentDirectory) { + return; + } + + const uri = await FileSystem.StorageAccessFramework.createFileAsync( + FileSystem.documentDirectory, + filename, + 'text/plain' + ); + + await FileSystem.StorageAccessFramework.writeAsStringAsync(uri, contents); + + const url = await performUpload({ uri }, false); + useDebugStore.setState({ logsUrl: url }); + } +} diff --git a/packages/shared/src/debug.ts b/packages/shared/src/debug.ts index 12340235b6..499c325811 100644 --- a/packages/shared/src/debug.ts +++ b/packages/shared/src/debug.ts @@ -4,6 +4,8 @@ import { useLiveRef } from './logic/utilHooks'; import { useCurrentSession } from './store/session'; const customLoggers = new Set(); +let logger: Console | null = null; +let forceEnabled = false; interface Breadcrumb { tag: string; @@ -38,6 +40,14 @@ export function addCustomEnabledLoggers(loggers: string[]) { loggers.forEach((logger) => customLoggers.add(logger)); } +export function initializeLogger(loggerInput: Console) { + logger = loggerInput; +} + +export function toggleAllLogs(on: boolean) { + forceEnabled = on; +} + interface ErrorLoggerStub { capture: (event: string, data: Record) => void; } @@ -94,10 +104,10 @@ export function createDevLogger(tag: string, enabled: boolean) { } if ( - (enabled || customLoggers.has(tag)) && + (forceEnabled || enabled || customLoggers.has(tag)) && process.env.NODE_ENV !== 'production' ) { - const val = Reflect.get(target, resolvedProp, receiver); + const val = Reflect.get(logger || target, resolvedProp, receiver); const prefix = `${[sessionTimeLabel(), deltaLabel()].filter((v) => !!v).join(':')} [${tag}]`; val(prefix, ...args); } diff --git a/packages/shared/src/store/storage/storageActions.ts b/packages/shared/src/store/storage/storageActions.ts index ec2ec51ef4..868a19753e 100644 --- a/packages/shared/src/store/storage/storageActions.ts +++ b/packages/shared/src/store/storage/storageActions.ts @@ -6,12 +6,12 @@ import * as FileSystem from 'expo-file-system'; import { manipulateAsync } from 'expo-image-manipulator'; import { ImagePickerAsset } from 'expo-image-picker'; -import { getCurrentUserId } from '../../api'; +import { RNFile, getCurrentUserId } from '../../api'; import * as db from '../../db'; import { createDevLogger, escapeLog } from '../../debug'; import { setUploadState } from './storageUploadState'; import { - fetchImageFromUri, + fetchFileFromUri, getMemexUpload, hasCustomS3Creds, hasHostingUploadCreds, @@ -30,7 +30,18 @@ export const uploadAsset = async (asset: ImagePickerAsset, isWeb = false) => { logger.log('full asset', asset); setUploadState(asset.uri, { status: 'uploading', localUri: asset.uri }); try { - const remoteUri = await performUpload(asset, isWeb); + logger.log('resizing asset', asset.uri); + const resizedAsset = await manipulateAsync( + asset.uri, + [ + { + resize: + asset.width > asset.height ? { width: 1200 } : { height: 1200 }, + }, + ], + { compress: 0.75 } + ); + const remoteUri = await performUpload(resizedAsset, isWeb); logger.crumb('upload succeeded'); logger.log('final uri', remoteUri); setUploadState(asset.uri, { status: 'success', remoteUri }); @@ -41,8 +52,11 @@ export const uploadAsset = async (asset: ImagePickerAsset, isWeb = false) => { } }; -const performUpload = async (asset: ImagePickerAsset, isWeb = false) => { - logger.log('performing upload', asset.uri, 'isWeb', isWeb); +export const performUpload = async ( + params: Pick, + isWeb = false +) => { + logger.log('performing upload', params.uri, 'isWeb', isWeb); const [config, credentials] = await Promise.all([ db.getStorageConfiguration(), db.getStorageCredentials(), @@ -52,41 +66,29 @@ const performUpload = async (asset: ImagePickerAsset, isWeb = false) => { throw new Error('unable to upload: missing storage configuration'); } - logger.log('resizing asset', asset.uri); - const resizedAsset = await manipulateAsync( - asset.uri, - [ - { - resize: asset.width > asset.height ? { width: 1200 } : { height: 1200 }, - }, - ], - { compress: 0.75 } - ); + const file = await fetchFileFromUri(params.uri, params.height, params.width); + if (!file) { + throw new Error('unable to fetch image from uri'); + } + const contentType = file.type; const fileKey = `${deSig(getCurrentUserId())}/${deSig( formatDa(unixToDa(new Date().getTime())) - )}-${resizedAsset.uri.split('/').pop()}`; + )}-${params.uri.split('/').pop()}`; logger.log('asset key:', fileKey); if (hasHostingUploadCreds(config, credentials)) { - const file = await fetchImageFromUri( - resizedAsset.uri, - resizedAsset.height, - resizedAsset.width - ); - if (!file) { - throw new Error('unable to fetch image from uri'); - } const { hostedUrl, uploadUrl } = await getMemexUpload({ - file, - uploadKey: fileKey, + contentLength: file.blob.size, + contentType, + fileName: fileKey, }); await uploadFile( uploadUrl, - resizedAsset.uri, + params.uri, { 'Cache-Control': 'public, max-age=3600', - 'Content-Type': file.type, + 'Content-Type': contentType, }, isWeb ); @@ -106,7 +108,7 @@ const performUpload = async (asset: ImagePickerAsset, isWeb = false) => { }); const headers = { - 'Content-Type': asset.mimeType ?? 'application/octet-stream', + 'Content-Type': contentType ?? 'application/octet-stream', 'Cache-Control': 'public, max-age=3600', 'x-amz-acl': 'public-read', // necessary for digital ocean spaces }; @@ -131,7 +133,7 @@ const performUpload = async (asset: ImagePickerAsset, isWeb = false) => { await uploadFile( signedUrl, - resizedAsset.uri, + params.uri, isDigitalOcean ? headers : undefined, isWeb ); diff --git a/packages/shared/src/store/storage/storageUtils.ts b/packages/shared/src/store/storage/storageUtils.ts index 56403c7f4f..65b00c28dd 100644 --- a/packages/shared/src/store/storage/storageUtils.ts +++ b/packages/shared/src/store/storage/storageUtils.ts @@ -13,10 +13,10 @@ import { desig } from '../../urbit'; const logger = createDevLogger('storage utils', true); -export const fetchImageFromUri = async ( +export const fetchFileFromUri = async ( uri: string, - height: number, - width: number + height?: number, + width?: number ) => { try { const response = await fetch(uri); @@ -26,7 +26,7 @@ export const fetchImageFromUri = async ( const file: RNFile = { uri, blob, - name: name ?? 'channel-image', + name: name ?? 'file', type: blob.type, height, width, @@ -84,20 +84,16 @@ export const getIsHosted = () => { return isHosted; }; -interface MemexUploadParams { +export interface MemexUploadParams { token: string; contentLength: number; contentType: string; fileName: string; } -export const getMemexUpload = async ({ - file, - uploadKey, -}: { - file: api.RNFile; - uploadKey: string; -}) => { +export const getMemexUpload = async ( + params: Omit +) => { const currentUser = api.getCurrentUserId(); const token = await scry({ app: 'genuine', @@ -108,9 +104,7 @@ export const getMemexUpload = async ({ const uploadParams: MemexUploadParams = { token, - contentLength: file.blob.size, - contentType: file.type, - fileName: uploadKey, + ...params, }; const endpoint = `${MEMEX_BASE_URL}/v1/${desig(currentUser)}/upload`; From 3cd9bbaf493792da1a713e8ecc7a0d19de1896a9 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 13:38:29 -0500 Subject: [PATCH 050/259] notebooks: represent hidden and deleted states for posts --- .../components/NotebookPost/NotebookPost.tsx | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/packages/ui/src/components/NotebookPost/NotebookPost.tsx b/packages/ui/src/components/NotebookPost/NotebookPost.tsx index 70f0b9fdd2..309242f5b4 100644 --- a/packages/ui/src/components/NotebookPost/NotebookPost.tsx +++ b/packages/ui/src/components/NotebookPost/NotebookPost.tsx @@ -88,31 +88,48 @@ export function NotebookPost({ pressStyle={{ backgroundColor: '$secondaryBackground' }} disabled={viewMode === 'activity'} > - - - {viewMode !== 'activity' && ( - - {post.textContent} - - )} + + {post.hidden + ? 'You have hidden this post.' + : 'This post has been deleted.'} + + + ) : ( + <> + - {showReplies && hasReplies ? ( - - ) : null} + {viewMode !== 'activity' && ( + + {post.textContent} + + )} + + {showReplies && hasReplies ? ( + + ) : null} + + )} {post.deliveryStatus === 'failed' ? ( From c852ff512f34ab0ca75107f94688b8a609799ca6 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 15 Oct 2024 15:39:20 -0400 Subject: [PATCH 051/259] correctly interpret joining state from gang claim --- packages/shared/src/urbit/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/urbit/utils.ts b/packages/shared/src/urbit/utils.ts index 4ef00b6105..4cbdb36fed 100644 --- a/packages/shared/src/urbit/utils.ts +++ b/packages/shared/src/urbit/utils.ts @@ -378,7 +378,10 @@ export function createMultiDmId(seed = Date.now()) { export function getJoinStatusFromGang(gang: ubg.Gang): GroupJoinStatus | null { if (gang.claim?.progress) { - if (gang.claim?.progress === 'adding') { + if ( + gang.claim?.progress === 'adding' || + gang.claim?.progress === 'watching' + ) { return 'joining'; } From 6ae4082f10bf0a49a5428290289b637f92c52d2c Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 15:04:17 -0500 Subject: [PATCH 052/259] use useIsAdmin where appropriate --- .../features/groups/GroupMembersScreen.tsx | 1 + .../ChatMessageActions/MessageActions.tsx | 12 ++-------- .../ui/src/components/ChatOptionsSheet.tsx | 23 ++++--------------- .../src/components/GroupMembersScreenView.tsx | 15 ++++-------- 4 files changed, 11 insertions(+), 40 deletions(-) diff --git a/packages/app/features/groups/GroupMembersScreen.tsx b/packages/app/features/groups/GroupMembersScreen.tsx index e63aecab14..78ebf50a86 100644 --- a/packages/app/features/groups/GroupMembersScreen.tsx +++ b/packages/app/features/groups/GroupMembersScreen.tsx @@ -56,6 +56,7 @@ export function GroupMembersScreen({ route, navigation }: Props) { onPressGoToDm={(contactId: string) => handleGoToDm([contactId])} members={groupMembers} roles={groupRoles} + groupId={groupId} currentUserId={currentUserId} onPressBan={banUser} onPressUnban={unbanUser} diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx index 921d85ccb0..8ac6b00b75 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx @@ -4,6 +4,7 @@ import * as db from '@tloncorp/shared/dist/db'; import * as logic from '@tloncorp/shared/dist/logic'; import * as store from '@tloncorp/shared/dist/store'; import * as Haptics from 'expo-haptics'; +import { useIsAdmin } from '../../../utils'; import { useMemo } from 'react'; import { Alert } from 'react-native'; @@ -33,16 +34,7 @@ export default function MessageActions({ const currentUserId = useCurrentUserId(); const { addAttachment } = useAttachmentContext(); const channel = useChannelContext(); - const { data: group } = store.useGroup({ id: post.groupId ?? '' }); - const currenUserIsAdmin = useMemo( - () => - group?.members?.some( - (member) => - member?.contactId === currentUserId && - member.roles.some((role) => role.roleId === 'admin') - ), - [group?.members, currentUserId] - ); + const currenUserIsAdmin = useIsAdmin(post.groupId ?? '', currentUserId); const postActions = useMemo(() => { return getPostActions({ post, diff --git a/packages/ui/src/components/ChatOptionsSheet.tsx b/packages/ui/src/components/ChatOptionsSheet.tsx index 45e9d81faa..60385e8e78 100644 --- a/packages/ui/src/components/ChatOptionsSheet.tsx +++ b/packages/ui/src/components/ChatOptionsSheet.tsx @@ -18,6 +18,7 @@ import { useSheet } from 'tamagui'; import { ChevronLeft } from '../assets/icons'; import { useCalm, useChatOptions, useCurrentUserId } from '../contexts'; import * as utils from '../utils'; +import { useIsAdmin } from '../utils'; import { Action, ActionGroup, ActionSheet } from './ActionSheet'; import { IconButton } from './IconButton'; import { ListItem } from './ListItem'; @@ -151,15 +152,7 @@ export function GroupOptions({ const isPinned = group?.pin; - const currentUserIsAdmin = useMemo( - () => - group?.members?.some( - (m) => - m.contactId === currentUser && - m.roles?.some((r) => r.roleId === 'admin') - ) ?? false, - [currentUser, group?.members] - ); + const currentUserIsAdmin = useIsAdmin(group.id, currentUser); const handleVolumeUpdate = useCallback( (newLevel: string) => { @@ -525,15 +518,7 @@ export function ChannelOptions({ [group?.currentUserIsHost] ); - const currentUserIsAdmin = useMemo( - () => - group?.members?.some( - (m) => - m.contactId === currentUser && - m.roles?.some((r) => r.roleId === 'admin') - ) ?? false, - [currentUser, group?.members] - ); + const currentUserIsAdmin = useIsAdmin(channel.groupId ?? '', currentUser); const { disableNicknames } = useCalm(); const title = useMemo(() => { @@ -703,7 +688,7 @@ export function ChannelOptions({ } as ActionGroup, ] : []), - // TODO: redefine in a more readable way. + // TODO: redefine in a more readable way. ...(group && !['groupDm', 'dm'].includes(channel.type) && (group.privacy === 'public' || diff --git a/packages/ui/src/components/GroupMembersScreenView.tsx b/packages/ui/src/components/GroupMembersScreenView.tsx index bbee14dc92..eedb375113 100644 --- a/packages/ui/src/components/GroupMembersScreenView.tsx +++ b/packages/ui/src/components/GroupMembersScreenView.tsx @@ -5,6 +5,7 @@ import { SectionList } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { View, getTokenValue } from 'tamagui'; +import { useIsAdmin } from '../utils'; import { ContactList } from './ContactList'; import { GroupJoinRequestSheet } from './GroupJoinRequestSheet'; import { ProfileSheet } from './ProfileSheet'; @@ -15,6 +16,7 @@ export function GroupMembersScreenView({ goBack, members, roles, + groupId, bannedUsers, joinRequests, groupPrivacyType, @@ -30,6 +32,7 @@ export function GroupMembersScreenView({ members: db.ChatMember[]; roles: db.GroupRole[]; currentUserId: string; + groupId: string; bannedUsers: db.GroupMemberBan[]; joinRequests: db.GroupJoinRequest[]; groupPrivacyType: GroupPrivacy; @@ -160,17 +163,7 @@ export function GroupMembersScreenView({ [roles] ); - const currentUserIsAdmin = useMemo( - () => - members.some( - (m) => - m.contactId === currentUserId && - m.roles !== undefined && - m.roles !== null && - m.roles.some((r) => r.roleId === 'admin') - ), - [members, currentUserId] - ); + const currentUserIsAdmin = useIsAdmin(groupId, currentUserId); return ( <> From d488270798a19677dada9735d07b4dd0c95f8384 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 15:11:05 -0500 Subject: [PATCH 053/259] members: add 'groups' table to deps for removeChatMembers query --- packages/shared/src/db/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index ea51c8117b..d0e6da549c 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -1065,7 +1065,7 @@ export const removeChatMembers = createWriteQuery( ) ); }, - ['chatMembers'] + ['chatMembers', 'groups'] ); export const getUnreadsCount = createReadQuery( From dbf77fc3780647b1e561a6693b7709c75fe6adce Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 15:13:44 -0500 Subject: [PATCH 054/259] members: add 'groups' table to deps for addChatMembers --- packages/shared/src/db/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index d0e6da549c..326d8b98cb 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -772,7 +772,7 @@ export const addChatMembers = createWriteQuery( .onConflictDoNothing(); }); }, - ['chatMembers'] + ['chatMembers', 'groups'] ); export const addGroupInvites = createWriteQuery( From 3c1dd0cd902bea1f94cbb6cd4947df73672922aa Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 15 Oct 2024 15:49:08 -0500 Subject: [PATCH 055/259] urbit: consolidate client logic further and handle logged out case --- .../src/components/AuthenticatedApp.tsx | 36 +--------- packages/app/hooks/useBootSequence.ts | 12 +--- packages/app/hooks/useConfigureUrbitClient.ts | 61 +++++++++++++++-- packages/app/hooks/useHandleLogout.ts | 5 +- packages/app/lib/api.ts | 67 ------------------- packages/shared/src/api/urbit.ts | 25 +++++-- 6 files changed, 82 insertions(+), 124 deletions(-) delete mode 100644 packages/app/lib/api.ts diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index a176657fe9..dbe4ca0cf4 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -1,25 +1,12 @@ -import crashlytics from '@react-native-firebase/crashlytics'; -import { useNavigation } from '@react-navigation/native'; -import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { useShip } from '@tloncorp/app/contexts/ship'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; import { useConfigureUrbitClient } from '@tloncorp/app/hooks/useConfigureUrbitClient'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; -import { useHandleLogout } from '@tloncorp/app/hooks/useHandleLogout'; import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; -import { useResetDb } from '@tloncorp/app/hooks/useResetDb'; -import { cancelFetch, configureClient } from '@tloncorp/app/lib/api'; -import { getShipAccessCode } from '@tloncorp/app/lib/hostingApi'; -import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; -import { trackError } from '@tloncorp/app/utils/posthog'; -import { - createDevLogger, - initializeCrashReporter, - sync, -} from '@tloncorp/shared'; +import { sync } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { ZStack } from '@tloncorp/ui'; import { useCallback, useEffect } from 'react'; @@ -29,39 +16,22 @@ import { useDeepLinkListener } from '../hooks/useDeepLinkListener'; import useNotificationListener, { type Props as NotificationListenerProps, } from '../hooks/useNotificationListener'; -import { OnboardingStackParamList } from '../types'; export interface AuthenticatedAppProps { notificationListenerProps: NotificationListenerProps; } -const appLogger = createDevLogger('app', false); - function AuthenticatedApp({ notificationListenerProps, }: AuthenticatedAppProps) { const shipInfo = useShip(); - const { ship, shipUrl, authType } = shipInfo; + const { ship, shipUrl } = shipInfo; const currentUserId = useCurrentUserId(); const configureClient = useConfigureUrbitClient(); useNotificationListener(notificationListenerProps); useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); - const resetDb = useResetDb(); - const logout = useHandleLogout({ - resetDb: () => { - appLogger.log('Resetting db on logout'); - resetDb(); - }, - }); - const navigation = - useNavigation< - NativeStackNavigationProp< - OnboardingStackParamList, - 'TlonLogin' | 'ShipLogin' - > - >(); useEffect(() => { configureClient(); @@ -78,8 +48,6 @@ function AuthenticatedApp({ if (status === 'active') { sync.syncUnreads({ priority: sync.SyncPriority.High }); sync.syncPinnedItems({ priority: sync.SyncPriority.High }); - } else if (status === 'background') { - cancelFetch(); } }, []); diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index 6c200112f7..14ecbfb4aa 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -4,7 +4,6 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { useLureMetadata } from '../contexts/branch'; import { useShip } from '../contexts/ship'; -import { configureClient } from '../lib/api'; import { NodeBootPhase } from '../lib/bootHelpers'; import BootHelpers from '../lib/bootHelpers'; import { getShipFromCookie } from '../utils/ship'; @@ -24,8 +23,8 @@ interface BootSequenceReport { /* Takes a fresh hosting account and holds its hand until it has a node that's ready to transition to a logged in state. - - Two main components: + + Two main components: runBootPhase — executes a single boot step, returns the next step in the sequence runBootSequence — repeatedly executes runBootPhase until the sequence is complete @@ -111,13 +110,6 @@ export function useBootSequence({ authType: 'hosted', }); - // configureClient({ - // shipName: auth.nodeId, - // shipUrl: auth.nodeUrl, - // onReset: () => store.syncStart(), - // onChannelReset: () => store.handleDiscontinuity(), - // onChannelStatusChange: store.handleChannelStatusChange, - // }); configureUrbitClient({ shipName: auth.nodeId, shipUrl: auth.nodeUrl }); store.syncStart(); diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index b66430e136..e949d78d5b 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -4,24 +4,69 @@ import { sync, updateSession, } from '@tloncorp/shared/dist'; -import { ClientParams } from '@tloncorp/shared/dist/api'; +import { ClientParams, configureClient } from '@tloncorp/shared/dist/api'; import { useCallback } from 'react'; +//@ts-expect-error no typedefs +import { fetch as streamingFetch } from 'react-native-fetch-api'; +//@ts-expect-error no typedefs +import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; +//@ts-expect-error no typedefs +import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; import { ENABLED_LOGGERS } from '../constants'; import { useShip } from '../contexts/ship'; -import { configureClient } from '../lib/api'; import { getShipAccessCode } from '../lib/hostingApi'; import { resetDb } from '../lib/nativeDb'; import { useHandleLogout } from './useHandleLogout'; -const appLogger = createDevLogger('configure client', false); +polyfillReadableStream(); +polyfillEncoding(); + +let abortController = new AbortController(); + +const apiFetch: typeof fetch = (input, { ...init } = {}) => { + // Wire our injected AbortController up to the one passed in by the client. + if (init.signal) { + init.signal.onabort = () => { + abortController.abort(); + abortController = new AbortController(); + }; + } + + const headers = new Headers(init.headers); + // The urbit client is inconsistent about sending cookies, sometimes causing + // the server to send back a new, anonymous, cookie, which is sent on all + // subsequent requests and screws everything up. This ensures that explicit + // cookie headers are never set, delegating all cookie handling to the + // native http client. + headers.delete('Cookie'); + headers.delete('cookie'); + const newInit: RequestInit = { + ...init, + headers, + // Avoid setting credentials method for same reason as above. + credentials: undefined, + signal: abortController.signal, + // @ts-expect-error This is used by the SSE polyfill to determine whether + // to stream the request. + reactNative: { textStreaming: true }, + }; + return streamingFetch(input, newInit); +}; + +export const cancelFetch = () => { + abortController.abort(); + abortController = new AbortController(); +}; + +const clientLogger = createDevLogger('configure client', false); export function useConfigureUrbitClient() { const shipInfo = useShip(); const { ship, shipUrl, authType } = shipInfo; const logout = useHandleLogout({ resetDb: () => { - appLogger.log('Resetting db on logout'); + clientLogger.log('Resetting db on logout'); resetDb(); }, }); @@ -32,6 +77,8 @@ export function useConfigureUrbitClient() { shipName: params?.shipName ?? ship ?? '', shipUrl: params?.shipUrl ?? shipUrl ?? '', verbose: ENABLED_LOGGERS.includes('urbit'), + fetchFn: apiFetch, + cancelFetch, onReconnect: () => { const threshold = 5 * 60 * 1000; // 5 minutes const lastReconnect = getSession()?.startTime ?? 0; @@ -53,11 +100,11 @@ export function useConfigureUrbitClient() { authType === 'self' ? undefined : async () => { - appLogger.log('Getting ship access code', { + clientLogger.log('Getting ship access code', { ship, authType, }); - appLogger.trackError( + clientLogger.trackError( 'Hosted ship logged out of urbit, getting ship access code' ); if (!ship) { @@ -68,7 +115,7 @@ export function useConfigureUrbitClient() { return code; }, handleAuthFailure: async () => { - appLogger.trackError( + clientLogger.trackError( 'Failed to authenticate with ship, redirecting to login' ); await logout(); diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index 8f62a78278..8486dd5806 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -1,4 +1,7 @@ -import { createDevLogger } from '@tloncorp/shared/dist'; +import { + createDevLogger, + updateInitializedClient, +} from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; import { useCallback } from 'react'; diff --git a/packages/app/lib/api.ts b/packages/app/lib/api.ts deleted file mode 100644 index 0a95b48571..0000000000 --- a/packages/app/lib/api.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as api from '@tloncorp/shared/dist/api'; -import { - getInitializedClient, - updateInitializedClient, -} from '@tloncorp/shared/dist/store'; -import { ChannelStatus } from '@urbit/http-api'; -import { ClientParams } from 'packages/shared/src/api'; -//@ts-expect-error no typedefs -import { fetch as streamingFetch } from 'react-native-fetch-api'; -//@ts-expect-error no typedefs -import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; -//@ts-expect-error no typedefs -import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; - -polyfillReadableStream(); -polyfillEncoding(); - -let abortController = new AbortController(); - -const apiFetch: typeof fetch = (input, { ...init } = {}) => { - // Wire our injected AbortController up to the one passed in by the client. - if (init.signal) { - init.signal.onabort = () => { - abortController.abort(); - abortController = new AbortController(); - }; - } - - const headers = new Headers(init.headers); - // The urbit client is inconsistent about sending cookies, sometimes causing - // the server to send back a new, anonymous, cookie, which is sent on all - // subsequent requests and screws everything up. This ensures that explicit - // cookie headers are never set, delegating all cookie handling to the - // native http client. - headers.delete('Cookie'); - headers.delete('cookie'); - const newInit: RequestInit = { - ...init, - headers, - // Avoid setting credentials method for same reason as above. - credentials: undefined, - signal: abortController.signal, - // @ts-expect-error This is used by the SSE polyfill to determine whether - // to stream the request. - reactNative: { textStreaming: true }, - }; - return streamingFetch(input, newInit); -}; - -export const cancelFetch = () => { - abortController.abort(); - abortController = new AbortController(); -}; - -// TODO: can this just get moved into the hook? -export function configureClient(params: Omit) { - const clientInitialized = getInitializedClient(); - if (!clientInitialized) { - api.configureClient({ - ...params, - fetchFn: apiFetch, - }); - updateInitializedClient(true); - } else { - console.log(`skipping client configuration, already initialized`); - } -} diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 8d78cc4540..32d208817e 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -3,6 +3,7 @@ import { ChannelStatus, PokeInterface, Urbit } from '@urbit/http-api'; import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; +import { getInitializedClient, updateInitializedClient } from '../store'; import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); @@ -10,7 +11,11 @@ const logger = createDevLogger('urbit', false); interface Config extends Pick< ClientParams, - 'getCode' | 'handleAuthFailure' | 'shipUrl' | 'onChannelReset' + | 'getCode' + | 'handleAuthFailure' + | 'shipUrl' + | 'onChannelReset' + | 'cancelFetch' > { client: Urbit | null; subWatchers: Watchers; @@ -52,6 +57,7 @@ export interface ClientParams { shipUrl: string; verbose?: boolean; fetchFn?: typeof fetch; + cancelFetch?: () => void; getCode?: () => Promise; handleAuthFailure?: () => void; onReconnect?: () => void; @@ -96,27 +102,31 @@ export const getCurrentUserIsHosted = () => { return client.url.endsWith('tlon.network'); }; -let configureCount = 0; export function configureClient({ shipName, shipUrl, verbose, fetchFn, + cancelFetch, getCode, handleAuthFailure, onReconnect, onChannelReset, onChannelStatusChange, }: ClientParams) { - logger.log('configuring client', shipName, shipUrl); - if (configureCount++ > 0) { - logger.error('client already configured'); + const clientInitialized = getInitializedClient(); + if (clientInitialized) { + logger.log('client already initialized, skipping'); + return; } + + logger.log('configuring client', shipName, shipUrl); config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.ship = deSig(shipName); config.client.our = preSig(shipName); config.client.verbose = verbose; config.shipUrl = shipUrl; + config.cancelFetch = cancelFetch; config.onChannelReset = onChannelReset; config.getCode = getCode; config.handleAuthFailure = handleAuthFailure; @@ -156,11 +166,16 @@ export function configureClient({ config.client.on('channel-reaped', () => { logger.log('client channel-reaped'); }); + + updateInitializedClient(true); } export function removeUrbitClient() { + config.client?.delete(); + config.cancelFetch?.(); config.client = null; config.subWatchers = {}; + updateInitializedClient(false); } function printEndpoint(endpoint: UrbitEndpoint) { From ba6dd69b309e14dbd2ff4feab2b7e56dc25a2848 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 15 Oct 2024 16:55:39 -0400 Subject: [PATCH 056/259] add new query for getting all channels, use that to check against name collisions when creating new channel --- packages/app/features/top/GroupChannelsScreen.tsx | 2 +- packages/app/hooks/useGroupContext.ts | 10 +++------- packages/shared/src/db/modelBuilders.ts | 15 +++------------ packages/shared/src/db/queries.ts | 8 ++++++++ packages/shared/src/store/dbHooks.ts | 9 +++++++++ 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index 817ca2d264..d21772b6a4 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -28,7 +28,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { const [inviteSheetGroup, setInviteSheetGroup] = useState( null ); - const { createChannel } = useGroupContext({ groupId: id }); + const { createChannel } = useGroupContext({ groupId: id, isFocused }); const pinnedItems = useMemo(() => { return pins ?? []; diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index 957596f43b..f678b2f098 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -100,10 +100,7 @@ export const useGroupContext = ({ } }, [group]); - const { data: pendingChats } = store.usePendingChats({ - enabled: isFocused, - }); - const { data: currentChatData } = store.useCurrentChats({ + const { data: existingChannels } = store.useAllChannels({ enabled: isFocused, }); @@ -120,8 +117,7 @@ export const useGroupContext = ({ const { name, id } = assembleNewChannelIdAndName({ title, channelType, - currentChatData, - pendingChats, + existingChannels: existingChannels ?? [], currentUserId, }); @@ -136,7 +132,7 @@ export const useGroupContext = ({ }); } }, - [group, currentUserId, currentChatData, pendingChats] + [group, currentUserId, existingChannels] ); const deleteChannel = useCallback( diff --git a/packages/shared/src/db/modelBuilders.ts b/packages/shared/src/db/modelBuilders.ts index 3caab0c657..0df2b0d11a 100644 --- a/packages/shared/src/db/modelBuilders.ts +++ b/packages/shared/src/db/modelBuilders.ts @@ -9,7 +9,6 @@ import { import * as db from '../db'; import * as logic from '../logic'; import { convertToAscii } from '../logic'; -import { CurrentChats, PendingChats } from '../store'; import * as ub from '../urbit'; import { getChannelKindFromType } from '../urbit'; import * as types from './types'; @@ -17,22 +16,14 @@ import * as types from './types'; export function assembleNewChannelIdAndName({ title, channelType, - currentChatData, - pendingChats, + existingChannels, currentUserId, }: { title: string; channelType: Omit; - currentChatData?: CurrentChats | null; - pendingChats?: PendingChats | null; + existingChannels: db.Channel[]; currentUserId: string; }) { - const existingChannels = [ - ...(pendingChats ?? []), - ...(currentChatData?.pinned ?? []), - ...(currentChatData?.unpinned ?? []), - ]; - const titleIsNumber = Number.isInteger(Number(title)); // we need unique channel names that are valid for urbit's @tas type const tempChannelName = titleIsNumber @@ -47,7 +38,7 @@ export function assembleNewChannelIdAndName({ ); }; - const randomSmallNumber = Math.floor(Math.random() * 100); + const randomSmallNumber = Math.floor(Math.random() * 1000); const channelName = existingChannel() ? `${tempChannelName}-${randomSmallNumber}` : tempChannelName; diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index ea51c8117b..011bba790d 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -230,6 +230,14 @@ export const getPins = createReadQuery( ['pins'] ); +export const getAllChannels = createReadQuery( + 'getAllChannels', + async (ctx: QueryCtx) => { + return ctx.db.query.channels.findMany(); + }, + ['channels'] +); + export const getChats = createReadQuery( 'getChats', async (ctx: QueryCtx): Promise => { diff --git a/packages/shared/src/store/dbHooks.ts b/packages/shared/src/store/dbHooks.ts index d3f6516895..b7a37c594d 100644 --- a/packages/shared/src/store/dbHooks.ts +++ b/packages/shared/src/store/dbHooks.ts @@ -27,6 +27,15 @@ export type CustomQueryConfig = Pick< 'enabled' >; +export const useAllChannels = ({ enabled }: { enabled?: boolean }) => { + const querykey = useKeyFromQueryDeps(db.getAllChannels); + return useQuery({ + queryKey: ['allChannels', querykey], + queryFn: () => db.getAllChannels(), + enabled, + }); +}; + export const useCurrentChats = ( queryConfig?: CustomQueryConfig ): UseQueryResult => { From e504ad2827269ff5f5aef238970a6e3c6642bb96 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 15 Oct 2024 18:19:03 -0400 Subject: [PATCH 057/259] fix optimistic updates for add channel --- packages/app/features/top/GroupChannelsScreen.tsx | 3 ++- packages/shared/src/api/groupsApi.ts | 6 ++++-- packages/shared/src/db/queries.ts | 6 +++++- packages/shared/src/store/channelActions.ts | 1 + .../ui/src/components/GroupChannelsScreenView.tsx | 11 ++++------- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index d21772b6a4..d96bcaf440 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -28,7 +28,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { const [inviteSheetGroup, setInviteSheetGroup] = useState( null ); - const { createChannel } = useGroupContext({ groupId: id, isFocused }); + const { group, createChannel } = useGroupContext({ groupId: id, isFocused }); const pinnedItems = useMemo(() => { return pins ?? []; @@ -62,6 +62,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { onBackPressed={handleGoBackPressed} currentUser={currentUser} createChannel={createChannel} + group={group} /> ( { app: 'groups', path: '/groups/ui' }, (groupUpdateEvent) => { - logger.log('groupUpdateEvent', { groupUpdateEvent }); + logger.log('groupUpdateEvent', groupUpdateEvent); eventHandler(toGroupUpdate(groupUpdateEvent)); } ); subscribe({ app: 'groups', path: '/gangs/updates' }, (rawEvent: ub.Gangs) => { - logger.log('gangsUpdateEvent:', rawEvent); + logger.log('gangsUpdateEvent', rawEvent); eventHandler(toGangsGroupsUpdate(rawEvent)); }); }; @@ -1337,6 +1337,8 @@ export function toClientGroup( haveInvite: false, currentUserIsMember: isJoined, currentUserIsHost: hostUserId === currentUserId, + // if meta is unset, it's still in the join process + joinStatus: !group.meta || group.meta.title === '' ? 'joining' : undefined, hostUserId, flaggedPosts, navSections: group['zone-ord'] diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index 011bba790d..b4590839a3 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -1463,7 +1463,11 @@ export const insertChannels = createWriteQuery( .values(channels) .onConflictDoUpdate({ target: $channels.id, - set: conflictUpdateSetAll($channels, ['lastPostId', 'lastPostAt']), + set: conflictUpdateSetAll($channels, [ + 'lastPostId', + 'lastPostAt', + 'currentUserIsMember', + ]), }); for (const channel of channels) { diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index 6b2bbd40bb..6cd5427e66 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -29,6 +29,7 @@ export async function createChannel({ type: channelType as db.ChannelType, groupId, addedToGroupAt: Date.now(), + currentUserIsMember: true, }; await db.insertChannels([newChannel]); diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index b89ff31221..ce7b9b3a28 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -4,7 +4,6 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ScrollView, View, YStack } from 'tamagui'; import { useCurrentUserId } from '../contexts'; -import { useChatOptions } from '../contexts/chatOptions'; import { useIsAdmin } from '../utils/channelUtils'; import ChannelNavSections from './ChannelNavSections'; import { ChatOptionsSheet, ChatOptionsSheetMethods } from './ChatOptionsSheet'; @@ -16,6 +15,7 @@ import { import { ScreenHeader } from './ScreenHeader'; type GroupChannelsScreenViewProps = { + group: db.Group | null; onChannelPressed: (channel: db.Channel) => void; onBackPressed: () => void; currentUser: string; @@ -31,12 +31,11 @@ type GroupChannelsScreenViewProps = { }; export function GroupChannelsScreenView({ + group, onChannelPressed, onBackPressed, createChannel, }: GroupChannelsScreenViewProps) { - const groupOptions = useChatOptions(); - const group = groupOptions?.group; const chatOptionsSheetRef = useRef(null); const [showCreateChannel, setShowCreateChannel] = useState(false); const [sortBy, setSortBy] = useState('recency'); @@ -105,9 +104,7 @@ export function GroupChannelsScreenView({ } /> - {group && - groupOptions.groupChannels && - groupOptions.groupChannels.length ? ( + {group && group.channels && group.channels.length ? ( Date: Tue, 15 Oct 2024 18:37:50 -0400 Subject: [PATCH 058/259] remove channel description from add channel sheet --- packages/app/hooks/useGroupContext.ts | 2 +- packages/shared/src/store/channelActions.ts | 6 +++--- .../components/GroupChannelsScreenView.tsx | 2 +- .../ManageChannels/CreateChannelSheet.tsx | 19 ++----------------- 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index f678b2f098..11f5553fb3 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -111,7 +111,7 @@ export const useGroupContext = ({ channelType, }: { title: string; - description: string; + description?: string; channelType: Omit; }) => { const { name, id } = assembleNewChannelIdAndName({ diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index 6cd5427e66..e19a8bf04b 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -18,14 +18,14 @@ export async function createChannel({ channelId: string; name: string; title: string; - description: string; + description?: string; channelType: Omit; }) { // optimistic update const newChannel: db.Channel = { id: channelId, title, - description, + description: description ?? '', type: channelType as db.ChannelType, groupId, addedToGroupAt: Date.now(), @@ -41,7 +41,7 @@ export async function createChannel({ group: groupId, name, title, - description, + description: description ?? '', readers: [], writers: [], }); diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index ce7b9b3a28..46ed8efdd5 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -25,7 +25,7 @@ type GroupChannelsScreenViewProps = { channelType, }: { title: string; - description: string; + description?: string; channelType: ChannelTypeName; }) => Promise; }; diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 81062ff58b..eeddcd7198 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -39,27 +39,21 @@ export function CreateChannelSheet({ channelType, }: { title: string; - description: string; + description?: string; channelType: ChannelTypeName; }) => void; }) { const { control, handleSubmit } = useForm({ defaultValues: { title: '', - description: '', channelType: 'chat', }, }); const handlePressSave = useCallback( - async (data: { - title: string; - description: string; - channelType: string; - }) => { + async (data: { title: string; channelType: string }) => { createChannel({ title: data.title, - description: data.description, channelType: data.channelType as ChannelTypeName, }); onOpenChange(false); @@ -80,15 +74,6 @@ export function CreateChannelSheet({ rules={{ required: 'Channel title is required' }} /> - - - Date: Tue, 15 Oct 2024 18:44:43 -0400 Subject: [PATCH 059/259] missed a spot --- .../src/components/ManageChannels/ManageChannelsScreenView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx index 2d17cf6a7d..edc137d5ef 100644 --- a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx +++ b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx @@ -194,7 +194,7 @@ interface ManageChannelsScreenViewProps { channelType, }: { title: string; - description: string; + description?: string; channelType: ChannelTypeName; }) => Promise; createNavSection: ({ title }: { title: string }) => Promise; From ccd58805902a5b05ac5224c65c69b41e0a801cc4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Oct 2024 13:54:41 +0000 Subject: [PATCH 060/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 2ad732bf4c..ef5cb5c08b 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v5.ensqi.86b0e.93jfb.65ah6.l4h30.glob' 0v5.ensqi.86b0e.93jfb.65ah6.l4h30] + glob-http+['https://bootstrap.urbit.org/glob-0v6.0sjnh.84djm.kqv5r.eeb2p.ailh6.glob' 0v6.0sjnh.84djm.kqv5r.eeb2p.ailh6] base+'groups' version+[6 4 2] website+'https://tlon.io' From 99b6638086ba663eecd69641823bd3f094e40866 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 09:36:29 -0500 Subject: [PATCH 061/259] gallery: navigate appropriately when tapping refs --- packages/app/features/top/PostScreen.tsx | 23 ++++++- packages/ui/src/components/DetailView.tsx | 9 +-- packages/ui/src/components/PostScreenView.tsx | 61 ++++++++++++++++++- 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/packages/app/features/top/PostScreen.tsx b/packages/app/features/top/PostScreen.tsx index ec85e16c9a..f84d6f045f 100644 --- a/packages/app/features/top/PostScreen.tsx +++ b/packages/app/features/top/PostScreen.tsx @@ -3,6 +3,7 @@ import * as db from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { PostScreenView, useCurrentUserId } from '@tloncorp/ui'; +import { useGroupActions } from 'packages/app/hooks/useGroupActions'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useChannelContext } from '../../hooks/useChannelContext'; @@ -30,9 +31,10 @@ export default function PostScreen(props: Props) { uploaderKey: `${postParam.channelId}/${postParam.id}`, }); - const { navigateToImage } = useChannelNavigation({ - channelId: postParam.channelId, - }); + const { navigateToImage, navigateToRef } = + useChannelNavigation({ + channelId: postParam.channelId, + }); const currentUserId = useCurrentUserId(); @@ -119,6 +121,18 @@ export default function PostScreen(props: Props) { [props.navigation] ); + const { performGroupAction } = useGroupActions(); + + const handleGoToDm = useCallback( + async (participants: string[]) => { + const dmChannel = await store.upsertDmChannel({ + participants, + }); + props.navigation.push('Channel', { channel: dmChannel }); + }, + [props.navigation] + ); + return currentUserId && channel && post ? ( ; } export const DetailView = ({ @@ -40,6 +41,7 @@ export const DetailView = ({ activeMessage, headerMode, editorIsFocused, + flatListRef, }: DetailViewProps) => { const channelType = useMemo( () => urbit.getChannelType(post.channelId), @@ -49,13 +51,12 @@ export const DetailView = ({ const resolvedPosts = useMemo(() => { return isChat && posts ? [...posts, post] : posts; }, [posts, post, isChat]); - const flatListRef = useRef(null); useEffect(() => { - if (editorIsFocused) { + if (editorIsFocused && flatListRef) { flatListRef.current?.scrollToIndex({ index: 1, animated: true }); } - }, [editorIsFocused]); + }, [editorIsFocused, flatListRef]); const scroller = useMemo(() => { return ( diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 3acfe43636..58271aa9cc 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -3,7 +3,8 @@ import type * as db from '@tloncorp/shared/dist/db'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { Story } from '@tloncorp/shared/dist/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { FlatList } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Text, View, YStack } from 'tamagui'; @@ -14,6 +15,7 @@ import { BigInput } from './BigInput'; import { ChannelFooter } from './Channel/ChannelFooter'; import { ChannelHeader } from './Channel/ChannelHeader'; import { DetailView } from './DetailView'; +import { GroupPreviewAction, GroupPreviewSheet } from './GroupPreviewSheet'; import KeyboardAvoidingView from './KeyboardAvoidingView'; import { MessageInput } from './MessageInput'; import { TlonEditorBridge } from './MessageInput/toolbarActions.native'; @@ -39,6 +41,9 @@ export function PostScreenView({ editPost, onPressRetry, onPressDelete, + onPressRef, + onGroupAction, + goToDm, negotiationMatch, headerMode, canUpload, @@ -69,6 +74,9 @@ export function PostScreenView({ ) => Promise; onPressRetry: (post: db.Post) => void; onPressDelete: (post: db.Post) => void; + onPressRef: (channel: db.Channel, post: db.Post) => void; + onGroupAction: (action: GroupPreviewAction, group: db.Group) => void; + goToDm: (participants: string[]) => void; negotiationMatch: boolean; headerMode: 'default' | 'next'; canUpload: boolean; @@ -86,6 +94,8 @@ export function PostScreenView({ editor: TlonEditorBridge | null; }>(null); const [editorIsFocused, setEditorIsFocused] = useState(false); + const [groupPreview, setGroupPreview] = useState(null); + const flatListRef = useRef(null); // We track the editor focus state to determine when we need to scroll to the // bottom of the screen when the keyboard is opened/editor is focused. @@ -112,9 +122,49 @@ export function PostScreenView({ return editingPost && editingPost.id === parentPost?.id; }, [editingPost, parentPost]); + const onPressGroupRef = useCallback((group: db.Group) => { + setGroupPreview(group); + }, []); + + const handleGroupAction = useCallback( + (action: GroupPreviewAction, group: db.Group) => { + onGroupAction(action, group); + setGroupPreview(null); + }, + [onGroupAction] + ); + + const handleRefPress = useCallback( + (refChannel: db.Channel, post: db.Post) => { + const anchorIndex = posts?.findIndex((p) => p.id === post.id) ?? -1; + + if ( + refChannel.id === channel.id && + anchorIndex !== -1 && + flatListRef.current + ) { + // If the post is already loaded, scroll to it + flatListRef.current?.scrollToIndex({ + index: anchorIndex, + animated: false, + viewPosition: 0.5, + }); + return; + } + + onPressRef(refChannel, post); + }, + [onPressRef, posts, channel] + ); + return ( - + ) : null} @@ -212,6 +263,12 @@ export function PostScreenView({ /> )} + setGroupPreview(null)} + onActionComplete={handleGroupAction} + /> From bdbc49f0f1fa007745d23f8cc34c6f23d1cb7c64 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 09:54:29 -0500 Subject: [PATCH 062/259] chat options: navigate back to chat list on leave --- packages/app/hooks/useChatSettingsNavigation.ts | 8 ++++++++ packages/ui/src/components/ChatOptionsSheet.tsx | 3 +++ packages/ui/src/contexts/chatOptions.tsx | 5 ++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/app/hooks/useChatSettingsNavigation.ts b/packages/app/hooks/useChatSettingsNavigation.ts index 44604f6586..585e808e46 100644 --- a/packages/app/hooks/useChatSettingsNavigation.ts +++ b/packages/app/hooks/useChatSettingsNavigation.ts @@ -71,6 +71,13 @@ export const useChatSettingsNavigation = () => { [navigation] ); + const navigateOnLeave = useCallback( + () => { + navigation.navigate('ChatList'); + }, + [navigation] + ); + return { onPressChannelMembers, onPressChannelMeta, @@ -79,5 +86,6 @@ export const useChatSettingsNavigation = () => { onPressManageChannels, onPressGroupPrivacy, onPressRoles, + navigateOnLeave, }; }; diff --git a/packages/ui/src/components/ChatOptionsSheet.tsx b/packages/ui/src/components/ChatOptionsSheet.tsx index 60385e8e78..ae9973e4b5 100644 --- a/packages/ui/src/components/ChatOptionsSheet.tsx +++ b/packages/ui/src/components/ChatOptionsSheet.tsx @@ -511,6 +511,7 @@ export function ChannelOptions({ onPressChannelMeta, onPressManageChannels, onPressInvite, + onPressLeave, } = useChatOptions() ?? {}; const currentUserIsHost = useMemo( @@ -752,6 +753,7 @@ export function ChannelOptions({ style: 'destructive', onPress: () => { sheetRef.current.setOpen(false); + onPressLeave?.(); store.respondToDMInvite({ channel, accept: false }); }, }, @@ -774,6 +776,7 @@ export function ChannelOptions({ onPressChannelMembers, onPressManageChannels, onPressInvite, + onPressLeave, title, ]); return ( diff --git a/packages/ui/src/contexts/chatOptions.tsx b/packages/ui/src/contexts/chatOptions.tsx index 356ff6bd44..5d0fe22060 100644 --- a/packages/ui/src/contexts/chatOptions.tsx +++ b/packages/ui/src/contexts/chatOptions.tsx @@ -47,6 +47,7 @@ type ChatOptionsProviderProps = { onPressChannelMeta: (channelId: string) => void; onPressRoles: (groupId: string) => void; onSelectSort?: (sortBy: 'recency' | 'arranged') => void; + navigateOnLeave?: () => void; }; export const ChatOptionsProvider = ({ @@ -62,6 +63,7 @@ export const ChatOptionsProvider = ({ onPressChannelMembers, onPressChannelMeta, onPressRoles, + navigateOnLeave, }: ChatOptionsProviderProps) => { const groupQuery = useGroup({ id: groupId ?? '' }); const group = groupId ? groupQuery.data ?? null : null; @@ -80,7 +82,8 @@ export const ChatOptionsProvider = ({ if (group) { await store.leaveGroup(group.id); } - }, [group]); + navigateOnLeave?.(); + }, [group, navigateOnLeave]); const onSelectSort = useCallback((sortBy: 'recency' | 'arranged') => { db.storeChannelSortPreference(sortBy); From c6070ecbeb91a820c38e2fd75519ed3c9547f3ca Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 09:58:15 -0500 Subject: [PATCH 063/259] fix import for useGroupActions --- packages/app/features/top/PostScreen.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/app/features/top/PostScreen.tsx b/packages/app/features/top/PostScreen.tsx index f84d6f045f..5c46f40905 100644 --- a/packages/app/features/top/PostScreen.tsx +++ b/packages/app/features/top/PostScreen.tsx @@ -3,11 +3,11 @@ import * as db from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { PostScreenView, useCurrentUserId } from '@tloncorp/ui'; -import { useGroupActions } from 'packages/app/hooks/useGroupActions'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useChannelContext } from '../../hooks/useChannelContext'; import { useChannelNavigation } from '../../hooks/useChannelNavigation'; +import { useGroupActions } from '../../hooks/useGroupActions'; import type { RootStackParamList } from '../../navigation/types'; type Props = NativeStackScreenProps; @@ -31,10 +31,9 @@ export default function PostScreen(props: Props) { uploaderKey: `${postParam.channelId}/${postParam.id}`, }); - const { navigateToImage, navigateToRef } = - useChannelNavigation({ - channelId: postParam.channelId, - }); + const { navigateToImage, navigateToRef } = useChannelNavigation({ + channelId: postParam.channelId, + }); const currentUserId = useCurrentUserId(); From 93e4341a65c9fcb2d7f37230e81f688f5ce5221d Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Oct 2024 14:59:34 +0000 Subject: [PATCH 064/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index ef5cb5c08b..36641c4b17 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v6.0sjnh.84djm.kqv5r.eeb2p.ailh6.glob' 0v6.0sjnh.84djm.kqv5r.eeb2p.ailh6] + glob-http+['https://bootstrap.urbit.org/glob-0v5.cdkn1.29ten.suoa4.66q4k.cl7fg.glob' 0v5.cdkn1.29ten.suoa4.66q4k.cl7fg] base+'groups' version+[6 4 2] website+'https://tlon.io' From d30e5c36851ed20915b775d86e36dd863991ebb9 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 10:06:34 -0500 Subject: [PATCH 065/259] fix fixtures --- .../src/fixtures/DetailView/detailViewFixtureBase.tsx | 3 +++ apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx b/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx index f0deeb7638..77b9db7de4 100644 --- a/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx +++ b/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx @@ -56,6 +56,9 @@ export const DetailViewFixture = ({ canUpload={true} handleGoToUserProfile={() => {}} headerMode="default" + onPressRef={() => {}} + onGroupAction={() => {}} + goToDm={() => {}} /> diff --git a/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx b/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx index 9a81df5f73..65f41277bf 100644 --- a/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx @@ -39,6 +39,9 @@ export default ( clearDraft={() => {}} canUpload={true} headerMode="default" + onPressRef={() => {}} + onGroupAction={() => {}} + goToDm={() => {}} /> ); From 67de1b63443b72f70e282918b7f9daa5b5262565 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 16 Oct 2024 11:20:10 -0400 Subject: [PATCH 066/259] rewrap client init/teardown methods --- packages/app/hooks/useConfigureUrbitClient.ts | 3 ++- packages/shared/src/api/urbit.ts | 15 +++---------- packages/shared/src/store/clientActions.ts | 21 +++++++++++++++++++ packages/shared/src/store/index.ts | 1 + 4 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 packages/shared/src/store/clientActions.ts diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index e949d78d5b..be1b0953a2 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -4,7 +4,8 @@ import { sync, updateSession, } from '@tloncorp/shared/dist'; -import { ClientParams, configureClient } from '@tloncorp/shared/dist/api'; +import { ClientParams } from '@tloncorp/shared/dist/api'; +import { configureClient } from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; //@ts-expect-error no typedefs import { fetch as streamingFetch } from 'react-native-fetch-api'; diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 32d208817e..e8a6cad5fc 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -3,7 +3,7 @@ import { ChannelStatus, PokeInterface, Urbit } from '@urbit/http-api'; import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; -import { getInitializedClient, updateInitializedClient } from '../store'; +// import { getInitializedClient, updateInitializedClient } from '../store'; import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); @@ -102,7 +102,7 @@ export const getCurrentUserIsHosted = () => { return client.url.endsWith('tlon.network'); }; -export function configureClient({ +export function internalConfigureClient({ shipName, shipUrl, verbose, @@ -114,12 +114,6 @@ export function configureClient({ onChannelReset, onChannelStatusChange, }: ClientParams) { - const clientInitialized = getInitializedClient(); - if (clientInitialized) { - logger.log('client already initialized, skipping'); - return; - } - logger.log('configuring client', shipName, shipUrl); config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.ship = deSig(shipName); @@ -166,16 +160,13 @@ export function configureClient({ config.client.on('channel-reaped', () => { logger.log('client channel-reaped'); }); - - updateInitializedClient(true); } -export function removeUrbitClient() { +export function internalRemoveClient() { config.client?.delete(); config.cancelFetch?.(); config.client = null; config.subWatchers = {}; - updateInitializedClient(false); } function printEndpoint(endpoint: UrbitEndpoint) { diff --git a/packages/shared/src/store/clientActions.ts b/packages/shared/src/store/clientActions.ts new file mode 100644 index 0000000000..357026eb44 --- /dev/null +++ b/packages/shared/src/store/clientActions.ts @@ -0,0 +1,21 @@ +import * as api from '../api'; +import { createDevLogger } from '../debug'; +import { getInitializedClient, updateInitializedClient } from './session'; + +const logger = createDevLogger('ClientActions', true); + +export function configureClient(params: api.ClientParams) { + const clientInitialized = getInitializedClient(); + if (clientInitialized) { + logger.log('client already initialized, skipping'); + return; + } + + api.internalConfigureClient(params); + updateInitializedClient(true); +} + +export function removeClient() { + api.internalRemoveClient(); + updateInitializedClient(false); +} diff --git a/packages/shared/src/store/index.ts b/packages/shared/src/store/index.ts index 0ef4960fd2..7af001443b 100644 --- a/packages/shared/src/store/index.ts +++ b/packages/shared/src/store/index.ts @@ -15,4 +15,5 @@ export * from './useActivityFetchers'; export * from './session'; export * from './contactActions'; export * from './errorReporting'; +export * from './clientActions'; export * from './lure'; From ced94ed1ea282cc04047d78495097c25e1497527 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 16 Oct 2024 11:28:26 -0400 Subject: [PATCH 067/259] AddGalleryPost: avoid saying "Video" or "Rich" (text) --- packages/ui/src/components/AddGalleryPost.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/AddGalleryPost.tsx b/packages/ui/src/components/AddGalleryPost.tsx index 3d80885fe0..d95bc81530 100644 --- a/packages/ui/src/components/AddGalleryPost.tsx +++ b/packages/ui/src/components/AddGalleryPost.tsx @@ -21,14 +21,14 @@ export default function AddGalleryPost({ const actions = [ { - title: 'Photo or Video', + title: 'Image', action: () => { setShowAddGalleryPost(false); setShowAttachmentSheet(true); }, }, { - title: 'Rich Text', + title: 'Text', action: () => { setShowAddGalleryPost(false); setShowGalleryInput(true); From e7d725a1210ca0d79221b1a08bfd10d2f56c1753 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 16 Oct 2024 11:29:06 -0400 Subject: [PATCH 068/259] remove commented out import --- packages/shared/src/api/urbit.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index e8a6cad5fc..5eb067ceeb 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -3,7 +3,6 @@ import { ChannelStatus, PokeInterface, Urbit } from '@urbit/http-api'; import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; -// import { getInitializedClient, updateInitializedClient } from '../store'; import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); From 66911761926e322fce243b44c968a8ec817a125a Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 12:00:56 -0500 Subject: [PATCH 069/259] don't show deleted posts in galleries or notebooks --- packages/app/features/top/ChannelScreen.tsx | 8 +++++++- packages/ui/src/components/GalleryPost/GalleryPost.tsx | 4 ++++ packages/ui/src/components/NotebookPost/NotebookPost.tsx | 8 +++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index 4ddc106aaf..c4b32053ae 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -198,6 +198,12 @@ export default function ChannelScreen(props: Props) { }), }); + const filteredPosts = useMemo( + () => + channel?.type !== 'chat' ? posts?.filter((p) => !p.isDeleted) : posts, + [posts, channel] + ); + const sendPost = useCallback( async (content: Story, _channelId: string, metadata?: db.PostMetadata) => { if (!channel) { @@ -313,7 +319,7 @@ export default function ChannelScreen(props: Props) { hasNewerPosts={postsQuery.hasPreviousPage} hasOlderPosts={postsQuery.hasNextPage} group={group} - posts={posts} + posts={filteredPosts ?? null} selectedPostId={selectedPostId} goBack={props.navigation.goBack} messageSender={sendPost} diff --git a/packages/ui/src/components/GalleryPost/GalleryPost.tsx b/packages/ui/src/components/GalleryPost/GalleryPost.tsx index 7aa8d4bbe4..9fd32c8d58 100644 --- a/packages/ui/src/components/GalleryPost/GalleryPost.tsx +++ b/packages/ui/src/components/GalleryPost/GalleryPost.tsx @@ -64,6 +64,10 @@ export function GalleryPost({ const handleLongPress = useBoundHandler(post, onLongPress); + if (post.isDeleted) { + return null; + } + return ( - {post.hidden || post.isDeleted ? ( + {post.hidden ? ( - {post.hidden - ? 'You have hidden this post.' - : 'This post has been deleted.'} + You have hidden this post. ) : ( From eb03b8188f6843b96058e3bdb8ea40ea49a22074 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 13:33:03 -0500 Subject: [PATCH 070/259] channels: add ability to leave group channels on mobile --- packages/shared/src/api/channelsApi.ts | 21 +++++++++++++++++++ packages/shared/src/store/channelActions.ts | 18 ++++++++++++++++ .../ui/src/components/ChatOptionsSheet.tsx | 12 ++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/api/channelsApi.ts b/packages/shared/src/api/channelsApi.ts index 83aefdeaa7..7591d2cf3e 100644 --- a/packages/shared/src/api/channelsApi.ts +++ b/packages/shared/src/api/channelsApi.ts @@ -375,3 +375,24 @@ export const searchChannel = async (params: { return { posts, cursor }; }; + +export const leaveChannel = async (channelId: string) => { + return trackedPoke( + { + app: 'channels', + mark: 'channel-action', + json: { + channel: { + nest: channelId, + action: { + leave: null, + }, + }, + }, + }, + { app: 'channels', path: '/v1' }, + (event) => { + return 'leave' in event.response && event.response.leave === channelId; + } + ); +}; diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index e19a8bf04b..f78b64b83d 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -290,3 +290,21 @@ export async function upsertDmChannel({ logger.log(`returning new pending dm`, newDm); return newDm; } + +export async function leaveGroupChannel(channelId: string) { + const channel = await db.getChannel({ id: channelId }); + if (!channel) { + throw new Error('Channel not found'); + } + + // optimistic update + await db.updateChannel({ id: channelId, currentUserIsMember: false }); + + try { + await api.leaveChannel(channelId); + } catch (e) { + console.error('Failed to leave chat channel', e); + // rollback optimistic update + await db.updateChannel({ id: channelId, currentUserIsMember: true }); + } +} diff --git a/packages/ui/src/components/ChatOptionsSheet.tsx b/packages/ui/src/components/ChatOptionsSheet.tsx index ae9973e4b5..f0ea62b55a 100644 --- a/packages/ui/src/components/ChatOptionsSheet.tsx +++ b/packages/ui/src/components/ChatOptionsSheet.tsx @@ -754,7 +754,17 @@ export function ChannelOptions({ onPress: () => { sheetRef.current.setOpen(false); onPressLeave?.(); - store.respondToDMInvite({ channel, accept: false }); + if ( + channel.type === 'dm' || + channel.type === 'groupDm' + ) { + store.respondToDMInvite({ + channel, + accept: false, + }); + } else { + store.leaveGroupChannel(channel.id); + } }, }, ] From be50a80ddef021e7b27c4c5388074c1ae82b73e0 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 16 Oct 2024 15:41:31 -0400 Subject: [PATCH 071/259] onboarding: identify tlon employee in email step --- .../src/screens/Onboarding/SignUpEmailScreen.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx index 03b2689b71..eb833cc622 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx @@ -4,7 +4,11 @@ import { useLureMetadata, useSignupParams, } from '@tloncorp/app/contexts/branch'; -import { trackError, trackOnboardingAction } from '@tloncorp/app/utils/posthog'; +import { + identifyTlonEmployee, + trackError, + trackOnboardingAction, +} from '@tloncorp/app/utils/posthog'; import { Field, KeyboardAvoidingView, @@ -61,6 +65,9 @@ export const SignUpEmailScreen = ({ navigation, route: { params } }: Props) => { }); trackError({ message: 'Ineligible email address' }); } else { + if (email.endsWith('@tlon.io')) { + identifyTlonEmployee(); + } trackOnboardingAction({ actionName: 'Email submitted', email, From 2307cfb83c4bb7b3b102c12b54828e47370ffac3 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 16 Oct 2024 15:38:12 -0500 Subject: [PATCH 072/259] urbit: vendored http-api and improved logged out handling --- packages/app/hooks/useConfigureUrbitClient.ts | 77 +- packages/app/hooks/useHandleLogout.native.ts | 3 +- packages/app/hooks/useHandleLogout.ts | 8 +- packages/shared/package.json | 3 + packages/shared/src/api/urbit.ts | 62 +- packages/shared/src/http-api/Urbit.ts | 795 ++++++++++++++++++ packages/shared/src/http-api/events.ts | 71 ++ .../src/http-api/fetch-event-source/fetch.ts | 202 +++++ .../src/http-api/fetch-event-source/index.ts | 4 + .../src/http-api/fetch-event-source/parse.ts | 217 +++++ packages/shared/src/http-api/index.ts | 4 + packages/shared/src/http-api/types.ts | 211 +++++ packages/shared/src/http-api/utils.ts | 79 ++ pnpm-lock.yaml | 23 +- 14 files changed, 1646 insertions(+), 113 deletions(-) create mode 100644 packages/shared/src/http-api/Urbit.ts create mode 100644 packages/shared/src/http-api/events.ts create mode 100644 packages/shared/src/http-api/fetch-event-source/fetch.ts create mode 100644 packages/shared/src/http-api/fetch-event-source/index.ts create mode 100644 packages/shared/src/http-api/fetch-event-source/parse.ts create mode 100644 packages/shared/src/http-api/index.ts create mode 100644 packages/shared/src/http-api/types.ts create mode 100644 packages/shared/src/http-api/utils.ts diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index be1b0953a2..68998bcf32 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -1,18 +1,7 @@ -import { - createDevLogger, - getSession, - sync, - updateSession, -} from '@tloncorp/shared/dist'; +import { createDevLogger, sync } from '@tloncorp/shared/dist'; import { ClientParams } from '@tloncorp/shared/dist/api'; import { configureClient } from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; -//@ts-expect-error no typedefs -import { fetch as streamingFetch } from 'react-native-fetch-api'; -//@ts-expect-error no typedefs -import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; -//@ts-expect-error no typedefs -import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; import { ENABLED_LOGGERS } from '../constants'; import { useShip } from '../contexts/ship'; @@ -20,47 +9,7 @@ import { getShipAccessCode } from '../lib/hostingApi'; import { resetDb } from '../lib/nativeDb'; import { useHandleLogout } from './useHandleLogout'; -polyfillReadableStream(); -polyfillEncoding(); - -let abortController = new AbortController(); - -const apiFetch: typeof fetch = (input, { ...init } = {}) => { - // Wire our injected AbortController up to the one passed in by the client. - if (init.signal) { - init.signal.onabort = () => { - abortController.abort(); - abortController = new AbortController(); - }; - } - - const headers = new Headers(init.headers); - // The urbit client is inconsistent about sending cookies, sometimes causing - // the server to send back a new, anonymous, cookie, which is sent on all - // subsequent requests and screws everything up. This ensures that explicit - // cookie headers are never set, delegating all cookie handling to the - // native http client. - headers.delete('Cookie'); - headers.delete('cookie'); - const newInit: RequestInit = { - ...init, - headers, - // Avoid setting credentials method for same reason as above. - credentials: undefined, - signal: abortController.signal, - // @ts-expect-error This is used by the SSE polyfill to determine whether - // to stream the request. - reactNative: { textStreaming: true }, - }; - return streamingFetch(input, newInit); -}; - -export const cancelFetch = () => { - abortController.abort(); - abortController = new AbortController(); -}; - -const clientLogger = createDevLogger('configure client', false); +const clientLogger = createDevLogger('configure client', true); export function useConfigureUrbitClient() { const shipInfo = useShip(); @@ -78,24 +27,7 @@ export function useConfigureUrbitClient() { shipName: params?.shipName ?? ship ?? '', shipUrl: params?.shipUrl ?? shipUrl ?? '', verbose: ENABLED_LOGGERS.includes('urbit'), - fetchFn: apiFetch, - cancelFetch, - onReconnect: () => { - const threshold = 5 * 60 * 1000; // 5 minutes - const lastReconnect = getSession()?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } else { - updateSession({ startTime: Date.now() }); - } - }, - onChannelReset: () => { - const threshold = __DEV__ ? 60 * 1000 : 12 * 60 * 60 * 1000; // 12 hours - const lastReconnect = getSession()?.startTime ?? 0; - if (Date.now() - lastReconnect >= threshold) { - sync.handleDiscontinuity(); - } - }, + onQuitOrReset: sync.handleDiscontinuity, onChannelStatusChange: sync.handleChannelStatusChange, getCode: authType === 'self' @@ -116,6 +48,9 @@ export function useConfigureUrbitClient() { return code; }, handleAuthFailure: async () => { + clientLogger.error( + 'Failed to authenticate with ship, redirecting to login' + ); clientLogger.trackError( 'Failed to authenticate with ship, redirecting to login' ); diff --git a/packages/app/hooks/useHandleLogout.native.ts b/packages/app/hooks/useHandleLogout.native.ts index b83f0fec5d..c8b63ba706 100644 --- a/packages/app/hooks/useHandleLogout.native.ts +++ b/packages/app/hooks/useHandleLogout.native.ts @@ -1,5 +1,6 @@ import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; +import * as store from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; @@ -14,7 +15,7 @@ export function useHandleLogout({ resetDb }: { resetDb: () => void }) { const handleLogout = useCallback(async () => { api.queryClient.clear(); - api.removeUrbitClient(); + store.removeClient(); clearShip(); clearShipInfo(); removeHostingToken(); diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index 8486dd5806..c4ddc08fde 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -1,8 +1,6 @@ -import { - createDevLogger, - updateInitializedClient, -} from '@tloncorp/shared/dist'; +import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; +import * as store from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; @@ -21,7 +19,7 @@ export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { const handleLogout = useCallback(async () => { api.queryClient.clear(); - api.removeUrbitClient(); + store.removeClient(); clearShip(); clearShipInfo(); removeHostingToken(); diff --git a/packages/shared/package.json b/packages/shared/package.json index d824111a74..ea36736a84 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -31,7 +31,10 @@ "@urbit/http-api": "3.2.0-dev", "any-ascii": "^0.3.1", "big-integer": "^1.6.52", + "browser-or-node": "^3.0.0", "exponential-backoff": "^3.1.1", + "react-native-fetch-api": "^3.0.0", + "react-native-polyfill-globals": "^3.1.0", "sorted-btree": "^1.8.1" }, "devDependencies": { diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 5eb067ceeb..20ad311b80 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -1,8 +1,8 @@ import { deSig, preSig } from '@urbit/aura'; -import { ChannelStatus, PokeInterface, Urbit } from '@urbit/http-api'; import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; +import { AuthError, ChannelStatus, PokeInterface, Urbit } from '../http-api'; import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); @@ -10,11 +10,7 @@ const logger = createDevLogger('urbit', false); interface Config extends Pick< ClientParams, - | 'getCode' - | 'handleAuthFailure' - | 'shipUrl' - | 'onChannelReset' - | 'cancelFetch' + 'getCode' | 'handleAuthFailure' | 'shipUrl' | 'onQuitOrReset' > { client: Urbit | null; subWatchers: Watchers; @@ -55,12 +51,9 @@ export interface ClientParams { shipName: string; shipUrl: string; verbose?: boolean; - fetchFn?: typeof fetch; - cancelFetch?: () => void; getCode?: () => Promise; handleAuthFailure?: () => void; - onReconnect?: () => void; - onChannelReset?: () => void; + onQuitOrReset?: () => void; onChannelStatusChange?: (status: ChannelStatus) => void; } @@ -69,7 +62,7 @@ const config: Config = { shipUrl: '', subWatchers: {}, pendingAuth: null, - onChannelReset: undefined, + onQuitOrReset: undefined, getCode: undefined, handleAuthFailure: undefined, }; @@ -105,40 +98,26 @@ export function internalConfigureClient({ shipName, shipUrl, verbose, - fetchFn, - cancelFetch, getCode, handleAuthFailure, - onReconnect, - onChannelReset, + onQuitOrReset, onChannelStatusChange, }: ClientParams) { logger.log('configuring client', shipName, shipUrl); - config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); + config.client = config.client || new Urbit(shipUrl, '', ''); config.client.ship = deSig(shipName); config.client.our = preSig(shipName); config.client.verbose = verbose; config.shipUrl = shipUrl; - config.cancelFetch = cancelFetch; - config.onChannelReset = onChannelReset; + config.onQuitOrReset = onQuitOrReset; config.getCode = getCode; config.handleAuthFailure = handleAuthFailure; config.subWatchers = {}; - config.client.onReconnect = () => { - logger.log('client reconnected'); - onChannelStatusChange?.('reconnected'); - onReconnect?.(); - }; - - config.client.onRetry = () => { - logger.log('client retrying'); - onChannelStatusChange?.('reconnecting'); - }; - // the below event handlers will only fire if verbose is set to true config.client.on('status-update', (event) => { logger.log('status-update', event); + onChannelStatusChange?.(event.status); }); config.client.on('fact', (fact) => { @@ -150,6 +129,7 @@ export function internalConfigureClient({ config.client.on('seamless-reset', () => { logger.log('client seamless-reset'); + config.onQuitOrReset?.(); }); config.client.on('error', (error) => { @@ -163,7 +143,6 @@ export function internalConfigureClient({ export function internalRemoveClient() { config.client?.delete(); - config.cancelFetch?.(); config.client = null; config.subWatchers = {}; } @@ -214,7 +193,7 @@ export async function subscribe( }, quit: () => { logger.log('subscription quit on', printEndpoint(endpoint)); - config.onChannelReset?.(); + config.onQuitOrReset?.(); }, err: (error, id) => { logger.error(`subscribe error on ${printEndpoint(endpoint)}:`, error); @@ -232,6 +211,10 @@ export async function subscribe( const retry = async (err: any) => { logger.error('bad subscribe', printEndpoint(endpoint), err); + if (!(err instanceof AuthError)) { + throw err; + } + config.pendingAuth = reauth(); return doSub(); }; @@ -258,6 +241,10 @@ export async function subscribeOnce( return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); } catch (err) { logger.error('bad subscribeOnce', printEndpoint(endpoint), err); + if (!(err instanceof AuthError)) { + throw err; + } + await reauth(); return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); } @@ -274,8 +261,10 @@ export async function unsubscribe(id: number) { return config.client.unsubscribe(id); } catch (err) { logger.error('bad unsubscribe', id, err); - await reauth(); - return config.client.unsubscribe(id); + if (err instanceof AuthError) { + await reauth(); + return config.client.unsubscribe(id); + } } } @@ -297,6 +286,10 @@ export async function poke({ app, mark, json }: PokeParams) { }; const retry = async (err: any) => { logger.log('bad poke', app, mark, json, err); + if (!(err instanceof AuthError)) { + throw err; + } + await reauth(); return doPoke(); }; @@ -368,8 +361,9 @@ export async function scry({ app, path }: { app: string; path: string }) { async function reauth() { if (!config.getCode) { - console.warn('No getCode function provided for auth'); + logger.log('No getCode function provided for auth'); if (config.handleAuthFailure) { + logger.log('calling auth failure handler'); return config.handleAuthFailure(); } diff --git a/packages/shared/src/http-api/Urbit.ts b/packages/shared/src/http-api/Urbit.ts new file mode 100644 index 0000000000..a95f6e9b9e --- /dev/null +++ b/packages/shared/src/http-api/Urbit.ts @@ -0,0 +1,795 @@ +import { isBrowser } from 'browser-or-node'; +//@ts-expect-error no typedefs +import { fetch as streamingFetch } from 'react-native-fetch-api'; +//@ts-expect-error no typedefs +import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; +//@ts-expect-error no typedefs +import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; + +import { UrbitHttpApiEvent, UrbitHttpApiEventType } from './events'; +import { EventSourceMessage, fetchEventSource } from './fetch-event-source'; +import { + Ack, + AuthError, + AuthenticationInterface, + FatalError, + Message, + PokeHandlers, + PokeInterface, + ReapError, + SSEOptions, + Scry, + SubscriptionRequestInterface, + Thread, + headers, +} from './types'; +import EventEmitter, { hexString } from './utils'; + +polyfillReadableStream(); +polyfillEncoding(); + +let abortController = new AbortController(); + +/** + * A class for interacting with an urbit ship, given its URL and code + */ +export class Urbit { + /** + * Event emitter for debugging, see events.ts for full list of events + */ + private emitter = new EventEmitter(); + + /** + * UID will be used for the channel: The current unix time plus a random hex string + */ + private uid: string = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; + + /** + * lastEventId is an auto-updated index of which events have been *sent* over this channel. + * lastHeardEventId is the latest event we have heard back about. + * lastAcknowledgedEventId is the latest event we have sent an ack for. + */ + private lastEventId: number = 0; + private lastHeardEventId: number = -1; + private lastAcknowledgedEventId: number = -1; + + /** + * SSE Client is null for now; we don't want to start polling until it the channel exists + */ + private sseClientInitialized: boolean = false; + + /** + * Cookie gets set when we log in. + */ + cookie?: string; + + /** + * A registry of requestId to successFunc/failureFunc + * + * These functions are registered during a +poke and are executed + * in the onServerEvent()/onServerError() callbacks. Only one of + * the functions will be called, and the outstanding poke will be + * removed after calling the success or failure function. + */ + + private outstandingPokes: Map = new Map(); + + /** + * A registry of requestId to subscription functions. + * + * These functions are registered during a +subscribe and are + * executed in the onServerEvent()/onServerError() callbacks. The + * event function will be called whenever a new piece of data on this + * subscription is available, which may be 0, 1, or many times. The + * disconnect function may be called exactly once. + */ + private outstandingSubscriptions: Map = + new Map(); + + /** + * Identity of the ship we're connected to + */ + ship?: string | null; + + /** + * Our identity, with which we are authenticated into the ship + */ + our?: string | null; + + /** + * If verbose, logs output eagerly. + */ + verbose?: boolean; + + /** + * number of consecutive errors in connecting to the eventsource + */ + private errorCount = 0; + + /** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */ + private get channelUrl(): string { + return `${this.url}/~/channel/${this.uid}`; + } + + private get fetchOptions(): any { + const headers: headers = { + 'Content-Type': 'application/json', + }; + + return { + credentials: isBrowser ? 'include' : undefined, + accept: '*', + headers, + signal: abortController.signal, + reactNative: { textStreaming: true }, + }; + } + + /** + * Constructs a new Urbit connection. + * + * @param url The URL (with protocol and port) of the ship to be accessed. If + * the airlock is running in a webpage served by the ship, this should just + * be the empty string. + * @param code The access code for the ship at that address + */ + constructor( + public url: string, + public code?: string, + public desk?: string + ) { + if (isBrowser) { + window.addEventListener('beforeunload', this.delete); + } + return this; + } + + /** + * All-in-one hook-me-up. + * + * Given a ship, url, and code, this returns an airlock connection + * that is ready to go. It `|hi`s itself to create the channel, + * then opens the channel via EventSource. + * + */ + //TODO rename this to connect() and only do constructor & event source setup. + // that way it can be used with the assumption that you're already + // authenticated. + static async authenticate({ + ship, + url, + code, + verbose = false, + }: AuthenticationInterface) { + const airlock = new Urbit( + url.startsWith('http') ? url : `http://${url}`, + code + ); + airlock.verbose = verbose; + airlock.ship = ship; + await airlock.connect(); + await airlock.poke({ + app: 'hood', + mark: 'helm-hi', + json: 'opening airlock', + }); + await airlock.eventSource(); + return airlock; + } + + private emit( + event: T, + data: UrbitHttpApiEvent[T] + ) { + this.emitter.emit(event, data); + } + + on( + event: T, + callback: (data: UrbitHttpApiEvent[T]) => void + ): void { + this.emitter.on(event, callback); + + this.verbose && console.log(event, 'listening active'); + if (event === 'init') { + this.emitter.emit(event, { + uid: this.uid, + subscriptions: [...this.outstandingSubscriptions.entries()].map( + ([k, v]) => ({ id: k, app: v.app, path: v.path }) + ), + }); + } + } + + /** + * Gets the name of the ship accessible at this.url and stores it to this.ship + * + */ + async getShipName(): Promise { + if (this.ship) { + return Promise.resolve(); + } + + const nameResp = await streamingFetch(`${this.url}/~/host`, { + method: 'get', + credentials: 'include', + }); + const name = await nameResp.text(); + this.ship = name.substring(1); + } + + /** + * Gets the name of the ship accessible at this.url and stores it to this.ship + * + */ + async getOurName(): Promise { + if (this.our) { + return Promise.resolve(); + } + + const nameResp = await streamingFetch(`${this.url}/~/name`, { + method: 'get', + credentials: 'include', + }); + const name = await nameResp.text(); + this.our = name.substring(1); + } + + /** + * Connects to the Urbit ship. Nothing can be done until this is called. + * That's why we roll it into this.authenticate + * TODO as of urbit/urbit#6561, this is no longer true, and we are able + * to interact with the ship using a guest identity. + */ + //TODO rename to authenticate() and call connect() at the end + async connect(): Promise { + if (this.verbose) { + console.log( + `password=${this.code} `, + isBrowser + ? 'Connecting in browser context at ' + `${this.url}/~/login` + : 'Connecting from node context' + ); + } + return streamingFetch(`${this.url}/~/login`, { + method: 'post', + body: `password=${this.code}`, + credentials: 'include', + }).then(async (response: Response) => { + if (this.verbose) { + console.log('Received authentication response', response); + } + if (response.status >= 200 && response.status < 300) { + throw new Error('Login failed with status ' + response.status); + } + const cookie = response.headers.get('set-cookie'); + if (!this.ship && cookie) { + this.ship = new RegExp(/urbauth-~([\w-]+)/).exec(cookie)?.[1]; + } + if (!isBrowser) { + this.cookie = cookie || undefined; + } + this.getShipName(); + this.getOurName(); + }); + } + + /** + * Initializes the SSE pipe for the appropriate channel. + */ + async eventSource(): Promise { + if (this.sseClientInitialized) { + return Promise.resolve(); + } + if (this.lastEventId === 0) { + this.emit('status-update', { status: 'opening' }); + // Can't receive events until the channel is open, + // so poke and open then + await this.poke({ + app: 'hood', + mark: 'helm-hi', + json: 'Opening API channel', + }); + return; + } + this.sseClientInitialized = true; + return new Promise((resolve, reject) => { + const sseOptions: SSEOptions = { + headers: {}, + }; + if (isBrowser) { + sseOptions.withCredentials = true; + } + fetchEventSource(this.channelUrl, { + ...this.fetchOptions, + openWhenHidden: true, + responseTimeout: 25000, + fetch: streamingFetch, + onopen: async (response, isReconnect) => { + if (this.verbose) { + console.log('Opened eventsource', response); + } + if (response.ok) { + this.errorCount = 0; + this.emit('status-update', { + status: isReconnect ? 'reconnected' : 'active', + }); + resolve(); + return; // everything's good + } else { + const err = new Error('failed to open eventsource'); + reject(err); + } + }, + onmessage: (event: EventSourceMessage) => { + if (this.verbose) { + console.log('Received SSE: ', event); + } + if (!event.id) return; + const eventId = parseInt(event.id, 10); + this.emit('fact', { + id: eventId, + data: event.data, + time: Date.now(), + }); + if (eventId <= this.lastHeardEventId) { + if (this.verbose) { + console.log('dropping old or out-of-order event', { + eventId, + lastHeard: this.lastHeardEventId, + }); + } + return; + } + this.lastHeardEventId = eventId; + this.emit('id-update', { lastHeard: this.lastHeardEventId }); + if (eventId - this.lastAcknowledgedEventId > 20) { + this.ack(eventId); + } + + if (event.data && JSON.parse(event.data)) { + const data: any = JSON.parse(event.data); + + if ( + data.response === 'poke' && + this.outstandingPokes.has(data.id) + ) { + const funcs = this.outstandingPokes.get(data.id); + if ('ok' in data && funcs) { + funcs.onSuccess?.(); + } else if ('err' in data && funcs) { + console.error(data.err); + funcs.onError?.(data.err); + } else { + console.error('Invalid poke response', data); + } + this.outstandingPokes.delete(data.id); + } else if ( + data.response === 'subscribe' && + this.outstandingSubscriptions.has(data.id) + ) { + const funcs = this.outstandingSubscriptions.get(data.id); + if ('err' in data && funcs) { + console.error(data.err); + funcs.err?.(data.err, data.id); + this.outstandingSubscriptions.delete(data.id); + } + } else if ( + data.response === 'diff' && + this.outstandingSubscriptions.has(data.id) + ) { + const funcs = this.outstandingSubscriptions.get(data.id); + try { + funcs?.event?.(data.json, data.mark ?? 'json', data.id); + } catch (e) { + console.error('Failed to call subscription event callback', e); + } + } else if ( + data.response === 'quit' && + this.outstandingSubscriptions.has(data.id) + ) { + const sub = this.outstandingSubscriptions.get(data.id); + sub?.quit?.(data); + this.outstandingSubscriptions.delete(data.id); + this.emit('subscription', { + id: data.id, + status: 'close', + }); + if (sub?.resubOnQuit) { + this.subscribe(sub); + } + } else if (this.verbose) { + console.log([...this.outstandingSubscriptions.keys()]); + console.log('Unrecognized response', data); + } + } + }, + onerror: (error) => { + this.errorCount++; + this.emit('error', { + time: Date.now(), + msg: JSON.stringify(error), + error, + }); + if (error instanceof ReapError) { + this.emit('channel-reaped', { time: Date.now() }); + this.seamlessReset(); + return; + } + if (!(error instanceof FatalError)) { + this.emit('status-update', { status: 'reconnecting' }); + return Math.min(5000, Math.pow(2, this.errorCount - 1) * 750); + } + this.emit('status-update', { status: 'errored' }); + throw error; + }, + onclose: () => { + console.log('e'); + throw new Error('Ship unexpectedly closed the connection'); + }, + }); + }); + } + + /** + * Reset airlock, abandoning current subscriptions and wiping state + * + */ + reset() { + if (this.verbose) { + console.log('resetting'); + } + this.delete(); + this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; + this.emit('reset', { uid: this.uid }); + this.lastEventId = 0; + this.lastHeardEventId = -1; + this.lastAcknowledgedEventId = -1; + this.outstandingSubscriptions = new Map(); + this.outstandingPokes = new Map(); + this.sseClientInitialized = false; + } + + private seamlessReset() { + // called if a channel was reaped by %eyre before we reconnected + // so we have to make a new channel. + this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; + this.emit('seamless-reset', { uid: this.uid }); + this.emit('status-update', { status: 'initial' }); + this.sseClientInitialized = false; + this.lastEventId = 0; + this.lastHeardEventId = -1; + this.lastAcknowledgedEventId = -1; + const oldSubs = [...this.outstandingSubscriptions.entries()]; + this.outstandingSubscriptions = new Map(); + oldSubs.forEach(([id, sub]) => { + sub.quit?.({ + id, + response: 'quit', + }); + this.emit('subscription', { + id, + status: 'close', + }); + + if (sub.resubOnQuit) { + this.subscribe(sub); + } + }); + + this.outstandingPokes.forEach((poke, id) => { + poke.onError?.('Channel was reaped'); + }); + this.outstandingPokes = new Map(); + } + + /** + * Autoincrements the next event ID for the appropriate channel. + */ + private getEventId(): number { + this.lastEventId += 1; + this.emit('id-update', { current: this.lastEventId }); + return this.lastEventId; + } + + /** + * Acknowledges an event. + * + * @param eventId The event to acknowledge. + */ + private async ack(eventId: number): Promise { + this.lastAcknowledgedEventId = eventId; + this.emit('id-update', { lastAcknowledged: eventId }); + const message: Ack = { + action: 'ack', + 'event-id': eventId, + }; + await this.sendJSONtoChannel(message); + return eventId; + } + + private async sendJSONtoChannel(...json: (Message | Ack)[]): Promise { + const response = await streamingFetch(this.channelUrl, { + ...this.fetchOptions, + method: 'PUT', + body: JSON.stringify(json), + }); + if (!response.ok) { + throw new Error('Failed to PUT channel'); + } + if (!this.sseClientInitialized) { + if (this.verbose) { + console.log('initializing event source'); + } + await Promise.all([this.getOurName(), this.getShipName()]); + + if (this.our !== this.ship) { + console.log('our name does not match ship name'); + throw new AuthError('invalid session'); + } + + await this.eventSource(); + } + } + + /** + * Creates a subscription, waits for a fact and then unsubscribes + * + * @param app Name of gall agent to subscribe to + * @param path Path to subscribe to + * @param timeout Optional timeout before ending subscription + * + * @returns The first fact on the subcription + */ + async subscribeOnce(app: string, path: string, timeout?: number) { + return new Promise((resolve, reject) => { + let done = false; + const quit = () => { + if (!done) { + reject('quit'); + } + }; + const event = (e: T, mark: string, id: number) => { + if (!done) { + resolve(e); + this.unsubscribe(id); + } + }; + const request = { + app, + path, + resubOnQuit: false, + event, + err: reject, + quit, + }; + + this.subscribe(request).then((subId) => { + if (timeout) { + setTimeout(() => { + if (!done) { + done = true; + reject('timeout'); + this.unsubscribe(subId); + } + }, timeout); + } + }); + }); + } + + /** + * Pokes a ship with data. + * + * @param app The app to poke + * @param mark The mark of the data being sent + * @param json The data to send + */ + async poke(params: PokeInterface): Promise { + const { app, mark, json, ship, onSuccess, onError } = { + onSuccess: () => {}, + onError: () => {}, + ship: this.ship, + ...params, + }; + + if (this.lastEventId === 0) { + this.emit('status-update', { status: 'opening' }); + } + + const message: Message = { + id: this.getEventId(), + action: 'poke', + ship, + app, + mark, + json, + }; + this.outstandingPokes.set(message.id, { + onSuccess: () => { + onSuccess(); + }, + onError: (err) => { + onError(err); + }, + }); + await this.sendJSONtoChannel(message); + return message.id; + } + + /** + * Subscribes to a path on an app on a ship. + * + * + * @param app The app to subsribe to + * @param path The path to which to subscribe + * @param handlers Handlers to deal with various events of the subscription + */ + async subscribe(params: SubscriptionRequestInterface): Promise { + const { app, path, ship, resubOnQuit, err, event, quit } = { + err: () => {}, + event: () => {}, + quit: () => {}, + ship: this.ship, + resubOnQuit: true, + ...params, + }; + + if (this.lastEventId === 0) { + this.emit('status-update', { status: 'opening' }); + } + + const message: Message = { + id: this.getEventId(), + action: 'subscribe', + ship, + app, + path, + }; + + this.outstandingSubscriptions.set(message.id, { + app, + path, + resubOnQuit, + err, + event, + quit, + }); + + this.emit('subscription', { + id: message.id, + app, + path, + status: 'open', + }); + + await this.sendJSONtoChannel(message); + + return message.id; + } + + /** + * Unsubscribes to a given subscription. + * + * @param subscription + */ + async unsubscribe(subscription: number) { + return this.sendJSONtoChannel({ + id: this.getEventId(), + action: 'unsubscribe', + subscription, + }).then(() => { + this.emit('subscription', { + id: subscription, + status: 'close', + }); + this.outstandingSubscriptions.delete(subscription); + }); + } + + abort() { + abortController.abort(); + abortController = new AbortController(); + } + + /** + * Deletes the connection to a channel. + */ + async delete() { + this.abort(); + const body = JSON.stringify([ + { + id: this.getEventId(), + action: 'delete', + }, + ]); + if (isBrowser) { + navigator.sendBeacon(this.channelUrl, body); + } else { + const response = await streamingFetch(this.channelUrl, { + ...this.fetchOptions, + method: 'POST', + body: body, + }); + if (!response.ok) { + throw new Error('Failed to DELETE channel in node context'); + } + } + } + + /** + * Scry into an gall agent at a path + * + * @typeParam T - Type of the scry result + * + * @remarks + * + * Equivalent to + * ```hoon + * .^(T %gx /(scot %p our)/[app]/(scot %da now)/[path]/json) + * ``` + * The returned cage must have a conversion to JSON for the scry to succeed + * + * @param params The scry request + * @returns The scry result + */ + async scry(params: Scry): Promise { + const { app, path } = params; + const response = await streamingFetch( + `${this.url}/~/scry/${app}${path}.json`, + this.fetchOptions + ); + + if (!response.ok) { + return Promise.reject(response); + } + + return await response.json(); + } + + /** + * Run a thread + * + * + * @param inputMark The mark of the data being sent + * @param outputMark The mark of the data being returned + * @param threadName The thread to run + * @param body The data to send to the thread + * @returns The return value of the thread + */ + async thread(params: Thread): Promise { + const { + inputMark, + outputMark, + threadName, + body, + desk = this.desk, + } = params; + if (!desk) { + throw new Error('Must supply desk to run thread from'); + } + const res = await streamingFetch( + `${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`, + { + ...this.fetchOptions, + method: 'POST', + body: JSON.stringify(body), + } + ); + + return res.json(); + } + + /** + * Utility function to connect to a ship that has its *.arvo.network domain configured. + * + * @param name Name of the ship e.g. zod + * @param code Code to log in + */ + static async onArvoNetwork(ship: string, code: string): Promise { + const url = `https://${ship}.arvo.network`; + return await Urbit.authenticate({ ship, url, code }); + } +} + +export default Urbit; diff --git a/packages/shared/src/http-api/events.ts b/packages/shared/src/http-api/events.ts new file mode 100644 index 0000000000..5659ef6b0a --- /dev/null +++ b/packages/shared/src/http-api/events.ts @@ -0,0 +1,71 @@ +export type ChannelStatus = + | 'initial' + | 'opening' + | 'active' + | 'reconnecting' + | 'reconnected' + | 'errored'; + +export interface StatusUpdateEvent { + status: ChannelStatus; +} + +export interface FactEvent { + id: number; + time: number; + data: any; +} + +export interface SubscriptionEvent { + id: number; + app?: string; + path?: string; + status: 'open' | 'close'; +} + +export interface ErrorEvent { + time: number; + msg: string; + error: any; +} + +export type IdUpdateEvent = Partial<{ + current: number; + lastHeard: number; + lastAcknowledged: number; +}>; + +export interface ResetEvent { + uid: string; +} + +export interface InitEvent extends ResetEvent { + subscriptions: Omit[]; +} + +export interface ChannelReapedEvent { + time: number; +} + +export type UrbitHttpApiEvent = { + subscription: SubscriptionEvent; + 'status-update': StatusUpdateEvent; + 'id-update': IdUpdateEvent; + fact: FactEvent; + error: ErrorEvent; + reset: ResetEvent; + 'seamless-reset': ResetEvent; + 'channel-reaped': ChannelReapedEvent; + init: InitEvent; +}; + +export type UrbitHttpApiEventType = + | 'subscription' + | 'status-update' + | 'id-update' + | 'fact' + | 'error' + | 'reset' + | 'seamless-reset' + | 'channel-reaped' + | 'init'; diff --git a/packages/shared/src/http-api/fetch-event-source/fetch.ts b/packages/shared/src/http-api/fetch-event-source/fetch.ts new file mode 100644 index 0000000000..0c6f166606 --- /dev/null +++ b/packages/shared/src/http-api/fetch-event-source/fetch.ts @@ -0,0 +1,202 @@ +import { FatalError, ReapError } from '../types'; +import { EventSourceMessage, getBytes, getLines, getMessages } from './parse'; + +export const EventStreamContentType = 'text/event-stream'; + +const DefaultRetryInterval = 1000; +const LastEventId = 'last-event-id'; + +export interface FetchEventSourceInit extends RequestInit { + /** + * The request headers. FetchEventSource only supports the Record format. + */ + headers?: Record; + + /** + * Called when a response is received. Use this to validate that the response + * actually matches what you expect (and throw if it doesn't.) If not provided, + * will default to a basic validation to ensure the content-type is text/event-stream. + */ + onopen?: (response: Response, reconnection: boolean) => Promise; + + /** + * Called when a message is received. NOTE: Unlike the default browser + * EventSource.onmessage, this callback is called for _all_ events, + * even ones with a custom `event` field. + */ + onmessage?: (ev: EventSourceMessage) => void; + + /** + * Called when a response finishes. If you don't expect the server to kill + * the connection, you can throw an exception here and retry using onerror. + */ + onclose?: () => void; + + /** + * Called when there is any error making the request / processing messages / + * handling callbacks etc. Use this to control the retry strategy: if the + * error is fatal, rethrow the error inside the callback to stop the entire + * operation. Otherwise, you can return an interval (in milliseconds) after + * which the request will automatically retry (with the last-event-id). + * If this callback is not specified, or it returns undefined, fetchEventSource + * will treat every error as retriable and will try again after 1 second. + */ + onerror?: (err: any) => number | null | undefined | void; + + /** + * If true, will keep the request open even if the document is hidden. + * By default, fetchEventSource will close the request and reopen it + * automatically when the document becomes visible again. + */ + openWhenHidden?: boolean; + + /** The Fetch function to use. Defaults to window.fetch */ + fetch?: typeof fetch; + + /** How many millisedonds to wait for bytes before timing out */ + responseTimeout?: number; +} + +export function fetchEventSource( + input: RequestInfo, + { + signal: inputSignal, + headers: inputHeaders, + onopen: inputOnOpen, + onmessage, + onclose, + onerror, + openWhenHidden, + fetch: inputFetch, + responseTimeout, + ...rest + }: FetchEventSourceInit +) { + return new Promise((resolve, reject) => { + // make a copy of the input headers since we may modify it below: + const headers = { ...inputHeaders }; + if (!headers.accept) { + headers.accept = EventStreamContentType; + } + + let curRequestController: AbortController; + function onVisibilityChange() { + curRequestController.abort(); // close existing request on every visibility change + if (!document.hidden) { + create(); // page is now visible again, recreate request. + } + } + + if (typeof document !== 'undefined' && !openWhenHidden) { + document.addEventListener('visibilitychange', onVisibilityChange); + } + + let retryInterval = DefaultRetryInterval; + let retryTimer: ReturnType; + function dispose() { + if (typeof document !== 'undefined' && !openWhenHidden) { + document.removeEventListener('visibilitychange', onVisibilityChange); + } + clearTimeout(retryTimer); + curRequestController.abort(); + } + + // if the incoming signal aborts, dispose resources and resolve: + inputSignal?.addEventListener('abort', () => { + dispose(); + resolve(); // don't waste time constructing/logging errors + }); + + const fetchFn = inputFetch ?? fetch; + const onopen = inputOnOpen ?? defaultOnOpen; + let isReconnect = false; + async function create() { + curRequestController = new AbortController(); + try { + const response = (await Promise.race([ + fetchFn(input, { + ...rest, + headers, + signal: curRequestController.signal, + }), + new Promise((_, reject) => { + setTimeout( + () => reject(new Error('fetch timed out')), + responseTimeout + ); + }), + ])) as Response; + + if (response.status === 404) { + onerror?.(new ReapError('Channel reaped')); + dispose(); + resolve(); + return; + } + + if (response.status < 200 || response.status >= 300) { + throw new Error(`Invalid server response: ${response.status}`); + } + + await onopen(response, isReconnect); + // reset reconnect status + if (isReconnect) { + isReconnect = false; + } + + await getBytes( + response.body!, + getLines( + getMessages( + onmessage, + (id) => { + if (id) { + // store the id and send it back on the next retry: + headers[LastEventId] = id; + } else { + // don't send the last-event-id header anymore: + delete headers[LastEventId]; + } + }, + (retry) => { + retryInterval = retry; + } + ) + ), + responseTimeout + ); + + onclose?.(); + dispose(); + resolve(); + } catch (err) { + if (!curRequestController.signal.aborted) { + // if we haven't aborted the request ourselves: + try { + isReconnect = true; + // check if we need to retry: + const interval: any = onerror?.(err) ?? retryInterval; + clearTimeout(retryTimer); + curRequestController.abort(); + retryTimer = setTimeout(create, interval); + } catch (innerErr) { + // we should not retry anymore: + dispose(); + reject(innerErr); + } + } + } + } + + create(); + }); +} + +function defaultOnOpen(response: Response) { + const contentType = response.headers.get('content-type'); + if (!contentType?.startsWith(EventStreamContentType)) { + throw new Error( + `Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}` + ); + } +} diff --git a/packages/shared/src/http-api/fetch-event-source/index.ts b/packages/shared/src/http-api/fetch-event-source/index.ts new file mode 100644 index 0000000000..070243f734 --- /dev/null +++ b/packages/shared/src/http-api/fetch-event-source/index.ts @@ -0,0 +1,4 @@ +// copied from https://github.com/gfortaine/fetch-event-source with added modifications +export { fetchEventSource, EventStreamContentType } from './fetch'; +export type { FetchEventSourceInit } from './fetch'; +export type { EventSourceMessage } from './parse'; diff --git a/packages/shared/src/http-api/fetch-event-source/parse.ts b/packages/shared/src/http-api/fetch-event-source/parse.ts new file mode 100644 index 0000000000..a500da6aec --- /dev/null +++ b/packages/shared/src/http-api/fetch-event-source/parse.ts @@ -0,0 +1,217 @@ +/** + * Represents a message sent in an event stream + * https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format + */ +export interface EventSourceMessage { + /** The event ID to set the EventSource object's last event ID value. */ + id: string; + /** A string identifying the type of event described. */ + event: string; + /** The event data */ + data: string; + /** The reconnection interval (in milliseconds) to wait before retrying the connection */ + retry?: number; +} + +/** + * Converts a ReadableStream into a callback pattern. + * @param stream The input ReadableStream. + * @param onChunk A function that will be called on each new byte chunk in the stream. + * @returns {Promise} A promise that will be resolved when the stream closes. + */ +export async function getBytes( + stream: ReadableStream, + onChunk: (arr: Uint8Array) => void, + responseTimeout?: number +) { + const reader = stream.getReader(); + let result: ReadableStreamReadResult = { + done: false, + value: new Uint8Array(), + }; + + while (result && !result.done) { + result = await Promise.race([ + reader.read(), + new Promise>((_, reject) => { + setTimeout( + () => reject(new Error('getBytes timed out')), + responseTimeout + ); + }), + ]); + + if (!result.value) { + // empty chunk, skip it + console.warn('Empty chunk received from server'); + continue; + } + + try { + onChunk(result.value); + } catch (err) { + console.error('Error processing chunk:', err); + } + } +} + +const enum ControlChars { + NewLine = 10, + CarriageReturn = 13, + Space = 32, + Colon = 58, +} + +/** + * Parses arbitary byte chunks into EventSource line buffers. + * Each line should be of the format "field: value" and ends with \r, \n, or \r\n. + * @param onLine A function that will be called on each new EventSource line. + * @returns A function that should be called for each incoming byte chunk. + */ +export function getLines( + onLine: (line: Uint8Array, fieldLength: number) => void +) { + let buffer: Uint8Array | undefined; + let position: number; // current read position + let fieldLength: number; // length of the `field` portion of the line + let discardTrailingNewline = false; + + // return a function that can process each incoming byte chunk: + return function onChunk(arr: Uint8Array) { + if (buffer === undefined) { + buffer = arr; + position = 0; + fieldLength = -1; + } else { + // we're still parsing the old line. Append the new bytes into buffer: + buffer = concat(buffer, arr); + } + + const bufLength = buffer.length; + let lineStart = 0; // index where the current line starts + while (position < bufLength) { + if (discardTrailingNewline) { + if (buffer[position] === ControlChars.NewLine) { + lineStart = ++position; // skip to next char + } + + discardTrailingNewline = false; + } + + // start looking forward till the end of line: + let lineEnd = -1; // index of the \r or \n char + for (; position < bufLength && lineEnd === -1; ++position) { + switch (buffer[position]) { + case ControlChars.Colon: + if (fieldLength === -1) { + // first colon in line + fieldLength = position - lineStart; + } + break; + case ControlChars.CarriageReturn: + discardTrailingNewline = true; + // eslint-disable-next-line no-fallthrough + case ControlChars.NewLine: + lineEnd = position; + break; + } + } + + if (lineEnd === -1) { + // We reached the end of the buffer but the line hasn't ended. + // Wait for the next arr and then continue parsing: + break; + } + + // we've reached the line end, send it out: + onLine(buffer.subarray(lineStart, lineEnd), fieldLength); + lineStart = position; // we're now on the next line + fieldLength = -1; + } + + if (lineStart === bufLength) { + buffer = undefined; // we've finished reading it + } else if (lineStart !== 0) { + // Create a new view into buffer beginning at lineStart so we don't + // need to copy over the previous lines when we get the new arr: + buffer = buffer.subarray(lineStart); + position -= lineStart; + } + }; +} + +/** + * Parses line buffers into EventSourceMessages. + * @param onId A function that will be called on each `id` field. + * @param onRetry A function that will be called on each `retry` field. + * @param onMessage A function that will be called on each message. + * @returns A function that should be called for each incoming line buffer. + */ +export function getMessages( + onMessage?: (msg: EventSourceMessage) => void, + onId?: (id: string) => void, + onRetry?: (retry: number) => void +) { + let message = newMessage(); + const decoder = new TextDecoder(); + + // return a function that can process each incoming line buffer: + return function onLine(line: Uint8Array, fieldLength: number) { + if (line.length === 0) { + // empty line denotes end of message. Trigger the callback and start a new message: + onMessage?.(message); + message = newMessage(); + } else if (fieldLength > 0) { + // exclude comments and lines with no values + // line is of format ":" or ": " + // https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation + const field = decoder.decode(line.subarray(0, fieldLength)); + const valueOffset = + fieldLength + (line[fieldLength + 1] === ControlChars.Space ? 2 : 1); + const value = decoder.decode(line.subarray(valueOffset)); + + switch (field) { + case 'data': + // if this message already has data, append the new value to the old. + // otherwise, just set to the new value: + message.data = message.data ? message.data + '\n' + value : value; // otherwise, + break; + case 'event': + message.event = value; + break; + case 'id': + message = newMessage(); + onId?.((message.id = value)); + break; + case 'retry': + // eslint-disable-next-line no-case-declarations + const retry = parseInt(value, 10); + if (!isNaN(retry)) { + // per spec, ignore non-integers + onRetry?.((message.retry = retry)); + } + break; + } + } + }; +} + +function concat(a: Uint8Array, b: Uint8Array) { + const res = new Uint8Array(a.length + b.length); + res.set(a); + res.set(b, a.length); + return res; +} + +function newMessage(): EventSourceMessage { + // data, event, and id must be initialized to empty strings: + // https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation + // retry should be initialized to undefined so we return a consistent shape + // to the js engine all the time: https://mathiasbynens.be/notes/shapes-ics#takeaways + return { + data: '', + event: '', + id: '', + retry: undefined, + }; +} diff --git a/packages/shared/src/http-api/index.ts b/packages/shared/src/http-api/index.ts new file mode 100644 index 0000000000..4746d8874f --- /dev/null +++ b/packages/shared/src/http-api/index.ts @@ -0,0 +1,4 @@ +export * from './types'; +export * from './events'; +import { Urbit } from './Urbit'; +export { Urbit as default, Urbit }; diff --git a/packages/shared/src/http-api/types.ts b/packages/shared/src/http-api/types.ts new file mode 100644 index 0000000000..d79337d83d --- /dev/null +++ b/packages/shared/src/http-api/types.ts @@ -0,0 +1,211 @@ +/** + * An urbit style path, rendered as a Javascript string + * @example + * `"/updates"` + */ +export type Path = string; + +/** + * @p including leading sig, rendered as a string + * + * @example + * ```typescript + * "~sampel-palnet" + * ``` + * + */ +export type Patp = string; + +/** + * @p not including leading sig, rendered as a string + * + * @example + * ```typescript + * "sampel-palnet" + * ``` + * + */ +export type PatpNoSig = string; + +/** + * The name of a clay mark, as a string + * + * @example + * ```typescript + * "graph-update" + * ``` + */ +export type Mark = string; + +/** + * The name of a gall agent, as a string + * + * @example + * + * ```typescript + * "graph-store" + * ``` + */ +export type GallAgent = string; + +/** + * Description of an outgoing poke + * + * @typeParam Action - Typescript type of the data being poked + */ +export interface Poke { + /** + * Ship to poke. If left empty, the api lib will populate it with the ship that it is connected to. + * + * @remarks + * + * This should always be the ship that you are connected to + * + */ + ship?: PatpNoSig; + /** + */ + app: GallAgent; + /** + * Mark of the cage to be poked + * + */ + mark: Mark; + /** + * Vase of the cage of to be poked, as JSON + */ + json: Action; +} + +/** + * Description of a scry request + */ +export interface Scry { + /** {@inheritDoc GallAgent} */ + app: GallAgent; + /** {@inheritDoc Path} */ + path: Path; +} + +/** + * Description of a thread request + * + * @typeParam Action - Typescript type of the data being poked + */ +export interface Thread { + /** + * The mark of the input vase + */ + inputMark: Mark; + /** + * The mark of the output vase + */ + outputMark: Mark; + /** + * Name of the thread + * + * @example + * ```typescript + * "graph-add-nodes" + * ``` + */ + threadName: string; + /** + * Desk of thread + */ + desk?: string; + /** + * Data of the input vase + */ + body: Action; +} + +export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; + +export interface PokeHandlers { + onSuccess?: () => void; + onError?: (e: any) => void; +} + +export type PokeInterface = PokeHandlers & Poke; + +export interface AuthenticationInterface { + ship: string; + url: string; + code: string; + verbose?: boolean; +} + +/** + * Subscription event handlers + * + */ +export interface SubscriptionInterface { + /** + * Handle negative %watch-ack + */ + err?(error: any, id: string): void; + /** + * Handle %fact + */ + event?(data: any, mark: string, id: number): void; + /** + * Handle %kick + */ + quit?(data: any): void; +} + +export type OnceSubscriptionErr = 'quit' | 'nack' | 'timeout'; + +export interface SubscriptionRequestInterface extends SubscriptionInterface { + /** + * The app to subscribe to + * @example + * `"graph-store"` + */ + app: GallAgent; + /** + * The path to which to subscribe + * @example + * `"/keys"` + */ + path: Path; + /** + * Whether to resubscribe this exact subscription on quit + */ + resubOnQuit?: boolean; +} + +export interface headers { + 'Content-Type': string; + Cookie?: string; +} + +export interface CustomEventHandler { + (data: any, response: string): void; +} + +export interface SSEOptions { + headers: { + Cookie?: string; + }; + withCredentials?: boolean; +} + +export interface Ack extends Record { + action: Action; + 'event-id': number; +} + +export interface Message extends Record { + action: Action; + id: number; +} + +export class ResumableError extends Error {} + +export class FatalError extends Error {} + +export class ReapError extends Error {} + +export class AuthError extends Error {} diff --git a/packages/shared/src/http-api/utils.ts b/packages/shared/src/http-api/utils.ts new file mode 100644 index 0000000000..69e78889ff --- /dev/null +++ b/packages/shared/src/http-api/utils.ts @@ -0,0 +1,79 @@ +export function camelize(str: string) { + return str + .replace(/\s(.)/g, function ($1: string) { + return $1.toUpperCase(); + }) + .replace(/\s/g, '') + .replace(/^(.)/, function ($1: string) { + return $1.toLowerCase(); + }); +} + +export function uncamelize(str: string, separator = '-') { + // Replace all capital letters by separator followed by lowercase one + str = str.replace(/[A-Z]/g, function (letter: string) { + return separator + letter.toLowerCase(); + }); + return str.replace(new RegExp('^' + separator), ''); +} + +/** + * Returns a hex string of given length. + * + * Poached from StackOverflow. + * + * @param len Length of hex string to return. + */ +export function hexString(len: number): string { + const maxlen = 8; + const min = Math.pow(16, Math.min(len, maxlen) - 1); + const max = Math.pow(16, Math.min(len, maxlen)) - 1; + const n = Math.floor(Math.random() * (max - min + 1)) + min; + let r = n.toString(16); + while (r.length < len) { + r = r + hexString(len - maxlen); + } + return r; +} + +/** + * Generates a random UID. + * + * Copied from https://github.com/urbit/urbit/blob/137e4428f617c13f28ed31e520eff98d251ed3e9/pkg/interface/src/lib/util.js#L3 + */ +export function uid(): string { + let str = '0v'; + str += Math.ceil(Math.random() * 8) + '.'; + for (let i = 0; i < 5; i++) { + let _str = Math.ceil(Math.random() * 10000000).toString(32); + _str = ('00000' + _str).substr(-5, 5); + str += _str + '.'; + } + return str.slice(0, -1); +} + +export default class EventEmitter { + private listeners: Record void)[]> = {}; + + on(event: string, callback: (...data: any[]) => void) { + if (!(event in this.listeners)) { + this.listeners[event] = []; + } + + this.listeners[event].push(callback); + + return this; + } + + emit(event: string, ...data: any): any { + if (!(event in this.listeners)) { + return null; + } + + for (let i = 0; i < this.listeners[event].length; i++) { + const callback = this.listeners[event][i]; + + callback.call(this, ...data); + } + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a98e8e1c3..7ad790f854 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -342,7 +342,7 @@ importers: version: 29.7.0 '@react-native/metro-config': specifier: ^0.73.5 - version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) + version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13) '@tamagui/babel-plugin': specifier: ~1.112.12 version: 1.112.12(@swc/helpers@0.5.13)(encoding@0.1.13)(react@18.2.0) @@ -1637,6 +1637,9 @@ importers: big-integer: specifier: ^1.6.52 version: 1.6.52 + browser-or-node: + specifier: ^3.0.0 + version: 3.0.0 drizzle-orm: specifier: 0.30.9 version: 0.30.9(patch_hash=cegrec33e6f7d6ltk7vff5r7w4)(@op-engineering/op-sqlite@5.0.5(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(@opentelemetry/api@1.8.0)(@types/better-sqlite3@7.6.9)(@types/react@18.2.55)(better-sqlite3@9.4.5)(react@18.2.0) @@ -1646,6 +1649,12 @@ importers: react: specifier: ^18.2.0 version: 18.2.0 + react-native-fetch-api: + specifier: ^3.0.0 + version: 3.0.0 + react-native-polyfill-globals: + specifier: ^3.1.0 + version: 3.1.0(base-64@1.0.0)(react-native-fetch-api@3.0.0)(react-native-get-random-values@1.11.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(react-native-url-polyfill@2.0.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(text-encoding@0.7.0)(web-streams-polyfill@3.3.3) sorted-btree: specifier: ^1.8.1 version: 1.8.1 @@ -7170,6 +7179,9 @@ packages: browser-or-node@1.3.0: resolution: {integrity: sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==} + browser-or-node@3.0.0: + resolution: {integrity: sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==} + browserslist@4.22.2: resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -8328,11 +8340,13 @@ packages: eslint@8.56.0: resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm-resolve@1.0.11: @@ -18776,7 +18790,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': + '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native/js-polyfills': 0.73.1 '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -18785,7 +18799,10 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' + - bufferutil + - encoding - supports-color + - utf-8-validate '@react-native/normalize-color@2.1.0': {} @@ -21889,6 +21906,8 @@ snapshots: browser-or-node@1.3.0: {} + browser-or-node@3.0.0: {} + browserslist@4.22.2: dependencies: caniuse-lite: 1.0.30001576 From c7251dbbec46d832b65f636e7e04f90d9fb423df Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 16 Oct 2024 16:44:06 -0400 Subject: [PATCH 073/259] lure invitations: attribute shared group + user --- packages/app/features/top/ChannelScreen.tsx | 3 +++ packages/app/features/top/ChatListScreen.tsx | 5 +++- .../app/features/top/GroupChannelsScreen.tsx | 2 ++ packages/app/utils/posthog.ts | 4 +++ .../components/Channel/EmptyChannelNotice.tsx | 4 ++- packages/ui/src/components/Channel/index.tsx | 12 +++++++-- .../components/InviteFriendsToTlonButton.tsx | 25 ++++++++++++++----- .../ui/src/components/InviteUsersSheet.tsx | 8 +++++- .../ui/src/components/InviteUsersWidget.tsx | 4 ++- 9 files changed, 55 insertions(+), 12 deletions(-) diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index c4b32053ae..2f01eadf1a 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -27,6 +27,7 @@ import { useChannelNavigation } from '../../hooks/useChannelNavigation'; import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation'; import { useGroupActions } from '../../hooks/useGroupActions'; import type { RootStackParamList } from '../../navigation/types'; +import { trackInviteShared } from '../../utils/posthog'; const logger = createDevLogger('ChannelScreen', false); @@ -349,6 +350,7 @@ export default function ChannelScreen(props: Props) { editPost={editPost} negotiationMatch={negotiationStatus.matchedOrPending} canUpload={canUpload} + onShareInvite={() => trackInviteShared(group?.id, currentUserId)} /> {group && ( <> @@ -364,6 +366,7 @@ export default function ChannelScreen(props: Props) { onOpenChange={handleInviteSheetOpenChange} onInviteComplete={() => setInviteSheetGroup(null)} group={inviteSheetGroup ?? undefined} + onShareInvite={() => trackInviteShared(group.id, currentUserId)} /> )} diff --git a/packages/app/features/top/ChatListScreen.tsx b/packages/app/features/top/ChatListScreen.tsx index f74e27935b..a054b7c952 100644 --- a/packages/app/features/top/ChatListScreen.tsx +++ b/packages/app/features/top/ChatListScreen.tsx @@ -25,7 +25,7 @@ import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation import { useCurrentUserId } from '../../hooks/useCurrentUser'; import { useFeatureFlag } from '../../lib/featureFlags'; import type { RootStackParamList } from '../../navigation/types'; -import { identifyTlonEmployee } from '../../utils/posthog'; +import { identifyTlonEmployee, trackInviteShared } from '../../utils/posthog'; import { isSplashDismissed, setSplashDismissed } from '../../utils/splash'; const logger = createDevLogger('ChatListScreen', false); @@ -332,6 +332,9 @@ export default function ChatListScreen(props: Props) { onOpenChange={handleInviteSheetOpenChange} onInviteComplete={() => setInviteSheetGroup(null)} group={inviteSheetGroup ?? undefined} + onShareInvite={() => + trackInviteShared(inviteSheetGroup?.id, currentUser) + } /> ; @@ -73,6 +74,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { }} group={inviteSheetGroup ?? undefined} onInviteComplete={() => setInviteSheetGroup(null)} + onShareInvite={() => trackInviteShared(group?.id, currentUser)} /> ); diff --git a/packages/app/utils/posthog.ts b/packages/app/utils/posthog.ts index 81213d46b5..f652cce886 100644 --- a/packages/app/utils/posthog.ts +++ b/packages/app/utils/posthog.ts @@ -69,3 +69,7 @@ export const identifyTlonEmployee = () => { posthog.identify(UUID, { isTlonEmployee: true }); db.setIsTlonEmployee(true); }; + +export const trackInviteShared = (group: string | undefined, user: string) => { + capture('invite_shared', { group, user }); +}; diff --git a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx index fe5e975925..50834349dd 100644 --- a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx +++ b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx @@ -9,9 +9,11 @@ import { InviteFriendsToTlonButton } from '../InviteFriendsToTlonButton'; export function EmptyChannelNotice({ channel, userId, + onShareInvite, }: { channel: db.Channel; userId: string; + onShareInvite?: () => void; }) { const isGroupAdmin = useIsAdmin(channel.groupId ?? '', userId); const group = useGroup(channel.groupId ?? ''); @@ -38,7 +40,7 @@ export function EmptyChannelNotice({ {isGroupAdmin && isWelcomeChannel && ( - + )} ); diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 6c14889b49..d72884822a 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -70,6 +70,7 @@ export function Channel({ useGroup, usePostReference, onGroupAction, + onShareInvite, useChannel, storeDraft, clearDraft, @@ -110,6 +111,7 @@ export function Channel({ useGroup: typeof useGroupPreview; usePostReference: typeof usePostReferenceHook; onGroupAction: (action: GroupPreviewAction, group: db.Group) => void; + onShareInvite: () => void; useChannel: typeof useChannelFromStore; storeDraft: (draft: JSONContent, draftType?: GalleryDraftType) => void; clearDraft: (draftType?: GalleryDraftType) => void; @@ -142,8 +144,14 @@ export function Channel({ : GalleryPost; const renderEmptyComponent = useCallback(() => { - return ; - }, [currentUserId, channel]); + return ( + + ); + }, [currentUserId, channel, onShareInvite]); const onPressGroupRef = useCallback((group: db.Group) => { setGroupPreview(group); diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index 8dec64ed38..6dcbc7cb19 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -11,7 +11,13 @@ import { Button } from './Button'; import { Icon } from './Icon'; import { LoadingSpinner } from './LoadingSpinner'; -export function InviteFriendsToTlonButton({ group }: { group?: db.Group }) { +export function InviteFriendsToTlonButton({ + group, + onShare, +}: { + group?: db.Group; + onShare?: () => void; +}) { const userId = useCurrentUserId(); const isGroupAdmin = useIsAdmin(group?.id ?? '', userId); const branchDomain = useBranchDomain(); @@ -38,14 +44,21 @@ export function InviteFriendsToTlonButton({ group }: { group?: db.Group }) { return; } - await Share.share({ - message: `Join ${group.title} on Tlon: ${shareUrl}`, - title: `Join ${group.title} on Tlon`, - }); + try { + const result = await Share.share({ + message: `Join ${group.title} on Tlon: ${shareUrl}`, + title: `Join ${group.title} on Tlon`, + }); + if (result.action === Share.sharedAction) { + onShare?.(); + } + } catch (error) { + console.error('Error sharing:', error); + } return; } - }, [group, shareUrl, doCopy, status]); + }, [shareUrl, status, group, doCopy, onShare]); useEffect(() => { const meta = { diff --git a/packages/ui/src/components/InviteUsersSheet.tsx b/packages/ui/src/components/InviteUsersSheet.tsx index e4bbac26c5..b2b9ae5e21 100644 --- a/packages/ui/src/components/InviteUsersSheet.tsx +++ b/packages/ui/src/components/InviteUsersSheet.tsx @@ -10,11 +10,13 @@ const InviteUsersSheetComponent = ({ onOpenChange, group, onInviteComplete, + onShareInvite, }: { open: boolean; onOpenChange: (open: boolean) => void; group?: db.Group; onInviteComplete: () => void; + onShareInvite?: () => void; }) => { const { bottom } = useSafeAreaInsets(); const hasOpened = useRef(open); @@ -33,7 +35,11 @@ const InviteUsersSheetComponent = ({ snapPointsMode="percent" > - + ); diff --git a/packages/ui/src/components/InviteUsersWidget.tsx b/packages/ui/src/components/InviteUsersWidget.tsx index a3c3cf0f47..09f75f64af 100644 --- a/packages/ui/src/components/InviteUsersWidget.tsx +++ b/packages/ui/src/components/InviteUsersWidget.tsx @@ -10,9 +10,11 @@ import { InviteFriendsToTlonButton } from './InviteFriendsToTlonButton'; const InviteUsersWidgetComponent = ({ group, onInviteComplete, + onShareInvite, }: { group: db.Group; onInviteComplete: () => void; + onShareInvite?: () => void; }) => { const [invitees, setInvitees] = useState([]); @@ -36,7 +38,7 @@ const InviteUsersWidgetComponent = ({ return ( <> - + Date: Wed, 16 Oct 2024 15:57:22 -0500 Subject: [PATCH 074/259] client: fix refs --- packages/app/hooks/useHandleLogout.native.ts | 3 ++- packages/app/hooks/useHandleLogout.ts | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/app/hooks/useHandleLogout.native.ts b/packages/app/hooks/useHandleLogout.native.ts index b83f0fec5d..c8b63ba706 100644 --- a/packages/app/hooks/useHandleLogout.native.ts +++ b/packages/app/hooks/useHandleLogout.native.ts @@ -1,5 +1,6 @@ import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; +import * as store from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; @@ -14,7 +15,7 @@ export function useHandleLogout({ resetDb }: { resetDb: () => void }) { const handleLogout = useCallback(async () => { api.queryClient.clear(); - api.removeUrbitClient(); + store.removeClient(); clearShip(); clearShipInfo(); removeHostingToken(); diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index 8486dd5806..c4ddc08fde 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -1,8 +1,6 @@ -import { - createDevLogger, - updateInitializedClient, -} from '@tloncorp/shared/dist'; +import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; +import * as store from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; @@ -21,7 +19,7 @@ export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { const handleLogout = useCallback(async () => { api.queryClient.clear(); - api.removeUrbitClient(); + store.removeClient(); clearShip(); clearShipInfo(); removeHostingToken(); From 3ee19fd8afa6621bc26dc099a3ab859173dae756 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 16 Oct 2024 16:33:44 -0500 Subject: [PATCH 075/259] urbit: fix ship setting --- packages/shared/src/api/urbit.ts | 2 -- packages/shared/src/http-api/Urbit.ts | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 20ad311b80..3a76143b7e 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -105,8 +105,6 @@ export function internalConfigureClient({ }: ClientParams) { logger.log('configuring client', shipName, shipUrl); config.client = config.client || new Urbit(shipUrl, '', ''); - config.client.ship = deSig(shipName); - config.client.our = preSig(shipName); config.client.verbose = verbose; config.shipUrl = shipUrl; config.onQuitOrReset = onQuitOrReset; diff --git a/packages/shared/src/http-api/Urbit.ts b/packages/shared/src/http-api/Urbit.ts index a95f6e9b9e..25795b0d11 100644 --- a/packages/shared/src/http-api/Urbit.ts +++ b/packages/shared/src/http-api/Urbit.ts @@ -525,6 +525,9 @@ export class Urbit { if (this.our !== this.ship) { console.log('our name does not match ship name'); + console.log('our:', this.our); + console.log('ship:', this.ship); + console.log('messages:', json); throw new AuthError('invalid session'); } From ab01ec05ff00a8744a3eaba40ffbdae5fcf418db Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 16 Oct 2024 16:34:00 -0500 Subject: [PATCH 076/259] activity: fix marking threads read without thread --- packages/app/features/top/PostScreen.tsx | 2 +- packages/shared/src/store/channelActions.ts | 2 +- packages/shared/src/store/groupActions.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/app/features/top/PostScreen.tsx b/packages/app/features/top/PostScreen.tsx index ec85e16c9a..65bf4803a8 100644 --- a/packages/app/features/top/PostScreen.tsx +++ b/packages/app/features/top/PostScreen.tsx @@ -64,7 +64,7 @@ export default function PostScreen(props: Props) { }, [post, threadPosts]); const markRead = useCallback(() => { - if (channel && post && threadPosts) { + if (channel && post && threadPosts && threadPosts.length > 0) { store.markThreadRead({ channel, parentPost: post, diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index 6b2bbd40bb..789d7b6ffc 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -173,7 +173,7 @@ export async function markChannelRead(params: MarkChannelReadParams) { try { await api.readChannel(params); } catch (e) { - console.error('Failed to read channel', e); + console.error('Failed to read channel', params, e); // rollback optimistic update if (existingUnread) { await db.insertChannelUnreads([existingUnread]); diff --git a/packages/shared/src/store/groupActions.ts b/packages/shared/src/store/groupActions.ts index e3a8ee71f9..4445f86a0b 100644 --- a/packages/shared/src/store/groupActions.ts +++ b/packages/shared/src/store/groupActions.ts @@ -994,7 +994,7 @@ export async function markGroupRead(group: db.Group) { try { await api.readGroup(group); } catch (e) { - console.error('Failed to read channel', e); + console.error('Failed to read group', e); // rollback optimistic update if (existingUnread) { await db.insertGroupUnreads([existingUnread]); From 797c9ede089644494c1a8c44d746be4a876358d8 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 16 Oct 2024 19:21:47 -0400 Subject: [PATCH 077/259] lure: send ID in trackInviteShared up from InviteFriendsToTlonButton --- packages/app/features/top/ChannelScreen.tsx | 8 ++++++-- packages/app/features/top/ChatListScreen.tsx | 8 +++++--- packages/app/features/top/GroupChannelsScreen.tsx | 6 +++++- packages/app/utils/posthog.ts | 4 ++-- packages/ui/src/components/Channel/EmptyChannelNotice.tsx | 2 +- packages/ui/src/components/Channel/index.tsx | 2 +- packages/ui/src/components/InviteFriendsToTlonButton.tsx | 4 ++-- packages/ui/src/components/InviteUsersSheet.tsx | 2 +- packages/ui/src/components/InviteUsersWidget.tsx | 2 +- 9 files changed, 24 insertions(+), 14 deletions(-) diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index 2f01eadf1a..893e76d6e1 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -298,6 +298,10 @@ export default function ChannelScreen(props: Props) { } }, []); + const handleShareInvite = useCallback((lure: string) => { + trackInviteShared(lure); + }, []); + if (!channel) { return null; } @@ -350,7 +354,7 @@ export default function ChannelScreen(props: Props) { editPost={editPost} negotiationMatch={negotiationStatus.matchedOrPending} canUpload={canUpload} - onShareInvite={() => trackInviteShared(group?.id, currentUserId)} + onShareInvite={handleShareInvite} /> {group && ( <> @@ -366,7 +370,7 @@ export default function ChannelScreen(props: Props) { onOpenChange={handleInviteSheetOpenChange} onInviteComplete={() => setInviteSheetGroup(null)} group={inviteSheetGroup ?? undefined} - onShareInvite={() => trackInviteShared(group.id, currentUserId)} + onShareInvite={handleShareInvite} /> )} diff --git a/packages/app/features/top/ChatListScreen.tsx b/packages/app/features/top/ChatListScreen.tsx index a054b7c952..83ef90dc81 100644 --- a/packages/app/features/top/ChatListScreen.tsx +++ b/packages/app/features/top/ChatListScreen.tsx @@ -266,6 +266,10 @@ export default function ChatListScreen(props: Props) { setShowSearchInput(!showSearchInput); }, [showSearchInput]); + const handleShareInvite = useCallback((lure: string) => { + trackInviteShared(lure); + }, []); + return ( setInviteSheetGroup(null)} group={inviteSheetGroup ?? undefined} - onShareInvite={() => - trackInviteShared(inviteSheetGroup?.id, currentUser) - } + onShareInvite={handleShareInvite} /> { + trackInviteShared(lure); + }, []); + return ( setInviteSheetGroup(null)} - onShareInvite={() => trackInviteShared(group?.id, currentUser)} + onShareInvite={handleShareInvite} /> ); diff --git a/packages/app/utils/posthog.ts b/packages/app/utils/posthog.ts index f652cce886..c93ba29845 100644 --- a/packages/app/utils/posthog.ts +++ b/packages/app/utils/posthog.ts @@ -70,6 +70,6 @@ export const identifyTlonEmployee = () => { db.setIsTlonEmployee(true); }; -export const trackInviteShared = (group: string | undefined, user: string) => { - capture('invite_shared', { group, user }); +export const trackInviteShared = (lure: string) => { + capture('Invite Link Shared', { lure }); }; diff --git a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx index 50834349dd..de1eced27e 100644 --- a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx +++ b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx @@ -13,7 +13,7 @@ export function EmptyChannelNotice({ }: { channel: db.Channel; userId: string; - onShareInvite?: () => void; + onShareInvite?: (lure: string) => void; }) { const isGroupAdmin = useIsAdmin(channel.groupId ?? '', userId); const group = useGroup(channel.groupId ?? ''); diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index d72884822a..a5484be190 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -111,7 +111,7 @@ export function Channel({ useGroup: typeof useGroupPreview; usePostReference: typeof usePostReferenceHook; onGroupAction: (action: GroupPreviewAction, group: db.Group) => void; - onShareInvite: () => void; + onShareInvite: (lure: string) => void; useChannel: typeof useChannelFromStore; storeDraft: (draft: JSONContent, draftType?: GalleryDraftType) => void; clearDraft: (draftType?: GalleryDraftType) => void; diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index 6dcbc7cb19..e7df99ba57 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -16,7 +16,7 @@ export function InviteFriendsToTlonButton({ onShare, }: { group?: db.Group; - onShare?: () => void; + onShare?: (lure: string) => void; }) { const userId = useCurrentUserId(); const isGroupAdmin = useIsAdmin(group?.id ?? '', userId); @@ -51,7 +51,7 @@ export function InviteFriendsToTlonButton({ }); if (result.action === Share.sharedAction) { - onShare?.(); + onShare?.(shareUrl.split('/').pop() ?? ''); } } catch (error) { console.error('Error sharing:', error); diff --git a/packages/ui/src/components/InviteUsersSheet.tsx b/packages/ui/src/components/InviteUsersSheet.tsx index b2b9ae5e21..f8b5c60398 100644 --- a/packages/ui/src/components/InviteUsersSheet.tsx +++ b/packages/ui/src/components/InviteUsersSheet.tsx @@ -16,7 +16,7 @@ const InviteUsersSheetComponent = ({ onOpenChange: (open: boolean) => void; group?: db.Group; onInviteComplete: () => void; - onShareInvite?: () => void; + onShareInvite?: (lure: string) => void; }) => { const { bottom } = useSafeAreaInsets(); const hasOpened = useRef(open); diff --git a/packages/ui/src/components/InviteUsersWidget.tsx b/packages/ui/src/components/InviteUsersWidget.tsx index 09f75f64af..a13497ab06 100644 --- a/packages/ui/src/components/InviteUsersWidget.tsx +++ b/packages/ui/src/components/InviteUsersWidget.tsx @@ -14,7 +14,7 @@ const InviteUsersWidgetComponent = ({ }: { group: db.Group; onInviteComplete: () => void; - onShareInvite?: () => void; + onShareInvite?: (lure: string) => void; }) => { const [invitees, setInvitees] = useState([]); From 8867ce4e56d527da4624e7911f564ec41ff2af7b Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 16 Oct 2024 20:00:51 -0400 Subject: [PATCH 078/259] channel: fix onShareInvite props --- apps/tlon-mobile/src/fixtures/Channel.fixture.tsx | 1 + packages/ui/src/components/Channel/index.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx index 9e3dae72a4..fa54a34fd3 100644 --- a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx @@ -112,6 +112,7 @@ const baseProps: ComponentProps = { canUpload: true, onPressRetry: () => {}, onPressDelete: () => {}, + onShareInvite: () => {}, } as const; export const ChannelFixture = (props: { diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index a5484be190..9a52078d1c 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -111,7 +111,7 @@ export function Channel({ useGroup: typeof useGroupPreview; usePostReference: typeof usePostReferenceHook; onGroupAction: (action: GroupPreviewAction, group: db.Group) => void; - onShareInvite: (lure: string) => void; + onShareInvite?: (lure: string) => void; useChannel: typeof useChannelFromStore; storeDraft: (draft: JSONContent, draftType?: GalleryDraftType) => void; clearDraft: (draftType?: GalleryDraftType) => void; From 5154a80e91ddc0e820f6f1464916702eec3aaf37 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 09:55:27 -0400 Subject: [PATCH 079/259] wait i need the other branch --- packages/shared/src/logic/analytics.ts | 3 +++ packages/shared/src/logic/index.ts | 1 + packages/ui/src/components/InviteFriendsToTlonButton.tsx | 8 ++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 packages/shared/src/logic/analytics.ts diff --git a/packages/shared/src/logic/analytics.ts b/packages/shared/src/logic/analytics.ts new file mode 100644 index 0000000000..ae01fb7bca --- /dev/null +++ b/packages/shared/src/logic/analytics.ts @@ -0,0 +1,3 @@ +export enum AnalyticsEvent { + InviteShared = 'Invite Link Shared', +} diff --git a/packages/shared/src/logic/index.ts b/packages/shared/src/logic/index.ts index bf136709b7..e460101969 100644 --- a/packages/shared/src/logic/index.ts +++ b/packages/shared/src/logic/index.ts @@ -6,3 +6,4 @@ export * from './types'; export * from './activity'; export * from './branch'; export * from './deeplinks'; +export * from './analytics'; diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index e7df99ba57..5ad133ac26 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -1,3 +1,4 @@ +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import { useCallback, useEffect } from 'react'; @@ -11,6 +12,8 @@ import { Button } from './Button'; import { Icon } from './Icon'; import { LoadingSpinner } from './LoadingSpinner'; +const logger = createDevLogger('InviteButton', true); + export function InviteFriendsToTlonButton({ group, onShare, @@ -51,14 +54,15 @@ export function InviteFriendsToTlonButton({ }); if (result.action === Share.sharedAction) { - onShare?.(shareUrl.split('/').pop() ?? ''); + // onShare?.(shareUrl.split('/').pop() ?? ''); + // logger.trackeve } } catch (error) { console.error('Error sharing:', error); } return; } - }, [shareUrl, status, group, doCopy, onShare]); + }, [shareUrl, status, group, doCopy]); useEffect(() => { const meta = { From 36c1d30ae029db73015f3e242de2547006f27a78 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 15 Oct 2024 15:39:20 -0400 Subject: [PATCH 080/259] correctly interpret joining state from gang claim --- packages/shared/src/urbit/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/urbit/utils.ts b/packages/shared/src/urbit/utils.ts index 4ef00b6105..4cbdb36fed 100644 --- a/packages/shared/src/urbit/utils.ts +++ b/packages/shared/src/urbit/utils.ts @@ -378,7 +378,10 @@ export function createMultiDmId(seed = Date.now()) { export function getJoinStatusFromGang(gang: ubg.Gang): GroupJoinStatus | null { if (gang.claim?.progress) { - if (gang.claim?.progress === 'adding') { + if ( + gang.claim?.progress === 'adding' || + gang.claim?.progress === 'watching' + ) { return 'joining'; } From 5fd8cec0c001748a5ecc5a9232252d80782a76d9 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 15 Oct 2024 16:55:39 -0400 Subject: [PATCH 081/259] add new query for getting all channels, use that to check against name collisions when creating new channel --- packages/app/features/top/GroupChannelsScreen.tsx | 2 +- packages/app/hooks/useGroupContext.ts | 10 +++------- packages/shared/src/db/modelBuilders.ts | 15 +++------------ packages/shared/src/db/queries.ts | 8 ++++++++ packages/shared/src/store/dbHooks.ts | 9 +++++++++ 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index 817ca2d264..d21772b6a4 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -28,7 +28,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { const [inviteSheetGroup, setInviteSheetGroup] = useState( null ); - const { createChannel } = useGroupContext({ groupId: id }); + const { createChannel } = useGroupContext({ groupId: id, isFocused }); const pinnedItems = useMemo(() => { return pins ?? []; diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index 957596f43b..f678b2f098 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -100,10 +100,7 @@ export const useGroupContext = ({ } }, [group]); - const { data: pendingChats } = store.usePendingChats({ - enabled: isFocused, - }); - const { data: currentChatData } = store.useCurrentChats({ + const { data: existingChannels } = store.useAllChannels({ enabled: isFocused, }); @@ -120,8 +117,7 @@ export const useGroupContext = ({ const { name, id } = assembleNewChannelIdAndName({ title, channelType, - currentChatData, - pendingChats, + existingChannels: existingChannels ?? [], currentUserId, }); @@ -136,7 +132,7 @@ export const useGroupContext = ({ }); } }, - [group, currentUserId, currentChatData, pendingChats] + [group, currentUserId, existingChannels] ); const deleteChannel = useCallback( diff --git a/packages/shared/src/db/modelBuilders.ts b/packages/shared/src/db/modelBuilders.ts index 3caab0c657..0df2b0d11a 100644 --- a/packages/shared/src/db/modelBuilders.ts +++ b/packages/shared/src/db/modelBuilders.ts @@ -9,7 +9,6 @@ import { import * as db from '../db'; import * as logic from '../logic'; import { convertToAscii } from '../logic'; -import { CurrentChats, PendingChats } from '../store'; import * as ub from '../urbit'; import { getChannelKindFromType } from '../urbit'; import * as types from './types'; @@ -17,22 +16,14 @@ import * as types from './types'; export function assembleNewChannelIdAndName({ title, channelType, - currentChatData, - pendingChats, + existingChannels, currentUserId, }: { title: string; channelType: Omit; - currentChatData?: CurrentChats | null; - pendingChats?: PendingChats | null; + existingChannels: db.Channel[]; currentUserId: string; }) { - const existingChannels = [ - ...(pendingChats ?? []), - ...(currentChatData?.pinned ?? []), - ...(currentChatData?.unpinned ?? []), - ]; - const titleIsNumber = Number.isInteger(Number(title)); // we need unique channel names that are valid for urbit's @tas type const tempChannelName = titleIsNumber @@ -47,7 +38,7 @@ export function assembleNewChannelIdAndName({ ); }; - const randomSmallNumber = Math.floor(Math.random() * 100); + const randomSmallNumber = Math.floor(Math.random() * 1000); const channelName = existingChannel() ? `${tempChannelName}-${randomSmallNumber}` : tempChannelName; diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index 326d8b98cb..7d4e63a1bb 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -230,6 +230,14 @@ export const getPins = createReadQuery( ['pins'] ); +export const getAllChannels = createReadQuery( + 'getAllChannels', + async (ctx: QueryCtx) => { + return ctx.db.query.channels.findMany(); + }, + ['channels'] +); + export const getChats = createReadQuery( 'getChats', async (ctx: QueryCtx): Promise => { diff --git a/packages/shared/src/store/dbHooks.ts b/packages/shared/src/store/dbHooks.ts index d3f6516895..b7a37c594d 100644 --- a/packages/shared/src/store/dbHooks.ts +++ b/packages/shared/src/store/dbHooks.ts @@ -27,6 +27,15 @@ export type CustomQueryConfig = Pick< 'enabled' >; +export const useAllChannels = ({ enabled }: { enabled?: boolean }) => { + const querykey = useKeyFromQueryDeps(db.getAllChannels); + return useQuery({ + queryKey: ['allChannels', querykey], + queryFn: () => db.getAllChannels(), + enabled, + }); +}; + export const useCurrentChats = ( queryConfig?: CustomQueryConfig ): UseQueryResult => { From e9fc404eea87e233650f9c1730588f12d0e8e35a Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 15 Oct 2024 18:19:03 -0400 Subject: [PATCH 082/259] fix optimistic updates for add channel --- packages/app/features/top/GroupChannelsScreen.tsx | 3 ++- packages/shared/src/api/groupsApi.ts | 6 ++++-- packages/shared/src/db/queries.ts | 6 +++++- packages/shared/src/store/channelActions.ts | 1 + .../ui/src/components/GroupChannelsScreenView.tsx | 11 ++++------- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index d21772b6a4..d96bcaf440 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -28,7 +28,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { const [inviteSheetGroup, setInviteSheetGroup] = useState( null ); - const { createChannel } = useGroupContext({ groupId: id, isFocused }); + const { group, createChannel } = useGroupContext({ groupId: id, isFocused }); const pinnedItems = useMemo(() => { return pins ?? []; @@ -62,6 +62,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { onBackPressed={handleGoBackPressed} currentUser={currentUser} createChannel={createChannel} + group={group} /> ( { app: 'groups', path: '/groups/ui' }, (groupUpdateEvent) => { - logger.log('groupUpdateEvent', { groupUpdateEvent }); + logger.log('groupUpdateEvent', groupUpdateEvent); eventHandler(toGroupUpdate(groupUpdateEvent)); } ); subscribe({ app: 'groups', path: '/gangs/updates' }, (rawEvent: ub.Gangs) => { - logger.log('gangsUpdateEvent:', rawEvent); + logger.log('gangsUpdateEvent', rawEvent); eventHandler(toGangsGroupsUpdate(rawEvent)); }); }; @@ -1337,6 +1337,8 @@ export function toClientGroup( haveInvite: false, currentUserIsMember: isJoined, currentUserIsHost: hostUserId === currentUserId, + // if meta is unset, it's still in the join process + joinStatus: !group.meta || group.meta.title === '' ? 'joining' : undefined, hostUserId, flaggedPosts, navSections: group['zone-ord'] diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index 7d4e63a1bb..61bf466d0e 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -1463,7 +1463,11 @@ export const insertChannels = createWriteQuery( .values(channels) .onConflictDoUpdate({ target: $channels.id, - set: conflictUpdateSetAll($channels, ['lastPostId', 'lastPostAt']), + set: conflictUpdateSetAll($channels, [ + 'lastPostId', + 'lastPostAt', + 'currentUserIsMember', + ]), }); for (const channel of channels) { diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index 6b2bbd40bb..6cd5427e66 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -29,6 +29,7 @@ export async function createChannel({ type: channelType as db.ChannelType, groupId, addedToGroupAt: Date.now(), + currentUserIsMember: true, }; await db.insertChannels([newChannel]); diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index b89ff31221..ce7b9b3a28 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -4,7 +4,6 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ScrollView, View, YStack } from 'tamagui'; import { useCurrentUserId } from '../contexts'; -import { useChatOptions } from '../contexts/chatOptions'; import { useIsAdmin } from '../utils/channelUtils'; import ChannelNavSections from './ChannelNavSections'; import { ChatOptionsSheet, ChatOptionsSheetMethods } from './ChatOptionsSheet'; @@ -16,6 +15,7 @@ import { import { ScreenHeader } from './ScreenHeader'; type GroupChannelsScreenViewProps = { + group: db.Group | null; onChannelPressed: (channel: db.Channel) => void; onBackPressed: () => void; currentUser: string; @@ -31,12 +31,11 @@ type GroupChannelsScreenViewProps = { }; export function GroupChannelsScreenView({ + group, onChannelPressed, onBackPressed, createChannel, }: GroupChannelsScreenViewProps) { - const groupOptions = useChatOptions(); - const group = groupOptions?.group; const chatOptionsSheetRef = useRef(null); const [showCreateChannel, setShowCreateChannel] = useState(false); const [sortBy, setSortBy] = useState('recency'); @@ -105,9 +104,7 @@ export function GroupChannelsScreenView({ } /> - {group && - groupOptions.groupChannels && - groupOptions.groupChannels.length ? ( + {group && group.channels && group.channels.length ? ( Date: Tue, 15 Oct 2024 18:37:50 -0400 Subject: [PATCH 083/259] remove channel description from add channel sheet --- packages/app/hooks/useGroupContext.ts | 2 +- packages/shared/src/store/channelActions.ts | 6 +++--- .../components/GroupChannelsScreenView.tsx | 2 +- .../ManageChannels/CreateChannelSheet.tsx | 19 ++----------------- 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index f678b2f098..11f5553fb3 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -111,7 +111,7 @@ export const useGroupContext = ({ channelType, }: { title: string; - description: string; + description?: string; channelType: Omit; }) => { const { name, id } = assembleNewChannelIdAndName({ diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index 6cd5427e66..e19a8bf04b 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -18,14 +18,14 @@ export async function createChannel({ channelId: string; name: string; title: string; - description: string; + description?: string; channelType: Omit; }) { // optimistic update const newChannel: db.Channel = { id: channelId, title, - description, + description: description ?? '', type: channelType as db.ChannelType, groupId, addedToGroupAt: Date.now(), @@ -41,7 +41,7 @@ export async function createChannel({ group: groupId, name, title, - description, + description: description ?? '', readers: [], writers: [], }); diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index ce7b9b3a28..46ed8efdd5 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -25,7 +25,7 @@ type GroupChannelsScreenViewProps = { channelType, }: { title: string; - description: string; + description?: string; channelType: ChannelTypeName; }) => Promise; }; diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 81062ff58b..eeddcd7198 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -39,27 +39,21 @@ export function CreateChannelSheet({ channelType, }: { title: string; - description: string; + description?: string; channelType: ChannelTypeName; }) => void; }) { const { control, handleSubmit } = useForm({ defaultValues: { title: '', - description: '', channelType: 'chat', }, }); const handlePressSave = useCallback( - async (data: { - title: string; - description: string; - channelType: string; - }) => { + async (data: { title: string; channelType: string }) => { createChannel({ title: data.title, - description: data.description, channelType: data.channelType as ChannelTypeName, }); onOpenChange(false); @@ -80,15 +74,6 @@ export function CreateChannelSheet({ rules={{ required: 'Channel title is required' }} /> - - - Date: Tue, 15 Oct 2024 18:44:43 -0400 Subject: [PATCH 084/259] missed a spot --- .../src/components/ManageChannels/ManageChannelsScreenView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx index 2d17cf6a7d..edc137d5ef 100644 --- a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx +++ b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx @@ -194,7 +194,7 @@ interface ManageChannelsScreenViewProps { channelType, }: { title: string; - description: string; + description?: string; channelType: ChannelTypeName; }) => Promise; createNavSection: ({ title }: { title: string }) => Promise; From e823fab108744d164e4b9dc2c4e9744087266ede Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Oct 2024 14:59:34 +0000 Subject: [PATCH 085/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index ef5cb5c08b..36641c4b17 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v6.0sjnh.84djm.kqv5r.eeb2p.ailh6.glob' 0v6.0sjnh.84djm.kqv5r.eeb2p.ailh6] + glob-http+['https://bootstrap.urbit.org/glob-0v5.cdkn1.29ten.suoa4.66q4k.cl7fg.glob' 0v5.cdkn1.29ten.suoa4.66q4k.cl7fg] base+'groups' version+[6 4 2] website+'https://tlon.io' From fdfc968d8fc24da68478922d95a1696d952415cc Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 09:54:29 -0500 Subject: [PATCH 086/259] chat options: navigate back to chat list on leave --- packages/app/hooks/useChatSettingsNavigation.ts | 8 ++++++++ packages/ui/src/components/ChatOptionsSheet.tsx | 3 +++ packages/ui/src/contexts/chatOptions.tsx | 5 ++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/app/hooks/useChatSettingsNavigation.ts b/packages/app/hooks/useChatSettingsNavigation.ts index 44604f6586..585e808e46 100644 --- a/packages/app/hooks/useChatSettingsNavigation.ts +++ b/packages/app/hooks/useChatSettingsNavigation.ts @@ -71,6 +71,13 @@ export const useChatSettingsNavigation = () => { [navigation] ); + const navigateOnLeave = useCallback( + () => { + navigation.navigate('ChatList'); + }, + [navigation] + ); + return { onPressChannelMembers, onPressChannelMeta, @@ -79,5 +86,6 @@ export const useChatSettingsNavigation = () => { onPressManageChannels, onPressGroupPrivacy, onPressRoles, + navigateOnLeave, }; }; diff --git a/packages/ui/src/components/ChatOptionsSheet.tsx b/packages/ui/src/components/ChatOptionsSheet.tsx index 60385e8e78..ae9973e4b5 100644 --- a/packages/ui/src/components/ChatOptionsSheet.tsx +++ b/packages/ui/src/components/ChatOptionsSheet.tsx @@ -511,6 +511,7 @@ export function ChannelOptions({ onPressChannelMeta, onPressManageChannels, onPressInvite, + onPressLeave, } = useChatOptions() ?? {}; const currentUserIsHost = useMemo( @@ -752,6 +753,7 @@ export function ChannelOptions({ style: 'destructive', onPress: () => { sheetRef.current.setOpen(false); + onPressLeave?.(); store.respondToDMInvite({ channel, accept: false }); }, }, @@ -774,6 +776,7 @@ export function ChannelOptions({ onPressChannelMembers, onPressManageChannels, onPressInvite, + onPressLeave, title, ]); return ( diff --git a/packages/ui/src/contexts/chatOptions.tsx b/packages/ui/src/contexts/chatOptions.tsx index 356ff6bd44..5d0fe22060 100644 --- a/packages/ui/src/contexts/chatOptions.tsx +++ b/packages/ui/src/contexts/chatOptions.tsx @@ -47,6 +47,7 @@ type ChatOptionsProviderProps = { onPressChannelMeta: (channelId: string) => void; onPressRoles: (groupId: string) => void; onSelectSort?: (sortBy: 'recency' | 'arranged') => void; + navigateOnLeave?: () => void; }; export const ChatOptionsProvider = ({ @@ -62,6 +63,7 @@ export const ChatOptionsProvider = ({ onPressChannelMembers, onPressChannelMeta, onPressRoles, + navigateOnLeave, }: ChatOptionsProviderProps) => { const groupQuery = useGroup({ id: groupId ?? '' }); const group = groupId ? groupQuery.data ?? null : null; @@ -80,7 +82,8 @@ export const ChatOptionsProvider = ({ if (group) { await store.leaveGroup(group.id); } - }, [group]); + navigateOnLeave?.(); + }, [group, navigateOnLeave]); const onSelectSort = useCallback((sortBy: 'recency' | 'arranged') => { db.storeChannelSortPreference(sortBy); From 7e65614e50ab3d73529acc3f4edfd5adf3e6b394 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 09:36:29 -0500 Subject: [PATCH 087/259] gallery: navigate appropriately when tapping refs --- packages/app/features/top/PostScreen.tsx | 23 ++++++- packages/ui/src/components/DetailView.tsx | 9 +-- packages/ui/src/components/PostScreenView.tsx | 61 ++++++++++++++++++- 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/packages/app/features/top/PostScreen.tsx b/packages/app/features/top/PostScreen.tsx index ec85e16c9a..f84d6f045f 100644 --- a/packages/app/features/top/PostScreen.tsx +++ b/packages/app/features/top/PostScreen.tsx @@ -3,6 +3,7 @@ import * as db from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { PostScreenView, useCurrentUserId } from '@tloncorp/ui'; +import { useGroupActions } from 'packages/app/hooks/useGroupActions'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useChannelContext } from '../../hooks/useChannelContext'; @@ -30,9 +31,10 @@ export default function PostScreen(props: Props) { uploaderKey: `${postParam.channelId}/${postParam.id}`, }); - const { navigateToImage } = useChannelNavigation({ - channelId: postParam.channelId, - }); + const { navigateToImage, navigateToRef } = + useChannelNavigation({ + channelId: postParam.channelId, + }); const currentUserId = useCurrentUserId(); @@ -119,6 +121,18 @@ export default function PostScreen(props: Props) { [props.navigation] ); + const { performGroupAction } = useGroupActions(); + + const handleGoToDm = useCallback( + async (participants: string[]) => { + const dmChannel = await store.upsertDmChannel({ + participants, + }); + props.navigation.push('Channel', { channel: dmChannel }); + }, + [props.navigation] + ); + return currentUserId && channel && post ? ( ; } export const DetailView = ({ @@ -40,6 +41,7 @@ export const DetailView = ({ activeMessage, headerMode, editorIsFocused, + flatListRef, }: DetailViewProps) => { const channelType = useMemo( () => urbit.getChannelType(post.channelId), @@ -49,13 +51,12 @@ export const DetailView = ({ const resolvedPosts = useMemo(() => { return isChat && posts ? [...posts, post] : posts; }, [posts, post, isChat]); - const flatListRef = useRef(null); useEffect(() => { - if (editorIsFocused) { + if (editorIsFocused && flatListRef) { flatListRef.current?.scrollToIndex({ index: 1, animated: true }); } - }, [editorIsFocused]); + }, [editorIsFocused, flatListRef]); const scroller = useMemo(() => { return ( diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 3acfe43636..58271aa9cc 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -3,7 +3,8 @@ import type * as db from '@tloncorp/shared/dist/db'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { Story } from '@tloncorp/shared/dist/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { FlatList } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Text, View, YStack } from 'tamagui'; @@ -14,6 +15,7 @@ import { BigInput } from './BigInput'; import { ChannelFooter } from './Channel/ChannelFooter'; import { ChannelHeader } from './Channel/ChannelHeader'; import { DetailView } from './DetailView'; +import { GroupPreviewAction, GroupPreviewSheet } from './GroupPreviewSheet'; import KeyboardAvoidingView from './KeyboardAvoidingView'; import { MessageInput } from './MessageInput'; import { TlonEditorBridge } from './MessageInput/toolbarActions.native'; @@ -39,6 +41,9 @@ export function PostScreenView({ editPost, onPressRetry, onPressDelete, + onPressRef, + onGroupAction, + goToDm, negotiationMatch, headerMode, canUpload, @@ -69,6 +74,9 @@ export function PostScreenView({ ) => Promise; onPressRetry: (post: db.Post) => void; onPressDelete: (post: db.Post) => void; + onPressRef: (channel: db.Channel, post: db.Post) => void; + onGroupAction: (action: GroupPreviewAction, group: db.Group) => void; + goToDm: (participants: string[]) => void; negotiationMatch: boolean; headerMode: 'default' | 'next'; canUpload: boolean; @@ -86,6 +94,8 @@ export function PostScreenView({ editor: TlonEditorBridge | null; }>(null); const [editorIsFocused, setEditorIsFocused] = useState(false); + const [groupPreview, setGroupPreview] = useState(null); + const flatListRef = useRef(null); // We track the editor focus state to determine when we need to scroll to the // bottom of the screen when the keyboard is opened/editor is focused. @@ -112,9 +122,49 @@ export function PostScreenView({ return editingPost && editingPost.id === parentPost?.id; }, [editingPost, parentPost]); + const onPressGroupRef = useCallback((group: db.Group) => { + setGroupPreview(group); + }, []); + + const handleGroupAction = useCallback( + (action: GroupPreviewAction, group: db.Group) => { + onGroupAction(action, group); + setGroupPreview(null); + }, + [onGroupAction] + ); + + const handleRefPress = useCallback( + (refChannel: db.Channel, post: db.Post) => { + const anchorIndex = posts?.findIndex((p) => p.id === post.id) ?? -1; + + if ( + refChannel.id === channel.id && + anchorIndex !== -1 && + flatListRef.current + ) { + // If the post is already loaded, scroll to it + flatListRef.current?.scrollToIndex({ + index: anchorIndex, + animated: false, + viewPosition: 0.5, + }); + return; + } + + onPressRef(refChannel, post); + }, + [onPressRef, posts, channel] + ); + return ( - + ) : null} @@ -212,6 +263,12 @@ export function PostScreenView({ /> )} + setGroupPreview(null)} + onActionComplete={handleGroupAction} + /> From c51104e40ed25a8fe21d7016cb96c5d0942bda74 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 09:58:15 -0500 Subject: [PATCH 088/259] fix import for useGroupActions --- packages/app/features/top/PostScreen.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/app/features/top/PostScreen.tsx b/packages/app/features/top/PostScreen.tsx index f84d6f045f..5c46f40905 100644 --- a/packages/app/features/top/PostScreen.tsx +++ b/packages/app/features/top/PostScreen.tsx @@ -3,11 +3,11 @@ import * as db from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import * as urbit from '@tloncorp/shared/dist/urbit'; import { PostScreenView, useCurrentUserId } from '@tloncorp/ui'; -import { useGroupActions } from 'packages/app/hooks/useGroupActions'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useChannelContext } from '../../hooks/useChannelContext'; import { useChannelNavigation } from '../../hooks/useChannelNavigation'; +import { useGroupActions } from '../../hooks/useGroupActions'; import type { RootStackParamList } from '../../navigation/types'; type Props = NativeStackScreenProps; @@ -31,10 +31,9 @@ export default function PostScreen(props: Props) { uploaderKey: `${postParam.channelId}/${postParam.id}`, }); - const { navigateToImage, navigateToRef } = - useChannelNavigation({ - channelId: postParam.channelId, - }); + const { navigateToImage, navigateToRef } = useChannelNavigation({ + channelId: postParam.channelId, + }); const currentUserId = useCurrentUserId(); From 8ddff962b4f9941cf9c26ca8cf740c0003d3c902 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 10:06:34 -0500 Subject: [PATCH 089/259] fix fixtures --- .../src/fixtures/DetailView/detailViewFixtureBase.tsx | 3 +++ apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx b/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx index f0deeb7638..77b9db7de4 100644 --- a/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx +++ b/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx @@ -56,6 +56,9 @@ export const DetailViewFixture = ({ canUpload={true} handleGoToUserProfile={() => {}} headerMode="default" + onPressRef={() => {}} + onGroupAction={() => {}} + goToDm={() => {}} /> diff --git a/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx b/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx index 9a81df5f73..65f41277bf 100644 --- a/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/PostScreen.fixture.tsx @@ -39,6 +39,9 @@ export default ( clearDraft={() => {}} canUpload={true} headerMode="default" + onPressRef={() => {}} + onGroupAction={() => {}} + goToDm={() => {}} /> ); From f3328f280ce421fe41a08d6f8d79603cae9a81ea Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 16 Oct 2024 11:28:26 -0400 Subject: [PATCH 090/259] AddGalleryPost: avoid saying "Video" or "Rich" (text) --- packages/ui/src/components/AddGalleryPost.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/AddGalleryPost.tsx b/packages/ui/src/components/AddGalleryPost.tsx index 3d80885fe0..d95bc81530 100644 --- a/packages/ui/src/components/AddGalleryPost.tsx +++ b/packages/ui/src/components/AddGalleryPost.tsx @@ -21,14 +21,14 @@ export default function AddGalleryPost({ const actions = [ { - title: 'Photo or Video', + title: 'Image', action: () => { setShowAddGalleryPost(false); setShowAttachmentSheet(true); }, }, { - title: 'Rich Text', + title: 'Text', action: () => { setShowAddGalleryPost(false); setShowGalleryInput(true); From 09cf094bd39f13eb4d0b32e9e0d8244b0f5c1833 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 15 Oct 2024 13:38:29 -0500 Subject: [PATCH 091/259] notebooks: represent hidden and deleted states for posts --- .../components/NotebookPost/NotebookPost.tsx | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/packages/ui/src/components/NotebookPost/NotebookPost.tsx b/packages/ui/src/components/NotebookPost/NotebookPost.tsx index 70f0b9fdd2..309242f5b4 100644 --- a/packages/ui/src/components/NotebookPost/NotebookPost.tsx +++ b/packages/ui/src/components/NotebookPost/NotebookPost.tsx @@ -88,31 +88,48 @@ export function NotebookPost({ pressStyle={{ backgroundColor: '$secondaryBackground' }} disabled={viewMode === 'activity'} > - - - {viewMode !== 'activity' && ( - - {post.textContent} - - )} + + {post.hidden + ? 'You have hidden this post.' + : 'This post has been deleted.'} + + + ) : ( + <> + - {showReplies && hasReplies ? ( - - ) : null} + {viewMode !== 'activity' && ( + + {post.textContent} + + )} + + {showReplies && hasReplies ? ( + + ) : null} + + )} {post.deliveryStatus === 'failed' ? ( From 5fa8367272684666330a9031b6a3bd0443268317 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 16 Oct 2024 12:00:56 -0500 Subject: [PATCH 092/259] don't show deleted posts in galleries or notebooks --- packages/app/features/top/ChannelScreen.tsx | 8 +++++++- packages/ui/src/components/GalleryPost/GalleryPost.tsx | 4 ++++ packages/ui/src/components/NotebookPost/NotebookPost.tsx | 8 +++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index 4ddc106aaf..c4b32053ae 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -198,6 +198,12 @@ export default function ChannelScreen(props: Props) { }), }); + const filteredPosts = useMemo( + () => + channel?.type !== 'chat' ? posts?.filter((p) => !p.isDeleted) : posts, + [posts, channel] + ); + const sendPost = useCallback( async (content: Story, _channelId: string, metadata?: db.PostMetadata) => { if (!channel) { @@ -313,7 +319,7 @@ export default function ChannelScreen(props: Props) { hasNewerPosts={postsQuery.hasPreviousPage} hasOlderPosts={postsQuery.hasNextPage} group={group} - posts={posts} + posts={filteredPosts ?? null} selectedPostId={selectedPostId} goBack={props.navigation.goBack} messageSender={sendPost} diff --git a/packages/ui/src/components/GalleryPost/GalleryPost.tsx b/packages/ui/src/components/GalleryPost/GalleryPost.tsx index 7aa8d4bbe4..9fd32c8d58 100644 --- a/packages/ui/src/components/GalleryPost/GalleryPost.tsx +++ b/packages/ui/src/components/GalleryPost/GalleryPost.tsx @@ -64,6 +64,10 @@ export function GalleryPost({ const handleLongPress = useBoundHandler(post, onLongPress); + if (post.isDeleted) { + return null; + } + return ( - {post.hidden || post.isDeleted ? ( + {post.hidden ? ( - {post.hidden - ? 'You have hidden this post.' - : 'This post has been deleted.'} + You have hidden this post. ) : ( From dc39c1d5308e268793f585c3e24a59bf9f68a91e Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 17 Oct 2024 09:21:34 -0500 Subject: [PATCH 093/259] http-api: move polyfills out causing issues with tests --- packages/app/hooks/useConfigureUrbitClient.ts | 42 +++++++++++++++ packages/shared/src/api/urbit.ts | 5 +- packages/shared/src/http-api/Urbit.ts | 53 +++++++++---------- 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 68998bcf32..0a1de8177a 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -2,6 +2,12 @@ import { createDevLogger, sync } from '@tloncorp/shared/dist'; import { ClientParams } from '@tloncorp/shared/dist/api'; import { configureClient } from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; +//@ts-expect-error no typedefs +import { fetch as streamingFetch } from 'react-native-fetch-api'; +//@ts-expect-error no typedefs +import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; +//@ts-expect-error no typedefs +import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; import { ENABLED_LOGGERS } from '../constants'; import { useShip } from '../contexts/ship'; @@ -9,8 +15,43 @@ import { getShipAccessCode } from '../lib/hostingApi'; import { resetDb } from '../lib/nativeDb'; import { useHandleLogout } from './useHandleLogout'; +polyfillReadableStream(); +polyfillEncoding(); + +let abortController = new AbortController(); + const clientLogger = createDevLogger('configure client', true); +const apiFetch: typeof fetch = (input, { ...init } = {}) => { + // Wire our injected AbortController up to the one passed in by the client. + if (init.signal) { + init.signal.onabort = () => { + abortController.abort(); + abortController = new AbortController(); + }; + } + + const headers = new Headers(init.headers); + // The urbit client is inconsistent about sending cookies, sometimes causing + // the server to send back a new, anonymous, cookie, which is sent on all + // subsequent requests and screws everything up. This ensures that explicit + // cookie headers are never set, delegating all cookie handling to the + // native http client. + headers.delete('Cookie'); + headers.delete('cookie'); + const newInit: RequestInit = { + ...init, + headers, + // Avoid setting credentials method for same reason as above. + credentials: undefined, + signal: abortController.signal, + // @ts-expect-error This is used by the SSE polyfill to determine whether + // to stream the request. + reactNative: { textStreaming: true }, + }; + return streamingFetch(input, newInit); +}; + export function useConfigureUrbitClient() { const shipInfo = useShip(); const { ship, shipUrl, authType } = shipInfo; @@ -27,6 +68,7 @@ export function useConfigureUrbitClient() { shipName: params?.shipName ?? ship ?? '', shipUrl: params?.shipUrl ?? shipUrl ?? '', verbose: ENABLED_LOGGERS.includes('urbit'), + fetchFn: apiFetch, onQuitOrReset: sync.handleDiscontinuity, onChannelStatusChange: sync.handleChannelStatusChange, getCode: diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 3a76143b7e..c308bd97dd 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -1,4 +1,3 @@ -import { deSig, preSig } from '@urbit/aura'; import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; @@ -51,6 +50,7 @@ export interface ClientParams { shipName: string; shipUrl: string; verbose?: boolean; + fetchFn?: typeof fetch; getCode?: () => Promise; handleAuthFailure?: () => void; onQuitOrReset?: () => void; @@ -98,13 +98,14 @@ export function internalConfigureClient({ shipName, shipUrl, verbose, + fetchFn, getCode, handleAuthFailure, onQuitOrReset, onChannelStatusChange, }: ClientParams) { logger.log('configuring client', shipName, shipUrl); - config.client = config.client || new Urbit(shipUrl, '', ''); + config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.verbose = verbose; config.shipUrl = shipUrl; config.onQuitOrReset = onQuitOrReset; diff --git a/packages/shared/src/http-api/Urbit.ts b/packages/shared/src/http-api/Urbit.ts index 25795b0d11..49f55d48ef 100644 --- a/packages/shared/src/http-api/Urbit.ts +++ b/packages/shared/src/http-api/Urbit.ts @@ -1,10 +1,4 @@ import { isBrowser } from 'browser-or-node'; -//@ts-expect-error no typedefs -import { fetch as streamingFetch } from 'react-native-fetch-api'; -//@ts-expect-error no typedefs -import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; -//@ts-expect-error no typedefs -import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; import { UrbitHttpApiEvent, UrbitHttpApiEventType } from './events'; import { EventSourceMessage, fetchEventSource } from './fetch-event-source'; @@ -25,11 +19,6 @@ import { } from './types'; import EventEmitter, { hexString } from './utils'; -polyfillReadableStream(); -polyfillEncoding(); - -let abortController = new AbortController(); - /** * A class for interacting with an urbit ship, given its URL and code */ @@ -86,6 +75,11 @@ export class Urbit { private outstandingSubscriptions: Map = new Map(); + /** + * Our abort controller, used to close the connection + */ + private abort = new AbortController(); + /** * Identity of the ship we're connected to */ @@ -106,6 +100,11 @@ export class Urbit { */ private errorCount = 0; + /** + * Custom fetch implementation to use. + */ + fetchFn: typeof fetch = (...args) => fetch(...args); + /** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */ private get channelUrl(): string { return `${this.url}/~/channel/${this.uid}`; @@ -120,7 +119,7 @@ export class Urbit { credentials: isBrowser ? 'include' : undefined, accept: '*', headers, - signal: abortController.signal, + signal: this.abort.signal, reactNative: { textStreaming: true }, }; } @@ -136,11 +135,15 @@ export class Urbit { constructor( public url: string, public code?: string, - public desk?: string + public desk?: string, + fetchFn?: typeof fetch ) { if (isBrowser) { window.addEventListener('beforeunload', this.delete); } + if (fetchFn) { + this.fetchFn = fetchFn; + } return this; } @@ -210,7 +213,7 @@ export class Urbit { return Promise.resolve(); } - const nameResp = await streamingFetch(`${this.url}/~/host`, { + const nameResp = await this.fetchFn(`${this.url}/~/host`, { method: 'get', credentials: 'include', }); @@ -227,7 +230,7 @@ export class Urbit { return Promise.resolve(); } - const nameResp = await streamingFetch(`${this.url}/~/name`, { + const nameResp = await this.fetchFn(`${this.url}/~/name`, { method: 'get', credentials: 'include', }); @@ -251,7 +254,7 @@ export class Urbit { : 'Connecting from node context' ); } - return streamingFetch(`${this.url}/~/login`, { + return this.fetchFn(`${this.url}/~/login`, { method: 'post', body: `password=${this.code}`, credentials: 'include', @@ -304,7 +307,7 @@ export class Urbit { ...this.fetchOptions, openWhenHidden: true, responseTimeout: 25000, - fetch: streamingFetch, + fetch: this.fetchFn, onopen: async (response, isReconnect) => { if (this.verbose) { console.log('Opened eventsource', response); @@ -509,7 +512,7 @@ export class Urbit { } private async sendJSONtoChannel(...json: (Message | Ack)[]): Promise { - const response = await streamingFetch(this.channelUrl, { + const response = await this.fetchFn(this.channelUrl, { ...this.fetchOptions, method: 'PUT', body: JSON.stringify(json), @@ -690,16 +693,12 @@ export class Urbit { }); } - abort() { - abortController.abort(); - abortController = new AbortController(); - } - /** * Deletes the connection to a channel. */ async delete() { - this.abort(); + this.abort.abort(); + this.abort = new AbortController(); const body = JSON.stringify([ { id: this.getEventId(), @@ -709,7 +708,7 @@ export class Urbit { if (isBrowser) { navigator.sendBeacon(this.channelUrl, body); } else { - const response = await streamingFetch(this.channelUrl, { + const response = await this.fetchFn(this.channelUrl, { ...this.fetchOptions, method: 'POST', body: body, @@ -738,7 +737,7 @@ export class Urbit { */ async scry(params: Scry): Promise { const { app, path } = params; - const response = await streamingFetch( + const response = await this.fetchFn( `${this.url}/~/scry/${app}${path}.json`, this.fetchOptions ); @@ -771,7 +770,7 @@ export class Urbit { if (!desk) { throw new Error('Must supply desk to run thread from'); } - const res = await streamingFetch( + const res = await this.fetchFn( `${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`, { ...this.fetchOptions, From 18e50e0925495f3fca689fde5673a7a793d5ba75 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 17 Oct 2024 09:33:05 -0500 Subject: [PATCH 094/259] ops: fix imports --- packages/app/package.json | 6 ++++-- packages/shared/package.json | 3 --- pnpm-lock.yaml | 6 ++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index 8ccc9b365c..cded025bb5 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -7,8 +7,10 @@ "test": "vitest --watch false" }, "dependencies": { - "@tloncorp/ui": "workspace:*", "@tloncorp/shared": "workspace:*", + "@tloncorp/ui": "workspace:*", + "react-native-fetch-api": "^3.0.0", + "react-native-polyfill-globals": "^3.1.0", "sqlocal": "^0.11.1" }, "devDependencies": { @@ -17,8 +19,8 @@ }, "peerDependencies": { "@react-native-firebase/perf": "19.2.2", - "react-native-device-info": "^10.8.0", "lodash": "^4.17.21", + "react-native-device-info": "^10.8.0", "zustand": "^3.7.2" } } diff --git a/packages/shared/package.json b/packages/shared/package.json index ea36736a84..aff8744ef1 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -28,13 +28,10 @@ "dependencies": { "@react-native-async-storage/async-storage": "1.21.0", "@urbit/aura": "^1.0.0", - "@urbit/http-api": "3.2.0-dev", "any-ascii": "^0.3.1", "big-integer": "^1.6.52", "browser-or-node": "^3.0.0", "exponential-backoff": "^3.1.1", - "react-native-fetch-api": "^3.0.0", - "react-native-polyfill-globals": "^3.1.0", "sorted-btree": "^1.8.1" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ad790f854..d7b6cb76a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1542,6 +1542,12 @@ importers: react-native-device-info: specifier: ^10.8.0 version: 10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)) + react-native-fetch-api: + specifier: ^3.0.0 + version: 3.0.0 + react-native-polyfill-globals: + specifier: ^3.1.0 + version: 3.1.0(base-64@1.0.0)(react-native-fetch-api@3.0.0)(react-native-get-random-values@1.11.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(react-native-url-polyfill@2.0.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(text-encoding@0.7.0)(web-streams-polyfill@3.3.3) sqlocal: specifier: ^0.11.1 version: 0.11.1(drizzle-orm@0.30.9(patch_hash=cegrec33e6f7d6ltk7vff5r7w4)(@op-engineering/op-sqlite@5.0.5(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(@opentelemetry/api@1.8.0)(@types/better-sqlite3@7.6.9)(@types/react@18.2.55)(better-sqlite3@9.4.5)(react@18.2.0)) From b7b8c9c6496059489d75985370346f3b984ecad3 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 10:39:11 -0400 Subject: [PATCH 095/259] log it --- packages/shared/src/debug.ts | 2 +- packages/ui/src/components/InviteFriendsToTlonButton.tsx | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/debug.ts b/packages/shared/src/debug.ts index 29c215cbb9..900c21e86b 100644 --- a/packages/shared/src/debug.ts +++ b/packages/shared/src/debug.ts @@ -98,7 +98,7 @@ export function createDevLogger(tag: string, enabled: boolean) { if (args[0] && typeof args[0] === 'string') { const customProps = args[1] && typeof args[1] === 'object' ? args[1] : {}; - remoteLoggerInstance?.capture('app_error', { + remoteLoggerInstance?.capture(args[0], { ...customProps, message: `[${tag}] ${args[0]}`, }); diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index 5ad133ac26..db208ddcc9 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -54,8 +54,9 @@ export function InviteFriendsToTlonButton({ }); if (result.action === Share.sharedAction) { - // onShare?.(shareUrl.split('/').pop() ?? ''); - // logger.trackeve + logger.trackEvent(AnalyticsEvent.InviteShared, { + inviteId: shareUrl.split('/').pop() ?? null, + }); } } catch (error) { console.error('Error sharing:', error); From 35633842d635542e0145c2aff9586a9fee30f081 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 17 Oct 2024 09:39:19 -0500 Subject: [PATCH 096/259] ops: fix lock file --- pnpm-lock.yaml | 975 +------------------------------------------------ 1 file changed, 6 insertions(+), 969 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7b6cb76a9..478ed1bd5d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -342,7 +342,7 @@ importers: version: 29.7.0 '@react-native/metro-config': specifier: ^0.73.5 - version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13) + version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) '@tamagui/babel-plugin': specifier: ~1.112.12 version: 1.112.12(@swc/helpers@0.5.13)(encoding@0.1.13)(react@18.2.0) @@ -1566,7 +1566,7 @@ importers: dependencies: '@10play/tentap-editor': specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1634,9 +1634,6 @@ importers: '@urbit/aura': specifier: ^1.0.0 version: 1.0.0(big-integer@1.6.52) - '@urbit/http-api': - specifier: 3.2.0-dev - version: 3.2.0-dev any-ascii: specifier: ^0.3.1 version: 0.3.2(patch_hash=5ofxtlxe6za2xqrbq5pqbz7wb4) @@ -1655,12 +1652,6 @@ importers: react: specifier: ^18.2.0 version: 18.2.0 - react-native-fetch-api: - specifier: ^3.0.0 - version: 3.0.0 - react-native-polyfill-globals: - specifier: ^3.1.0 - version: 3.1.0(base-64@1.0.0)(react-native-fetch-api@3.0.0)(react-native-get-random-values@1.11.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(react-native-url-polyfill@2.0.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(text-encoding@0.7.0)(web-streams-polyfill@3.3.3) sorted-btree: specifier: ^1.8.1 version: 1.8.1 @@ -13678,43 +13669,6 @@ packages: snapshots: - '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': - dependencies: - '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-bold': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-bullet-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-code': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-code-block': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) - '@tiptap/extension-document': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-heading': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-history': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-horizontal-rule': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-italic': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-link': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-list-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-ordered-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-placeholder': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-strike': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-task-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-task-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/pm': 2.6.6 - '@tiptap/react': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) - lodash: 4.17.21 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) - react-native-webview: 13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - transitivePeerDependencies: - - '@tiptap/core' - '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) @@ -14608,19 +14562,6 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14634,13 +14575,6 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.24.7 - regexpu-core: 5.3.2 - semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14648,17 +14582,6 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.4 - transitivePeerDependencies: - - supports-color - '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14670,17 +14593,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.4 - transitivePeerDependencies: - - supports-color - '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14727,16 +14639,6 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.6 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14755,13 +14657,6 @@ snapshots: '@babel/helper-plugin-utils@7.24.8': {} - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14769,13 +14664,6 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 - '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14858,23 +14746,11 @@ snapshots: dependencies: '@babel/types': 7.25.6 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14882,26 +14758,12 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.25.2) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14910,12 +14772,6 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14929,12 +14785,6 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14947,39 +14797,18 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7)': - dependencies: - '@babel/compat-data': 7.25.2 - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -14989,25 +14818,12 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15015,19 +14831,10 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15038,21 +14845,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15063,81 +14860,41 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15148,136 +14905,67 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15286,63 +14974,31 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7)': + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15350,18 +15006,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) - '@babel/helper-split-export-declaration': 7.22.6 - globals: 11.12.0 - '@babel/plugin-transform-classes@7.23.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15374,117 +15018,58 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 - '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/template': 7.25.0 - '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 - '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15492,58 +15077,28 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15552,15 +15107,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-simple-access': 7.22.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15570,16 +15116,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-validator-identifier': 7.22.20 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15590,14 +15126,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15606,61 +15134,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15670,37 +15166,18 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) - '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.25.2) - '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15708,36 +15185,17 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15746,21 +15204,11 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15802,17 +15250,6 @@ snapshots: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) '@babel/types': 7.25.6 - '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) - '@babel/types': 7.25.6 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15830,40 +15267,17 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - regenerator-transform: 0.15.2 - '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) - babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.7) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15876,66 +15290,32 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-spread@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15944,138 +15324,29 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/preset-env@7.23.7(@babel/core@7.23.7)': - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.23.7) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.23.7) - '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) - '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) - babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) - babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) - core-js-compat: 3.35.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/preset-env@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -16169,13 +15440,6 @@ snapshots: '@babel/helper-validator-option': 7.24.8 '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.25.2) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/types': 7.25.6 - esutils: 2.0.3 - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -18552,13 +17816,6 @@ snapshots: '@react-native/assets-registry@0.73.1': {} - '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -18566,54 +17823,6 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/babel-preset@0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.23.7) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-react-jsx': 7.25.2(@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) - '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.23.7) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) - '@babel/template': 7.25.0 - '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.23.7) - react-refresh: 0.14.0 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - '@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -18662,19 +17871,6 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@babel/parser': 7.25.3 - '@babel/preset-env': 7.23.7(@babel/core@7.23.7) - flow-parser: 0.206.0 - glob: 7.2.3 - invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - mkdirp: 0.5.6 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/parser': 7.25.3 @@ -18709,27 +17905,6 @@ snapshots: - supports-color - utf-8-validate - '@react-native/community-cli-plugin@0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) - '@react-native-community/cli-tools': 12.3.7(encoding@0.1.13) - '@react-native/dev-middleware': 0.73.8(encoding@0.1.13) - '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - chalk: 4.1.2 - execa: 5.1.1 - metro: 0.80.5(encoding@0.1.13) - metro-config: 0.80.5(encoding@0.1.13) - metro-core: 0.80.5 - node-fetch: 2.6.12(encoding@0.1.13) - readline: 1.3.0 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - bufferutil - - encoding - - supports-color - - utf-8-validate - '@react-native/community-cli-plugin@0.73.18(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) @@ -18776,16 +17951,6 @@ snapshots: '@react-native/js-polyfills@0.73.1': {} - '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@babel/core': 7.23.7 - '@react-native/babel-preset': 0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - hermes-parser: 0.15.0 - nullthrows: 1.1.1 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -18796,7 +17961,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': + '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/js-polyfills': 0.73.1 '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -18805,10 +17970,7 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - - bufferutil - - encoding - supports-color - - utf-8-validate '@react-native/normalize-color@2.1.0': {} @@ -18816,12 +17978,6 @@ snapshots: '@react-native/normalize-colors@0.74.84': {} - '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) - '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))': dependencies: invariant: 2.2.4 @@ -21658,15 +20814,6 @@ snapshots: cosmiconfig: 7.1.0 resolve: 1.22.4 - babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.7): - dependencies: - '@babel/compat-data': 7.25.2 - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.25.2): dependencies: '@babel/compat-data': 7.25.2 @@ -21676,14 +20823,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) - core-js-compat: 3.35.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -21692,14 +20831,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.7): - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) - core-js-compat: 3.35.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -21708,13 +20839,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.7): - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -21726,12 +20850,6 @@ snapshots: babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.23.7): - dependencies: - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) - transitivePeerDependencies: - - '@babel/core' - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2): dependencies: '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) @@ -25262,31 +24380,6 @@ snapshots: jsc-safe-url@0.2.4: {} - jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)): - dependencies: - '@babel/core': 7.25.2 - '@babel/parser': 7.25.6 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.25.2) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.25.2) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.25.2) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.25.2) - '@babel/preset-env': 7.23.7(@babel/core@7.23.7) - '@babel/preset-flow': 7.23.3(@babel/core@7.25.2) - '@babel/preset-typescript': 7.23.3(@babel/core@7.25.2) - '@babel/register': 7.23.7(@babel/core@7.25.2) - babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) - chalk: 4.1.2 - flow-parser: 0.206.0 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - neo-async: 2.6.2 - node-dir: 0.1.17 - recast: 0.21.5 - temp: 0.8.4 - write-file-atomic: 2.4.3 - transitivePeerDependencies: - - supports-color - jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.25.2)): dependencies: '@babel/core': 7.25.2 @@ -27320,13 +26413,6 @@ snapshots: transitivePeerDependencies: - encoding - react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): - dependencies: - escape-string-regexp: 2.0.0 - invariant: 2.2.4 - react: 18.2.0 - react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) - react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: escape-string-regexp: 2.0.0 @@ -27388,55 +26474,6 @@ snapshots: - supports-color - utf-8-validate - react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0): - dependencies: - '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 12.3.7(encoding@0.1.13) - '@react-native-community/cli-platform-android': 12.3.7(encoding@0.1.13) - '@react-native-community/cli-platform-ios': 12.3.7(encoding@0.1.13) - '@react-native/assets-registry': 0.73.1 - '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13) - '@react-native/gradle-plugin': 0.73.4 - '@react-native/js-polyfills': 0.73.1 - '@react-native/normalize-colors': 0.73.2 - '@react-native/virtualized-lists': 0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0)) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - base64-js: 1.5.1 - chalk: 4.1.2 - deprecated-react-native-prop-types: 5.0.0 - event-target-shim: 5.0.1 - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - jest-environment-node: 29.7.0 - jsc-android: 250231.0.0 - memoize-one: 5.2.1 - metro-runtime: 0.80.5 - metro-source-map: 0.80.5 - mkdirp: 0.5.6 - nullthrows: 1.1.1 - pretty-format: 26.6.2 - promise: 8.3.0 - react: 18.2.0 - react-devtools-core: 4.28.5 - react-refresh: 0.14.0 - react-shallow-renderer: 16.15.0(react@18.2.0) - regenerator-runtime: 0.13.11 - scheduler: 0.24.0-canary-efb381bbf-20230505 - stacktrace-parser: 0.1.10 - whatwg-fetch: 3.6.20 - ws: 6.2.2 - yargs: 17.7.2 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - bufferutil - - encoding - - supports-color - - utf-8-validate - react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0): dependencies: '@jest/create-cache-key-function': 29.7.0 From e7a406c5799161cba4244bc66d36436a3c1e084c Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 10:41:39 -0400 Subject: [PATCH 097/259] rip it all out --- apps/tlon-mobile/src/fixtures/Channel.fixture.tsx | 1 - packages/app/features/top/ChannelScreen.tsx | 7 ------- packages/app/features/top/ChatListScreen.tsx | 7 +------ packages/app/features/top/GroupChannelsScreen.tsx | 6 ------ packages/app/utils/posthog.ts | 4 ---- .../ui/src/components/Channel/EmptyChannelNotice.tsx | 4 +--- packages/ui/src/components/Channel/index.tsx | 12 ++---------- .../ui/src/components/InviteFriendsToTlonButton.tsx | 1 - packages/ui/src/components/InviteUsersSheet.tsx | 8 +------- packages/ui/src/components/InviteUsersWidget.tsx | 4 +--- 10 files changed, 6 insertions(+), 48 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx index fa54a34fd3..9e3dae72a4 100644 --- a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx @@ -112,7 +112,6 @@ const baseProps: ComponentProps = { canUpload: true, onPressRetry: () => {}, onPressDelete: () => {}, - onShareInvite: () => {}, } as const; export const ChannelFixture = (props: { diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index 893e76d6e1..c4b32053ae 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -27,7 +27,6 @@ import { useChannelNavigation } from '../../hooks/useChannelNavigation'; import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation'; import { useGroupActions } from '../../hooks/useGroupActions'; import type { RootStackParamList } from '../../navigation/types'; -import { trackInviteShared } from '../../utils/posthog'; const logger = createDevLogger('ChannelScreen', false); @@ -298,10 +297,6 @@ export default function ChannelScreen(props: Props) { } }, []); - const handleShareInvite = useCallback((lure: string) => { - trackInviteShared(lure); - }, []); - if (!channel) { return null; } @@ -354,7 +349,6 @@ export default function ChannelScreen(props: Props) { editPost={editPost} negotiationMatch={negotiationStatus.matchedOrPending} canUpload={canUpload} - onShareInvite={handleShareInvite} /> {group && ( <> @@ -370,7 +364,6 @@ export default function ChannelScreen(props: Props) { onOpenChange={handleInviteSheetOpenChange} onInviteComplete={() => setInviteSheetGroup(null)} group={inviteSheetGroup ?? undefined} - onShareInvite={handleShareInvite} /> )} diff --git a/packages/app/features/top/ChatListScreen.tsx b/packages/app/features/top/ChatListScreen.tsx index 83ef90dc81..f74e27935b 100644 --- a/packages/app/features/top/ChatListScreen.tsx +++ b/packages/app/features/top/ChatListScreen.tsx @@ -25,7 +25,7 @@ import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation import { useCurrentUserId } from '../../hooks/useCurrentUser'; import { useFeatureFlag } from '../../lib/featureFlags'; import type { RootStackParamList } from '../../navigation/types'; -import { identifyTlonEmployee, trackInviteShared } from '../../utils/posthog'; +import { identifyTlonEmployee } from '../../utils/posthog'; import { isSplashDismissed, setSplashDismissed } from '../../utils/splash'; const logger = createDevLogger('ChatListScreen', false); @@ -266,10 +266,6 @@ export default function ChatListScreen(props: Props) { setShowSearchInput(!showSearchInput); }, [showSearchInput]); - const handleShareInvite = useCallback((lure: string) => { - trackInviteShared(lure); - }, []); - return ( setInviteSheetGroup(null)} group={inviteSheetGroup ?? undefined} - onShareInvite={handleShareInvite} /> ; @@ -48,10 +47,6 @@ export function GroupChannelsScreen({ navigation, route }: Props) { navigation.goBack(); }, [navigation]); - const handleShareInvite = useCallback((lure: string) => { - trackInviteShared(lure); - }, []); - return ( setInviteSheetGroup(null)} - onShareInvite={handleShareInvite} /> ); diff --git a/packages/app/utils/posthog.ts b/packages/app/utils/posthog.ts index 6ee74575ee..adee85053a 100644 --- a/packages/app/utils/posthog.ts +++ b/packages/app/utils/posthog.ts @@ -69,7 +69,3 @@ export const identifyTlonEmployee = () => { posthog.identify(UUID, { isTlonEmployee: true }); db.setIsTlonEmployee(true); }; - -export const trackInviteShared = (lure: string) => { - capture('Invite Link Shared', { lure }); -}; diff --git a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx index de1eced27e..fe5e975925 100644 --- a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx +++ b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx @@ -9,11 +9,9 @@ import { InviteFriendsToTlonButton } from '../InviteFriendsToTlonButton'; export function EmptyChannelNotice({ channel, userId, - onShareInvite, }: { channel: db.Channel; userId: string; - onShareInvite?: (lure: string) => void; }) { const isGroupAdmin = useIsAdmin(channel.groupId ?? '', userId); const group = useGroup(channel.groupId ?? ''); @@ -40,7 +38,7 @@ export function EmptyChannelNotice({ {isGroupAdmin && isWelcomeChannel && ( - + )} ); diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 9a52078d1c..6c14889b49 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -70,7 +70,6 @@ export function Channel({ useGroup, usePostReference, onGroupAction, - onShareInvite, useChannel, storeDraft, clearDraft, @@ -111,7 +110,6 @@ export function Channel({ useGroup: typeof useGroupPreview; usePostReference: typeof usePostReferenceHook; onGroupAction: (action: GroupPreviewAction, group: db.Group) => void; - onShareInvite?: (lure: string) => void; useChannel: typeof useChannelFromStore; storeDraft: (draft: JSONContent, draftType?: GalleryDraftType) => void; clearDraft: (draftType?: GalleryDraftType) => void; @@ -144,14 +142,8 @@ export function Channel({ : GalleryPost; const renderEmptyComponent = useCallback(() => { - return ( - - ); - }, [currentUserId, channel, onShareInvite]); + return ; + }, [currentUserId, channel]); const onPressGroupRef = useCallback((group: db.Group) => { setGroupPreview(group); diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index db208ddcc9..98a24f6bd8 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -16,7 +16,6 @@ const logger = createDevLogger('InviteButton', true); export function InviteFriendsToTlonButton({ group, - onShare, }: { group?: db.Group; onShare?: (lure: string) => void; diff --git a/packages/ui/src/components/InviteUsersSheet.tsx b/packages/ui/src/components/InviteUsersSheet.tsx index f8b5c60398..e4bbac26c5 100644 --- a/packages/ui/src/components/InviteUsersSheet.tsx +++ b/packages/ui/src/components/InviteUsersSheet.tsx @@ -10,13 +10,11 @@ const InviteUsersSheetComponent = ({ onOpenChange, group, onInviteComplete, - onShareInvite, }: { open: boolean; onOpenChange: (open: boolean) => void; group?: db.Group; onInviteComplete: () => void; - onShareInvite?: (lure: string) => void; }) => { const { bottom } = useSafeAreaInsets(); const hasOpened = useRef(open); @@ -35,11 +33,7 @@ const InviteUsersSheetComponent = ({ snapPointsMode="percent" > - + ); diff --git a/packages/ui/src/components/InviteUsersWidget.tsx b/packages/ui/src/components/InviteUsersWidget.tsx index a13497ab06..a3c3cf0f47 100644 --- a/packages/ui/src/components/InviteUsersWidget.tsx +++ b/packages/ui/src/components/InviteUsersWidget.tsx @@ -10,11 +10,9 @@ import { InviteFriendsToTlonButton } from './InviteFriendsToTlonButton'; const InviteUsersWidgetComponent = ({ group, onInviteComplete, - onShareInvite, }: { group: db.Group; onInviteComplete: () => void; - onShareInvite?: (lure: string) => void; }) => { const [invitees, setInvitees] = useState([]); @@ -38,7 +36,7 @@ const InviteUsersWidgetComponent = ({ return ( <> - + Date: Thu, 17 Oct 2024 10:47:45 -0400 Subject: [PATCH 098/259] whoops, straggler prop --- packages/ui/src/components/InviteFriendsToTlonButton.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index 98a24f6bd8..dd6c2ea229 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -14,12 +14,7 @@ import { LoadingSpinner } from './LoadingSpinner'; const logger = createDevLogger('InviteButton', true); -export function InviteFriendsToTlonButton({ - group, -}: { - group?: db.Group; - onShare?: (lure: string) => void; -}) { +export function InviteFriendsToTlonButton({ group }: { group?: db.Group }) { const userId = useCurrentUserId(); const isGroupAdmin = useIsAdmin(group?.id ?? '', userId); const branchDomain = useBranchDomain(); From 6af1d484c38309831daf4a75848fe875ddb5e242 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 14:02:49 -0400 Subject: [PATCH 099/259] fix ship setting for manual params, use boot counter to ensure loop never gets stuck --- .../src/screens/Onboarding/ReserveShipScreen.tsx | 7 ++++--- packages/app/hooks/useBootSequence.ts | 9 ++++++++- packages/shared/src/api/urbit.ts | 2 ++ packages/shared/src/http-api/Urbit.ts | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index 7ce4e50558..fa3eff19ac 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -31,11 +31,12 @@ export const ReserveShipScreen = ({ navigation }: Props) => { - Setting up your new p2p node + Booting your new P2P node for the first time... - + {/* TOOD: add back in when design is ready */} + {/* {BootPhaseExplanations[signupContext.bootPhase]} - + */} ); diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index 14ecbfb4aa..77a4779eb9 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -110,6 +110,8 @@ export function useBootSequence({ authType: 'hosted', }); + await wait(2000); + configureUrbitClient({ shipName: auth.nodeId, shipUrl: auth.nodeUrl }); store.syncStart(); @@ -229,6 +231,7 @@ export function useBootSequence({ return bootPhase; }, [ bootPhase, + configureUrbitClient, connectionStatus, hostingUser, lureMeta, @@ -236,6 +239,9 @@ export function useBootSequence({ setShip, ]); + // we increment a counter to ensure the effect executes after every run, even if + // the step didn't advance + const [bootStepCounter, setBootCounter] = useState(0); useEffect(() => { const runBootSequence = async () => { // prevent simultaneous runs @@ -272,6 +278,7 @@ export function useBootSequence({ setBootPhase(bootPhase); } finally { isRunningRef.current = false; + setBootCounter((c) => c + 1); } }; @@ -291,7 +298,7 @@ export function useBootSequence({ if (![NodeBootPhase.IDLE, NodeBootPhase.READY].includes(bootPhase)) { runBootSequence(); } - }, [runBootPhase, setBootPhase, bootPhase]); + }, [runBootPhase, setBootPhase, bootPhase, bootStepCounter]); // once finished, set the report useEffect(() => { diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index c308bd97dd..be6caf0cfd 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -2,6 +2,7 @@ import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; import { AuthError, ChannelStatus, PokeInterface, Urbit } from '../http-api'; +import { desig } from '../urbit'; import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); @@ -107,6 +108,7 @@ export function internalConfigureClient({ logger.log('configuring client', shipName, shipUrl); config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.verbose = verbose; + config.client.ship = desig(shipName); config.shipUrl = shipUrl; config.onQuitOrReset = onQuitOrReset; config.getCode = getCode; diff --git a/packages/shared/src/http-api/Urbit.ts b/packages/shared/src/http-api/Urbit.ts index 49f55d48ef..64e1dc1e33 100644 --- a/packages/shared/src/http-api/Urbit.ts +++ b/packages/shared/src/http-api/Urbit.ts @@ -517,6 +517,7 @@ export class Urbit { method: 'PUT', body: JSON.stringify(json), }); + if (!response.ok) { throw new Error('Failed to PUT channel'); } From f39880594a66f8aade8596ea0da036f43dff9352 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 17 Oct 2024 13:18:35 -0500 Subject: [PATCH 100/259] handle failed edit and delete states --- .../SendPostRetrySheet.fixture.tsx | 5 +++ packages/app/features/top/ChannelScreen.tsx | 41 +++++++++++++++-- ...tula.sql => 0000_deep_major_mapleleaf.sql} | 7 ++- .../src/db/migrations/meta/0000_snapshot.json | 40 ++++++++++++++++- .../src/db/migrations/meta/_journal.json | 4 +- .../shared/src/db/migrations/migrations.js | 2 +- packages/shared/src/db/schema.ts | 5 +++ packages/shared/src/store/postActions.ts | 24 ++++++++-- packages/ui/src/assets/icons/Refresh.svg | 3 ++ packages/ui/src/assets/icons/index.ts | 1 + packages/ui/src/components/AuthorRow.tsx | 39 ++++++++++++++-- packages/ui/src/components/Channel/index.tsx | 21 ++++++--- .../components/ChatMessage/ChatMessage.tsx | 26 ++++++++--- .../components/GalleryPost/GalleryPost.tsx | 44 +++++++++++++------ .../MessageInput/MessageInputBase.tsx | 9 +++- .../components/MessageInput/index.native.tsx | 23 ++++++++-- .../ui/src/components/MessageInput/index.tsx | 4 ++ .../components/NotebookPost/NotebookPost.tsx | 43 +++++++++++++++--- .../components/PostContent/contentUtils.tsx | 11 +++++ packages/ui/src/components/PostScreenView.tsx | 10 ++++- .../ui/src/components/SendPostRetrySheet.tsx | 14 +++++- 21 files changed, 318 insertions(+), 58 deletions(-) rename packages/shared/src/db/migrations/{0000_tidy_tarantula.sql => 0000_deep_major_mapleleaf.sql} (98%) create mode 100644 packages/ui/src/assets/icons/Refresh.svg diff --git a/apps/tlon-mobile/src/fixtures/ActionSheet/SendPostRetrySheet.fixture.tsx b/apps/tlon-mobile/src/fixtures/ActionSheet/SendPostRetrySheet.fixture.tsx index e2f8e66285..f2224c5bb4 100644 --- a/apps/tlon-mobile/src/fixtures/ActionSheet/SendPostRetrySheet.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/ActionSheet/SendPostRetrySheet.fixture.tsx @@ -1,10 +1,15 @@ import { SendPostRetrySheet } from '@tloncorp/ui/src/components/SendPostRetrySheet'; +import { createFakePost } from '../fakeData'; + +const post = createFakePost(); + export default ( {}} onPressDelete={() => {}} onPressRetry={() => {}} + post={post} /> ); diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index c4b32053ae..887666dcbe 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -237,10 +237,43 @@ export default function ChannelScreen(props: Props) { if (!channel) { throw new Error('Tried to retry send before channel loaded'); } - await store.retrySendPost({ - channel, - post, - }); + + if (post.deliveryStatus === 'failed') { + await store.retrySendPost({ + channel, + post, + }); + } + + if (post.editStatus === 'failed' && post.lastEditContent) { + const postFromDb = await db.getPost({ postId: post.id }); + let metadata: db.PostMetadata | undefined; + if (post.lastEditTitle) { + metadata = { + title: post.lastEditTitle ?? undefined, + }; + } + + if (post.lastEditImage) { + metadata = { + ...metadata, + image: post.lastEditImage ?? undefined, + }; + } + + await store.editPost({ + post, + content: JSON.parse(postFromDb?.lastEditContent as string) as Story, + parentId: post.parentId ?? undefined, + metadata, + }); + } + + if (post.deleteStatus === 'failed') { + await store.deletePost({ + post, + }); + } }, [channel] ); diff --git a/packages/shared/src/db/migrations/0000_tidy_tarantula.sql b/packages/shared/src/db/migrations/0000_deep_major_mapleleaf.sql similarity index 98% rename from packages/shared/src/db/migrations/0000_tidy_tarantula.sql rename to packages/shared/src/db/migrations/0000_deep_major_mapleleaf.sql index c296309e1f..6d9c930fb4 100644 --- a/packages/shared/src/db/migrations/0000_tidy_tarantula.sql +++ b/packages/shared/src/db/migrations/0000_deep_major_mapleleaf.sql @@ -59,7 +59,7 @@ CREATE TABLE `channels` ( `last_post_id` text, `last_post_at` integer, `is_cached_pending_channel` integer, - `is_dm_invite` integer, + `is_dm_invite` integer DEFAULT false, `synced_at` integer, `remote_updated_at` integer, `last_viewed_at` integer, @@ -265,6 +265,11 @@ CREATE TABLE `posts` ( `is_edited` integer, `is_deleted` integer, `delivery_status` text, + `edit_status` text, + `delete_status` text, + `last_edit_content` text, + `last_edit_title` text, + `last_edit_image` text, `synced_at` integer NOT NULL, `backend_time` text ); diff --git a/packages/shared/src/db/migrations/meta/0000_snapshot.json b/packages/shared/src/db/migrations/meta/0000_snapshot.json index dbe29df1b0..17c2156fd8 100644 --- a/packages/shared/src/db/migrations/meta/0000_snapshot.json +++ b/packages/shared/src/db/migrations/meta/0000_snapshot.json @@ -1,7 +1,7 @@ { "version": "5", "dialect": "sqlite", - "id": "d3b5845c-7fa4-48d9-ba18-3e237654d040", + "id": "28484c5d-0f34-4c24-b97e-41cca5544d56", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "activity_events": { @@ -387,7 +387,8 @@ "type": "integer", "primaryKey": false, "notNull": false, - "autoincrement": false + "autoincrement": false, + "default": false }, "synced_at": { "name": "synced_at", @@ -1754,6 +1755,41 @@ "notNull": false, "autoincrement": false }, + "edit_status": { + "name": "edit_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "delete_status": { + "name": "delete_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_edit_content": { + "name": "last_edit_content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_edit_title": { + "name": "last_edit_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_edit_image": { + "name": "last_edit_image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, "synced_at": { "name": "synced_at", "type": "integer", diff --git a/packages/shared/src/db/migrations/meta/_journal.json b/packages/shared/src/db/migrations/meta/_journal.json index 2bc2d2fc54..78accfbfd0 100644 --- a/packages/shared/src/db/migrations/meta/_journal.json +++ b/packages/shared/src/db/migrations/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1723573491052, - "tag": "0000_tidy_tarantula", + "when": 1729111636686, + "tag": "0000_deep_major_mapleleaf", "breakpoints": true } ] diff --git a/packages/shared/src/db/migrations/migrations.js b/packages/shared/src/db/migrations/migrations.js index 2391fe2fd5..c1a8b17cff 100644 --- a/packages/shared/src/db/migrations/migrations.js +++ b/packages/shared/src/db/migrations/migrations.js @@ -1,7 +1,7 @@ // This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo import journal from './meta/_journal.json'; -import m0000 from './0000_tidy_tarantula.sql'; +import m0000 from './0000_deep_major_mapleleaf.sql'; export default { journal, diff --git a/packages/shared/src/db/schema.ts b/packages/shared/src/db/schema.ts index 8a234cd60f..45616a93b1 100644 --- a/packages/shared/src/db/schema.ts +++ b/packages/shared/src/db/schema.ts @@ -772,6 +772,11 @@ export const posts = sqliteTable( isEdited: boolean('is_edited'), isDeleted: boolean('is_deleted'), deliveryStatus: text('delivery_status').$type(), + editStatus: text('edit_status').$type(), + deleteStatus: text('delete_status').$type(), + lastEditContent: text('last_edit_content', { mode: 'json' }), + lastEditTitle: text('last_edit_title'), + lastEditImage: text('last_edit_image'), syncedAt: timestamp('synced_at').notNull(), // backendTime translates to an unfortunate alternative timestamp that is used // in some places by the backend agents as part of a composite key for identifying a post. diff --git a/packages/shared/src/store/postActions.ts b/packages/shared/src/store/postActions.ts index 3236690fe3..039a4ab009 100644 --- a/packages/shared/src/store/postActions.ts +++ b/packages/shared/src/store/postActions.ts @@ -134,9 +134,14 @@ export async function editPost({ logger.log('editPost', { post, content, parentId, metadata }); // optimistic update const [contentForDb, flags] = toPostContent(content); + logger.log('editPost optimistic update', { contentForDb, flags }); await db.updatePost({ id: post.id, content: JSON.stringify(contentForDb), + editStatus: 'pending', + lastEditContent: JSON.stringify(contentForDb), + lastEditTitle: metadata?.title, + lastEditImage: metadata?.image, ...flags, }); logger.log('editPost optimistic update done'); @@ -152,14 +157,24 @@ export async function editPost({ parentId, }); logger.log('editPost api call done'); - sync.syncChannelMessageDelivery({ channelId: post.channelId }); - logger.log('editPost sync done'); + await db.updatePost({ + id: post.id, + editStatus: 'sent', + lastEditContent: null, + lastEditTitle: null, + lastEditImage: null, + }); + logger.log('editPost update done'); } catch (e) { console.error('Failed to edit post', e); logger.log('editPost failed', e); // rollback optimistic update - await db.updatePost({ id: post.id, content: post.content }); + await db.updatePost({ + id: post.id, + content: post.content, + editStatus: 'failed', + }); logger.log('editPost rollback done'); } } @@ -247,10 +262,12 @@ export async function deletePost({ post }: { post: db.Post }) { // optimistic update await db.markPostAsDeleted(post.id); + await db.updatePost({ id: post.id, deleteStatus: 'pending' }); await db.updateChannel({ id: post.channelId, lastPostId: null }); try { await api.deletePost(post.channelId, post.id); + await db.updatePost({ id: post.id, deleteStatus: 'sent' }); } catch (e) { console.error('Failed to delete post', e); @@ -258,6 +275,7 @@ export async function deletePost({ post }: { post: db.Post }) { await db.updatePost({ id: post.id, ...existingPost, + deleteStatus: 'failed', }); await db.updateChannel({ id: post.channelId, lastPostId: post.id }); } diff --git a/packages/ui/src/assets/icons/Refresh.svg b/packages/ui/src/assets/icons/Refresh.svg new file mode 100644 index 0000000000..d37323a6be --- /dev/null +++ b/packages/ui/src/assets/icons/Refresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/ui/src/assets/icons/index.ts b/packages/ui/src/assets/icons/index.ts index b75d9a3332..5c748734c0 100644 --- a/packages/ui/src/assets/icons/index.ts +++ b/packages/ui/src/assets/icons/index.ts @@ -66,6 +66,7 @@ export { default as Play } from './Play.svg'; export { default as Profile } from './Profile.svg'; export { default as Record } from './Record.svg'; export { default as Redo } from './Redo.svg'; +export { default as Refresh } from './Refresh.svg'; export { default as RightSidebar } from './RightSidebar.svg'; export { default as Search } from './Search.svg'; export { default as Send } from './Send.svg'; diff --git a/packages/ui/src/components/AuthorRow.tsx b/packages/ui/src/components/AuthorRow.tsx index 5290db67e0..505b951bc4 100644 --- a/packages/ui/src/components/AuthorRow.tsx +++ b/packages/ui/src/components/AuthorRow.tsx @@ -38,6 +38,8 @@ type AuthorRowProps = ComponentProps & { sent?: number; roles?: string[]; deliveryStatus?: db.PostDeliveryStatus | null; + deleteStatus?: db.PostDeliveryStatus | null; + editStatus?: db.PostDeliveryStatus | null; type?: db.PostType; detailView?: boolean; showEditedIndicator?: boolean; @@ -59,17 +61,41 @@ export default function AuthorRow({ ...props }: AuthorRowProps) { export function DetailViewAuthorRow({ authorId, color, + showEditedIndicator, + deliveryStatus, + deleteStatus, + editStatus, ...props -}: { authorId: string; color?: ColorTokens } & ComponentProps) { +}: { + authorId: string; + showEditedIndicator?: boolean; + deliveryStatus?: db.PostDeliveryStatus | null; + editStatus?: db.PostDeliveryStatus | null; + deleteStatus?: db.PostDeliveryStatus | null; + color?: ColorTokens; +} & ComponentProps) { const openProfile = useNavigateToProfile(authorId); + const deliveryFailed = + deliveryStatus === 'failed' || + editStatus === 'failed' || + deleteStatus === 'failed'; + const shouldTruncate = showEditedIndicator || deliveryFailed; + return ( + {deliveryFailed ? ( + + Tap to retry + + ) : null} ); } @@ -80,6 +106,8 @@ export function ChatAuthorRow({ sent, roles, deliveryStatus, + editStatus, + deleteStatus, ...props }: AuthorRowProps) { const openProfile = useNavigateToProfile(authorId); @@ -94,7 +122,12 @@ export function ChatAuthorRow({ const firstRole = roles?.[0]; - const shouldTruncate = showEditedIndicator || firstRole || deliveryStatus === 'failed'; + const deliveryFailed = + deliveryStatus === 'failed' || + editStatus === 'failed' || + deleteStatus === 'failed'; + + const shouldTruncate = showEditedIndicator || firstRole || deliveryFailed; return ( @@ -117,7 +150,7 @@ export function ChatAuthorRow({ )} {firstRole && } - {deliveryStatus === 'failed' ? ( + {deliveryFailed ? ( Tap to retry diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 6c14889b49..3997d3de5f 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -243,6 +243,18 @@ export function Channel({ ] ); + const handleGoBack = useCallback(() => { + if ( + draftInputPresentationMode === 'fullscreen' && + draftInputRef.current != null + ) { + draftInputRef.current.exitFullscreen(); + setEditingPost?.(undefined); + } else { + goBack(); + } + }, [goBack, draftInputPresentationMode, draftInputRef, setEditingPost]); + return ( @@ -279,12 +291,7 @@ export function Channel({ group={group} mode={headerMode} title={title} - goBack={() => - draftInputPresentationMode === 'fullscreen' && - draftInputRef.current != null - ? draftInputRef.current.exitFullscreen() - : goBack() - } + goBack={handleGoBack} showSearchButton={isChatChannel} goToSearch={goToSearch} showSpinner={isLoadingPosts} @@ -377,7 +384,7 @@ export function Channel({ {headerMode === 'next' ? ( { onPressReplies?.(post); }, [onPressReplies, post]); const shouldHandlePress = useMemo(() => { - return Boolean(onPress || post.deliveryStatus === 'failed'); - }, [onPress, post.deliveryStatus]); + return Boolean(onPress || deliveryFailed); + }, [onPress, deliveryFailed]); const handlePress = useCallback(() => { - if (onPress && post.deliveryStatus !== 'failed') { + if (onPress && !deliveryFailed) { onPress(post); - } else if (post.deliveryStatus === 'failed') { + } else if (deliveryFailed) { setShowRetrySheet(true); } - }, [post, onPress]); + }, [post, onPress, deliveryFailed]); const handleLongPress = useCallback(() => { onLongPress?.(post); @@ -85,6 +93,7 @@ const ChatMessage = ({ }, [onPressDelete, post]); const content = usePostContent(post); + const lastEditContent = usePostLastEditContent(post); if (!post) { return null; @@ -130,12 +139,14 @@ const ChatMessage = ({ type={post.type} disabled={hideProfilePreview} deliveryStatus={post.deliveryStatus} + editStatus={post.editStatus} + deleteStatus={post.deleteStatus} showEditedIndicator={!!post.isEdited} /> ) : null} { - post.deliveryStatus === 'failed' - ? () => setShowRetrySheet(true) - : onPress?.(post); - }, [onPress, post]); + if (onPress && !deliveryFailed) { + onPress(post); + } else if (deliveryFailed) { + setShowRetrySheet(true); + } + }, [onPress, deliveryFailed, post]); const handleLongPress = useBoundHandler(post, onLongPress); @@ -84,22 +91,31 @@ export function GalleryPost({ width="100%" pointerEvents="none" > - {post.deliveryStatus === 'failed' ? ( - - - Message failed to send + + + {deliveryFailed && ( + + Tap to retry - - ) : ( - - - - )} + )} + )} diff --git a/packages/ui/src/components/MessageInput/MessageInputBase.tsx b/packages/ui/src/components/MessageInput/MessageInputBase.tsx index 0a8691c188..d1fe6b936e 100644 --- a/packages/ui/src/components/MessageInput/MessageInputBase.tsx +++ b/packages/ui/src/components/MessageInput/MessageInputBase.tsx @@ -67,6 +67,7 @@ export const MessageInputContainer = memo( onPressSend, setShouldBlur, containerHeight, + sendError, showMentionPopup = false, showAttachmentButton = true, floatingActionButton = false, @@ -83,6 +84,7 @@ export const MessageInputContainer = memo( setShouldBlur: (shouldBlur: boolean) => void; onPressSend: () => void; containerHeight: number; + sendError: boolean; showMentionPopup?: boolean; showAttachmentButton?: boolean; floatingActionButton?: boolean; @@ -153,7 +155,12 @@ export const MessageInputContainer = memo( {disableSend ? null : ( } + icon={ + + } /> )} diff --git a/packages/ui/src/components/MessageInput/index.native.tsx b/packages/ui/src/components/MessageInput/index.native.tsx index 2d1a049c33..6cef5349a0 100644 --- a/packages/ui/src/components/MessageInput/index.native.tsx +++ b/packages/ui/src/components/MessageInput/index.native.tsx @@ -146,6 +146,7 @@ export const MessageInput = forwardRef( const branchDomain = useBranchDomain(); const branchKey = useBranchKey(); const [isSending, setIsSending] = useState(false); + const [sendError, setSendError] = useState(false); const [hasSetInitialContent, setHasSetInitialContent] = useState(false); const [hasAutoFocused, setHasAutoFocused] = useState(false); const [editorCrashed, setEditorCrashed] = useState(); @@ -225,6 +226,7 @@ export const MessageInput = forwardRef( useEffect(() => { if (!hasSetInitialContent && editorState.isReady) { + messageInputLogger.log('Setting initial content'); try { getDraft(draftType).then((draft) => { if (!editingPost && draft) { @@ -246,8 +248,11 @@ export const MessageInput = forwardRef( // @ts-expect-error setContent does accept JSONContent editor.setContent(tiptapContent); setEditorIsEmpty(false); + messageInputLogger.log('set has set initial content'); + setHasSetInitialContent(true); } + messageInputLogger.log('Editing post?', editingPost); if (editingPost && editingPost.content) { messageInputLogger.log('Editing post', editingPost); const { @@ -299,6 +304,8 @@ export const MessageInput = forwardRef( // @ts-expect-error setContent does accept JSONContent editor.setContent(tiptapContent); setEditorIsEmpty(false); + messageInputLogger.log('set has set initial content'); + setHasSetInitialContent(true); } if (editingPost?.image) { @@ -314,8 +321,6 @@ export const MessageInput = forwardRef( }); } catch (e) { messageInputLogger.error('Error getting draft', e); - } finally { - setHasSetInitialContent(true); } } }, [ @@ -397,7 +402,7 @@ export const MessageInput = forwardRef( 'Content updated, update draft and check for mention text' ); - const json = await editor.getJSON(); + const json = (await editor.getJSON()) as JSONContent; const inlines = ( tiptap .JSONToInlines(json) @@ -426,6 +431,14 @@ export const MessageInput = forwardRef( messageInputLogger.log('Storing draft', json); + if ( + json.content?.length === 1 && + json.content[0].type === 'paragraph' && + !json.content[0].content + ) { + clearDraft(draftType); + } + storeDraft(json, draftType); }; @@ -715,8 +728,10 @@ export const MessageInput = forwardRef( await sendMessage(isEdit); } catch (e) { console.error('failed to send', e); + setSendError(true); } setIsSending(false); + setSendError(false); }, [sendMessage] ); @@ -889,6 +904,7 @@ export const MessageInput = forwardRef( const handleCancelEditing = useCallback(() => { setEditingPost?.(undefined); + setHasSetInitialContent(false); editor.setContent(''); clearDraft(draftType); clearAttachments(); @@ -900,6 +916,7 @@ export const MessageInput = forwardRef( onPressSend={handleSend} onPressEdit={handleEdit} containerHeight={containerHeight} + sendError={sendError} mentionText={mentionText} groupMembers={groupMembers} onSelectMention={onSelectMention} diff --git a/packages/ui/src/components/MessageInput/index.tsx b/packages/ui/src/components/MessageInput/index.tsx index 702fd0223f..91123cf70a 100644 --- a/packages/ui/src/components/MessageInput/index.tsx +++ b/packages/ui/src/components/MessageInput/index.tsx @@ -89,6 +89,7 @@ export function MessageInput({ const [containerHeight, setContainerHeight] = useState(initialHeight); const [isSending, setIsSending] = useState(false); + const [sendError, setSendError] = useState(false); const [hasSetInitialContent, setHasSetInitialContent] = useState(false); const [imageOnEditedPost, setImageOnEditedPost] = useState(); const [editorIsEmpty, setEditorIsEmpty] = useState(attachments.length === 0); @@ -531,8 +532,10 @@ export function MessageInput({ await sendMessage(isEdit); } catch (e) { console.error('failed to send', e); + setSendError(true); } setIsSending(false); + setSendError(false); }, [sendMessage] ); @@ -564,6 +567,7 @@ export function MessageInput({ showMentionPopup={showMentionPopup} isEditing={!!editingPost} isSending={isSending} + sendError={sendError} cancelEditing={() => setEditingPost?.(undefined)} showAttachmentButton={showAttachmentButton} floatingActionButton={floatingActionButton} diff --git a/packages/ui/src/components/NotebookPost/NotebookPost.tsx b/packages/ui/src/components/NotebookPost/NotebookPost.tsx index 3ed7dc7ade..dfc55e794a 100644 --- a/packages/ui/src/components/NotebookPost/NotebookPost.tsx +++ b/packages/ui/src/components/NotebookPost/NotebookPost.tsx @@ -14,7 +14,10 @@ import { DetailViewAuthorRow } from '../AuthorRow'; import { ChatMessageReplySummary } from '../ChatMessage/ChatMessageReplySummary'; import { Image } from '../Image'; import { createContentRenderer } from '../PostContent/ContentRenderer'; -import { usePostContent } from '../PostContent/contentUtils'; +import { + usePostContent, + usePostLastEditContent, +} from '../PostContent/contentUtils'; import { SendPostRetrySheet } from '../SendPostRetrySheet'; import { Text } from '../TextV2'; @@ -61,18 +64,23 @@ export function NotebookPost({ setShowRetrySheet(false); }, [onPressDelete, post]); + const deliveryFailed = + post.deliveryStatus === 'failed' || + post.editStatus === 'failed' || + post.deleteStatus === 'failed'; + const handlePress = useCallback(() => { if (post.hidden || post.isDeleted) { return; } - if (post.deliveryStatus === 'failed') { + if (deliveryFailed) { setShowRetrySheet(true); return; } onPress?.(post); - }, [post, onPress]); + }, [post, onPress, deliveryFailed]); if (!post || post.isDeleted) { return null; @@ -139,6 +147,7 @@ export function NotebookPost({ )} - {post.title ?? 'Untitled Post'} + + {post.editStatus === 'failed' || post.editStatus === 'pending' + ? post.lastEditTitle ?? 'Untitled Post' + : post.title ?? 'Untitled Post'} + {showDate && ( @@ -181,13 +197,22 @@ function NotebookPostHeader({ )} - {showAuthor && } + {showAuthor && ( + + )} ); } export function NotebookPostDetailView({ post }: { post: db.Post }) { const content = usePostContent(post); + const lastEditContent = usePostLastEditContent(post); + return ( ); diff --git a/packages/ui/src/components/PostContent/contentUtils.tsx b/packages/ui/src/components/PostContent/contentUtils.tsx index b008a06fe0..a93584aed4 100644 --- a/packages/ui/src/components/PostContent/contentUtils.tsx +++ b/packages/ui/src/components/PostContent/contentUtils.tsx @@ -205,6 +205,17 @@ export function usePostContent(post: Post): BlockData[] { }, [post]); } +export function usePostLastEditContent(post: Post): BlockData[] { + return useMemo(() => { + try { + return convertContent(post.lastEditContent); + } catch (e) { + console.error('Failed to convert post content:', e); + return []; + } + }, [post]); +} + /** * Convert an array of inlines to an array of blocks. The existing inline will * be split if it contains block-like inlines (again, blockquote, code block, diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 58271aa9cc..56bfa3b210 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -157,6 +157,14 @@ export function PostScreenView({ [onPressRef, posts, channel] ); + const handleGoBack = useCallback(() => { + if (isEditingParent) { + console.log('setEditingPost', undefined); + setEditingPost?.(undefined); + } + goBack?.(); + }, [goBack, isEditingParent, setEditingPost]); + return ( void; onPressRetry: () => void; onPressDelete: () => void; }) => { + const actionTitle = + post.editStatus === 'failed' + ? 'Post edit failed' + : post.deleteStatus === 'failed' + ? 'Post delete failed' + : 'Post failed to send'; + const actions: Action[] = useMemo( () => [ { @@ -22,14 +32,14 @@ export const SendPostRetrySheet = ({ { title: 'Delete', action: onPressDelete, - accent: 'negative' + accent: 'negative', }, ], [onPressRetry, onPressDelete] ); return ( Date: Thu, 17 Oct 2024 14:38:26 -0500 Subject: [PATCH 101/259] don't show hidden posts in chat list previews --- packages/ui/src/components/ListItem/ListItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/ListItem/ListItem.tsx b/packages/ui/src/components/ListItem/ListItem.tsx index df282fc4d6..6fa8c7a288 100644 --- a/packages/ui/src/components/ListItem/ListItem.tsx +++ b/packages/ui/src/components/ListItem/ListItem.tsx @@ -226,7 +226,7 @@ export const ListItemPostPreview = ({ {': '} ) : null} - {post.textContent ?? ''} + {post.hidden ? '(This post has been hidden)' : post.textContent ?? ''} ); }; From ae9baaa4a8d7ed1c5a4424170b71c3ae1943d836 Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 17 Oct 2024 13:09:20 -0700 Subject: [PATCH 102/259] Shorten post collection layout method identifiers --- packages/shared/src/index.ts | 6 +++--- .../src/types/PostCollectionConfiguration.ts | 14 +++++++------- packages/ui/src/components/Channel/Scroller.tsx | 12 ++++++------ packages/ui/src/components/Channel/index.tsx | 12 ++++-------- packages/ui/src/utils/channelUtils.tsx | 10 ++++------ 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index f39b19f332..b8dea04d3b 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -13,9 +13,9 @@ export { PostCollectionConfiguration, PostCollectionLayout, PostCollectionLayoutType, - postCollectionConfigurationFromChannel, - postCollectionLayoutForType, - postCollectionLayoutTypeFromChannel, + configurationFromChannel, + layoutForType, + layoutTypeFromChannel, } from './types/PostCollectionConfiguration'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 8562002f25..8054151368 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -12,13 +12,13 @@ export type PostCollectionLayoutType = // Why overload this function instead of just doing a union? // If the caller has a non-nullable `channel`, they can then get a // non-nullable return value - nice, right? -export function postCollectionLayoutTypeFromChannel( +export function layoutTypeFromChannel( channel: db.Channel ): PostCollectionLayoutType; -export function postCollectionLayoutTypeFromChannel( +export function layoutTypeFromChannel( channel: db.Channel | null ): PostCollectionLayoutType | null; -export function postCollectionLayoutTypeFromChannel( +export function layoutTypeFromChannel( channel: db.Channel | null ): PostCollectionLayoutType | null { switch (channel?.type) { @@ -74,7 +74,7 @@ export interface PostCollectionLayout { scrollDirection: 'bottom-to-top' | 'top-to-bottom'; } -export function postCollectionLayoutForType( +export function layoutForType( layoutType: PostCollectionLayoutType ): PostCollectionLayout { switch (layoutType) { @@ -127,13 +127,13 @@ export interface PostCollectionConfiguration { usesMemberListAsFallbackTitle: boolean; } -export function postCollectionConfigurationFromChannel( +export function configurationFromChannel( channel: db.Channel ): PostCollectionConfiguration; -export function postCollectionConfigurationFromChannel( +export function configurationFromChannel( channel: db.Channel | null ): PostCollectionConfiguration | null; -export function postCollectionConfigurationFromChannel( +export function configurationFromChannel( channel: db.Channel | null ): PostCollectionConfiguration | null { switch (channel?.type) { diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 5cd7cc7900..7652e0c79a 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -1,7 +1,7 @@ import { - postCollectionConfigurationFromChannel, - postCollectionLayoutForType, - postCollectionLayoutTypeFromChannel, + configurationFromChannel, + layoutForType, + layoutTypeFromChannel, useMutableCallback, } from '@tloncorp/shared'; import { createDevLogger } from '@tloncorp/shared/dist'; @@ -141,15 +141,15 @@ const Scroller = forwardRef( ref ) => { const collectionLayoutType = useMemo( - () => postCollectionLayoutTypeFromChannel(channel), + () => layoutTypeFromChannel(channel), [channel] ); const collectionLayout = useMemo( - () => postCollectionLayoutForType(collectionLayoutType), + () => layoutForType(collectionLayoutType), [collectionLayoutType] ); const collectionConfig = useMemo( - () => postCollectionConfigurationFromChannel(channel), + () => configurationFromChannel(channel), [channel] ); diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 7c00c27623..6f36a8ac5f 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -1,7 +1,4 @@ -import { - postCollectionLayoutForType, - postCollectionLayoutTypeFromChannel, -} from '@tloncorp/shared'; +import { layoutForType, layoutTypeFromChannel } from '@tloncorp/shared'; import { isChatChannel as getIsChatChannel, useChannel as useChannelFromStore, @@ -137,8 +134,7 @@ export function Channel({ const canWrite = utils.useCanWrite(channel, currentUserId); const collectionLayout = useMemo( - () => - postCollectionLayoutForType(postCollectionLayoutTypeFromChannel(channel)), + () => layoutForType(layoutTypeFromChannel(channel)), [channel] ); @@ -331,8 +327,8 @@ export function Channel({ setEditingPost={setEditingPost} channel={channel} firstUnreadId={ - (initialChannelUnread?.countWithoutThreads ?? - 0 > 0) + initialChannelUnread?.countWithoutThreads ?? + 0 > 0 ? initialChannelUnread?.firstUnreadPostId : null } diff --git a/packages/ui/src/utils/channelUtils.tsx b/packages/ui/src/utils/channelUtils.tsx index bd0f35932c..02d566df31 100644 --- a/packages/ui/src/utils/channelUtils.tsx +++ b/packages/ui/src/utils/channelUtils.tsx @@ -1,4 +1,4 @@ -import { postCollectionConfigurationFromChannel } from '@tloncorp/shared'; +import { configurationFromChannel } from '@tloncorp/shared'; import type * as db from '@tloncorp/shared/dist/db'; import { useMemberRoles } from '@tloncorp/shared/dist/store'; import { useMemo } from 'react'; @@ -37,9 +37,9 @@ function getChannelTitle({ // (There should be no path to titling a 1:1 DM in-app.) return channelTitle ? channelTitle - : (members + : members ?.map((member) => getChannelMemberName(member, disableNicknames)) - .join(', ') ?? 'No title'); + .join(', ') ?? 'No title'; } else { return channelTitle ?? 'Untitled channel'; } @@ -48,9 +48,7 @@ function getChannelTitle({ export function useChannelTitle(channel: db.Channel | null) { const { disableNicknames } = useCalm(); const usesMemberListAsFallbackTitle = useMemo( - () => - postCollectionConfigurationFromChannel(channel) - ?.usesMemberListAsFallbackTitle, + () => configurationFromChannel(channel)?.usesMemberListAsFallbackTitle, [channel] ); From cb5efe9aa210a46cd83b3d554cdf611e6dcc9e59 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Oct 2024 20:36:00 +0000 Subject: [PATCH 103/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 36641c4b17..4e47b0cd95 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v5.cdkn1.29ten.suoa4.66q4k.cl7fg.glob' 0v5.cdkn1.29ten.suoa4.66q4k.cl7fg] + glob-http+['https://bootstrap.urbit.org/glob-0v3.j6b0q.5nqig.e3c7q.bcd5f.ba1ts.glob' 0v3.j6b0q.5nqig.e3c7q.bcd5f.ba1ts] base+'groups' version+[6 4 2] website+'https://tlon.io' From ddf2e19d70e69862d662e178d3c8fb095cadff1f Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 17 Oct 2024 15:58:21 -0500 Subject: [PATCH 104/259] urbit: fix ship name shenanigans --- packages/shared/src/api/urbit.ts | 8 ++++---- packages/shared/src/http-api/Urbit.ts | 23 ++++++++++++----------- packages/shared/src/store/sync.ts | 14 +++++++++++++- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index be6caf0cfd..3ed0c8274c 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -81,14 +81,14 @@ export const client = new Proxy( ) as Urbit; export const getCurrentUserId = () => { - if (!client.our) { + if (!client.nodeId) { throw new Error('Client not initialized'); } - return client.our; + return client.nodeId; }; export const getCurrentUserIsHosted = () => { - if (!client.our) { + if (!client.nodeId) { throw new Error('Client not initialized'); } @@ -108,7 +108,7 @@ export function internalConfigureClient({ logger.log('configuring client', shipName, shipUrl); config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.verbose = verbose; - config.client.ship = desig(shipName); + config.client.nodeId = shipName; config.shipUrl = shipUrl; config.onQuitOrReset = onQuitOrReset; config.getCode = getCode; diff --git a/packages/shared/src/http-api/Urbit.ts b/packages/shared/src/http-api/Urbit.ts index 64e1dc1e33..a3e9ef7479 100644 --- a/packages/shared/src/http-api/Urbit.ts +++ b/packages/shared/src/http-api/Urbit.ts @@ -1,5 +1,6 @@ import { isBrowser } from 'browser-or-node'; +import { desig } from '../urbit'; import { UrbitHttpApiEvent, UrbitHttpApiEventType } from './events'; import { EventSourceMessage, fetchEventSource } from './fetch-event-source'; import { @@ -83,7 +84,7 @@ export class Urbit { /** * Identity of the ship we're connected to */ - ship?: string | null; + nodeId?: string | null; /** * Our identity, with which we are authenticated into the ship @@ -169,7 +170,7 @@ export class Urbit { code ); airlock.verbose = verbose; - airlock.ship = ship; + airlock.nodeId = ship; await airlock.connect(); await airlock.poke({ app: 'hood', @@ -209,7 +210,7 @@ export class Urbit { * */ async getShipName(): Promise { - if (this.ship) { + if (this.nodeId) { return Promise.resolve(); } @@ -218,7 +219,7 @@ export class Urbit { credentials: 'include', }); const name = await nameResp.text(); - this.ship = name.substring(1); + this.nodeId = name; } /** @@ -235,7 +236,7 @@ export class Urbit { credentials: 'include', }); const name = await nameResp.text(); - this.our = name.substring(1); + this.our = name; } /** @@ -266,8 +267,8 @@ export class Urbit { throw new Error('Login failed with status ' + response.status); } const cookie = response.headers.get('set-cookie'); - if (!this.ship && cookie) { - this.ship = new RegExp(/urbauth-~([\w-]+)/).exec(cookie)?.[1]; + if (!this.nodeId && cookie) { + this.nodeId = new RegExp(/urbauth-~([\w-]+)/).exec(cookie)?.[1]; } if (!isBrowser) { this.cookie = cookie || undefined; @@ -527,10 +528,10 @@ export class Urbit { } await Promise.all([this.getOurName(), this.getShipName()]); - if (this.our !== this.ship) { + if (this.our !== this.nodeId) { console.log('our name does not match ship name'); console.log('our:', this.our); - console.log('ship:', this.ship); + console.log('ship:', this.nodeId); console.log('messages:', json); throw new AuthError('invalid session'); } @@ -596,7 +597,7 @@ export class Urbit { const { app, mark, json, ship, onSuccess, onError } = { onSuccess: () => {}, onError: () => {}, - ship: this.ship, + ship: desig(this.nodeId ?? ''), ...params, }; @@ -637,7 +638,7 @@ export class Urbit { err: () => {}, event: () => {}, quit: () => {}, - ship: this.ship, + ship: desig(this.nodeId ?? ''), resubOnQuit: true, ...params, }; diff --git a/packages/shared/src/store/sync.ts b/packages/shared/src/store/sync.ts index 3cf644ff3d..9c9b0ad9b5 100644 --- a/packages/shared/src/store/sync.ts +++ b/packages/shared/src/store/sync.ts @@ -201,7 +201,19 @@ export const syncContacts = async (ctx?: SyncCtx) => { const contacts = await syncQueue.add('contacts', ctx, () => api.getContacts() ); - await db.insertContacts(contacts); + logger.log('got contacts from api', contacts); + try { + await db.insertContacts(contacts); + } catch (e) { + logger.error('error inserting contacts', e); + } + + try { + const newContacts = await db.getContacts(); + logger.log('got contacts from db', newContacts); + } catch (e) { + logger.error('error getting contacts from db', e); + } }; export const syncPinnedItems = async (ctx?: SyncCtx) => { From 00a48d5d7a177ffb088280569bf8c4d6321987b8 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Thu, 17 Oct 2024 16:16:27 -0500 Subject: [PATCH 105/259] client: clean up client info gathering --- packages/shared/src/api/settingsApi.ts | 8 ++------ .../shared/src/store/storage/storageUtils.ts | 20 ++----------------- packages/shared/src/store/useNegotiation.ts | 5 ++--- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/packages/shared/src/api/settingsApi.ts b/packages/shared/src/api/settingsApi.ts index 0c402ca69f..cc5a07b199 100644 --- a/packages/shared/src/api/settingsApi.ts +++ b/packages/shared/src/api/settingsApi.ts @@ -1,6 +1,6 @@ import * as db from '../db'; import * as ub from '../urbit'; -import { client, scry } from './urbit'; +import { getCurrentUserId, scry } from './urbit'; export const getSettings = async () => { const results = await scry({ @@ -30,12 +30,8 @@ const toClientSidebarSort = ( export const toClientSettings = ( settings: ub.GroupsDeskSettings ): db.Settings => { - if (!client.ship) { - throw new Error('Client not configured'); - } - return { - userId: client.ship, + userId: getCurrentUserId(), theme: settings.desk.display?.theme, disableAppTileUnreads: settings.desk.calmEngine?.disableAppTileUnreads, disableAvatars: settings.desk.calmEngine?.disableAvatars, diff --git a/packages/shared/src/store/storage/storageUtils.ts b/packages/shared/src/store/storage/storageUtils.ts index 56403c7f4f..106f2148d4 100644 --- a/packages/shared/src/store/storage/storageUtils.ts +++ b/packages/shared/src/store/storage/storageUtils.ts @@ -40,22 +40,12 @@ export const fetchImageFromUri = async ( export type SizedImage = { uri: string; width: number; height: number }; -export const getShipInfo = () => { - const { ship, url } = client; - - if (!ship) { - return { ship: '', shipUrl: '' }; - } - - return { ship: preSig(ship), shipUrl: url }; -}; - export const hasHostingUploadCreds = ( configuration: StorageConfiguration | null, credentials: StorageCredentials | null ) => { return ( - getIsHosted() && + api.getCurrentUserIsHosted() && (configuration?.service === 'presigned-url' || !hasCustomS3Creds(configuration, credentials)) ); @@ -78,12 +68,6 @@ export const hasCustomS3Creds = ( const MEMEX_BASE_URL = 'https://memex.tlon.network'; -export const getIsHosted = () => { - const shipInfo = getShipInfo(); - const isHosted = shipInfo?.shipUrl?.endsWith('tlon.network'); - return isHosted; -}; - interface MemexUploadParams { token: string; contentLength: number; @@ -142,6 +126,6 @@ export const getMemexUpload = async ({ }; export const getHostingUploadURL = async () => { - const isHosted = getIsHosted(); + const isHosted = api.getCurrentUserIsHosted(); return isHosted ? MEMEX_BASE_URL : ''; }; diff --git a/packages/shared/src/store/useNegotiation.ts b/packages/shared/src/store/useNegotiation.ts index bd90eacc41..20ead84192 100644 --- a/packages/shared/src/store/useNegotiation.ts +++ b/packages/shared/src/store/useNegotiation.ts @@ -5,7 +5,6 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'; import * as api from '../api'; import { queryClient } from '../api'; import { MatchingEvent, MatchingResponse } from '../urbit/negotiation'; -import { getShipInfo } from './storage'; function negotiationUpdater( event: MatchingEvent | null, @@ -107,10 +106,10 @@ export function useNegotiateMulti(ships: string[], app: string, agent: string) { return { ...rest, match: false, haveAllNegotiations: false }; } - const shipInfo = getShipInfo(); + const us = api.getCurrentUserId(); const shipKeys = ships - .filter((ship) => ship !== shipInfo.ship) + .filter((ship) => ship !== us) .map((ship) => `${ship}/${agent}`); const allShipsMatch = shipKeys.every( From 2ad243955ef55f327614a0012ce5d76aadc86005 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 18:27:28 -0400 Subject: [PATCH 106/259] make sure nodeId is sigged and always fetch our/actual session id --- packages/shared/src/api/urbit.ts | 4 ++-- packages/shared/src/http-api/Urbit.ts | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index 3ed0c8274c..c2bfb7d75f 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -2,7 +2,7 @@ import _ from 'lodash'; import { createDevLogger, escapeLog, runIfDev } from '../debug'; import { AuthError, ChannelStatus, PokeInterface, Urbit } from '../http-api'; -import { desig } from '../urbit'; +import { desig, preSig } from '../urbit'; import { getLandscapeAuthCookie } from './landscapeApi'; const logger = createDevLogger('urbit', false); @@ -108,7 +108,7 @@ export function internalConfigureClient({ logger.log('configuring client', shipName, shipUrl); config.client = config.client || new Urbit(shipUrl, '', '', fetchFn); config.client.verbose = verbose; - config.client.nodeId = shipName; + config.client.nodeId = preSig(shipName); config.shipUrl = shipUrl; config.onQuitOrReset = onQuitOrReset; config.getCode = getCode; diff --git a/packages/shared/src/http-api/Urbit.ts b/packages/shared/src/http-api/Urbit.ts index a3e9ef7479..afbc60c1eb 100644 --- a/packages/shared/src/http-api/Urbit.ts +++ b/packages/shared/src/http-api/Urbit.ts @@ -227,10 +227,6 @@ export class Urbit { * */ async getOurName(): Promise { - if (this.our) { - return Promise.resolve(); - } - const nameResp = await this.fetchFn(`${this.url}/~/name`, { method: 'get', credentials: 'include', From dbd09d8bf23d3222d8f9cc07376d4fe0d013e847 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 18:43:37 -0400 Subject: [PATCH 107/259] use client connection status for determing session --- packages/shared/src/store/session.ts | 12 +++++++++--- packages/shared/src/store/sync.ts | 7 +------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/shared/src/store/session.ts b/packages/shared/src/store/session.ts index fe3a596713..c08ca9f395 100644 --- a/packages/shared/src/store/session.ts +++ b/packages/shared/src/store/session.ts @@ -1,6 +1,8 @@ import { useSyncExternalStore } from 'react'; -export type Session = { startTime?: number; isReconnecting?: boolean }; +import { ChannelStatus } from '../http-api'; + +export type Session = { startTime?: number; channelStatus?: ChannelStatus }; // Session — time when subscriptions were first initialized after which we can assume // all new events will be heard @@ -106,7 +108,7 @@ export function useConnectionStatus() { return 'Connecting'; } - if (currentSession.isReconnecting) { + if (currentSession.channelStatus === 'reconnecting') { return 'Reconnecting'; } @@ -114,5 +116,9 @@ export function useConnectionStatus() { return 'Syncing'; } - return 'Connected'; + if (['active', 'reconnected'].includes(currentSession.channelStatus ?? '')) { + return 'Connected'; + } + + return 'Connecting'; } diff --git a/packages/shared/src/store/sync.ts b/packages/shared/src/store/sync.ts index 9c9b0ad9b5..14d98248d8 100644 --- a/packages/shared/src/store/sync.ts +++ b/packages/shared/src/store/sync.ts @@ -1042,12 +1042,7 @@ export const handleDiscontinuity = async () => { }; export const handleChannelStatusChange = async (status: ChannelStatus) => { - if (status === 'reconnecting') { - updateSession({ isReconnecting: true }); - } else if (status === 'reconnected') - updateSession({ - isReconnecting: false, - }); + updateSession({ channelStatus: status }); }; export const syncStart = async (alreadySubscribed?: boolean) => { From 59ecc7676e38c6fe75c720139bc46e2d9d68ee76 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 17 Oct 2024 19:34:23 -0400 Subject: [PATCH 108/259] fix types in ui package --- .../ChatMessageActions/MessageActions.tsx | 20 +++++++------------ packages/ui/src/components/ScreenHeader.tsx | 6 +++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx index 8ac6b00b75..1b99b56edf 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx @@ -4,13 +4,13 @@ import * as db from '@tloncorp/shared/dist/db'; import * as logic from '@tloncorp/shared/dist/logic'; import * as store from '@tloncorp/shared/dist/store'; import * as Haptics from 'expo-haptics'; -import { useIsAdmin } from '../../../utils'; import { useMemo } from 'react'; import { Alert } from 'react-native'; import { useChannelContext, useCurrentUserId } from '../../../contexts'; import { Attachment, useAttachmentContext } from '../../../contexts/attachment'; import { useCopy } from '../../../hooks/useCopy'; +import { useIsAdmin } from '../../../utils'; import ActionList from '../../ActionList'; const ENABLE_COPY_JSON = __DEV__; @@ -30,7 +30,7 @@ export default function MessageActions({ post: db.Post; channelType: db.ChannelType; }) { - const currentSession = useCurrentSession(); + const connectionStatus = store.useConnectionStatus(); const currentUserId = useCurrentUserId(); const { addAttachment } = useAttachmentContext(); const channel = useChannelContext(); @@ -69,10 +69,7 @@ export default function MessageActions({ {postActions.map((action, index) => ( handleAction({ id: action.id, @@ -85,7 +82,7 @@ export default function MessageActions({ onEdit, onViewReactions, addAttachment, - currentSession, + isConnected: connectionStatus === 'Connected', isNetworkDependent: action.networkDependent, }) } @@ -252,7 +249,7 @@ export async function handleAction({ onEdit, onViewReactions, addAttachment, - currentSession, + isConnected, isNetworkDependent, }: { id: string; @@ -265,13 +262,10 @@ export async function handleAction({ onEdit?: () => void; onViewReactions?: (post: db.Post) => void; addAttachment: (attachment: Attachment) => void; - currentSession: Session | null; + isConnected: boolean; isNetworkDependent: boolean; }) { - if ( - isNetworkDependent && - (!currentSession || currentSession?.isReconnecting) - ) { + if (isNetworkDependent && !isConnected) { Alert.alert( 'App is disconnected', 'This action is unavailable while the app is in a disconnected state.' diff --git a/packages/ui/src/components/ScreenHeader.tsx b/packages/ui/src/components/ScreenHeader.tsx index 6fc6fc2a68..31a70cf672 100644 --- a/packages/ui/src/components/ScreenHeader.tsx +++ b/packages/ui/src/components/ScreenHeader.tsx @@ -1,4 +1,4 @@ -import { useCurrentSession } from '@tloncorp/shared'; +import { useConnectionStatus } from '@tloncorp/shared'; import { ComponentProps, PropsWithChildren, @@ -33,11 +33,11 @@ export const ScreenHeaderComponent = ({ }>) => { const { top } = useSafeAreaInsets(); const resolvedTitle = isLoading ? 'Loading…' : title; - const currentSession = useCurrentSession(); + const connectionStatus = useConnectionStatus(); const textColor = showSessionStatus === false ? '$primaryText' - : currentSession?.isReconnecting || !currentSession + : connectionStatus !== 'Connected' ? '$tertiaryText' : '$primaryText'; From e51b87a6edebbbb06cad63d40f24be59bd97f6d1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 17 Oct 2024 23:52:49 +0000 Subject: [PATCH 109/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 4e47b0cd95..28d1bf4f40 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v3.j6b0q.5nqig.e3c7q.bcd5f.ba1ts.glob' 0v3.j6b0q.5nqig.e3c7q.bcd5f.ba1ts] + glob-http+['https://bootstrap.urbit.org/glob-0v5.3brgr.lidn5.qroqi.175ho.qbrpf.glob' 0v5.3brgr.lidn5.qroqi.175ho.qbrpf] base+'groups' version+[6 4 2] website+'https://tlon.io' From 1ca337ad7b33ae4bcc5828be4a49887f611d3c57 Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 26 Sep 2024 17:27:54 -0700 Subject: [PATCH 110/259] Remove unused import --- packages/shared/src/api/channelsApi.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/shared/src/api/channelsApi.ts b/packages/shared/src/api/channelsApi.ts index 7591d2cf3e..a545bb1d8e 100644 --- a/packages/shared/src/api/channelsApi.ts +++ b/packages/shared/src/api/channelsApi.ts @@ -6,11 +6,7 @@ import { createDevLogger } from '../debug'; import * as ub from '../urbit'; import { Posts } from '../urbit'; import { stringToTa } from '../urbit/utils'; -import { - getCanonicalPostId, - isDmChannelId, - isGroupChannelId, -} from './apiUtils'; +import { getCanonicalPostId, isGroupChannelId } from './apiUtils'; import { toPostData, toPostReplyData, toReactionsData } from './postsApi'; import { scry, subscribe, trackedPoke } from './urbit'; From 205353858bfb9b3039802e97478ba6f592b16354 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 18 Oct 2024 06:51:25 -0500 Subject: [PATCH 111/259] group channel list: fix long press on some arranged channels --- packages/ui/src/components/ChannelNavSection.tsx | 3 +++ packages/ui/src/components/ChannelNavSections.tsx | 1 + 2 files changed, 4 insertions(+) diff --git a/packages/ui/src/components/ChannelNavSection.tsx b/packages/ui/src/components/ChannelNavSection.tsx index 61c87e9d26..371c40912e 100644 --- a/packages/ui/src/components/ChannelNavSection.tsx +++ b/packages/ui/src/components/ChannelNavSection.tsx @@ -8,10 +8,12 @@ export default function ChannelNavSection({ section, channels, onSelect, + onLongPress, }: { section: db.GroupNavSection; channels: db.Channel[]; onSelect: (channel: any) => void; + onLongPress?: (channel: any) => void; }) { const sectionChannels = useMemo( () => @@ -46,6 +48,7 @@ export default function ChannelNavSection({ model={getChannel(item.channelId)!} useTypeIcon={true} onPress={onSelect} + onLongPress={onLongPress} /> ))} diff --git a/packages/ui/src/components/ChannelNavSections.tsx b/packages/ui/src/components/ChannelNavSections.tsx index b99a804a20..bae77a0580 100644 --- a/packages/ui/src/components/ChannelNavSections.tsx +++ b/packages/ui/src/components/ChannelNavSections.tsx @@ -82,6 +82,7 @@ export default function ChannelNavSections({ section={section} channels={sectionChannels} onSelect={onSelect} + onLongPress={onLongPress} /> ); })} From f58cf670dbd7db32134df12efd845029d4dc51d6 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 18 Oct 2024 07:21:28 -0500 Subject: [PATCH 112/259] handle scrolling in view reactions sheet --- apps/tlon-mobile/cosmos.imports.ts | 2 +- .../ChatMessage/ViewReactionsPane.tsx | 78 ++++++++++++++----- .../ChatMessage/ViewReactionsSheet.tsx | 6 +- 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/apps/tlon-mobile/cosmos.imports.ts b/apps/tlon-mobile/cosmos.imports.ts index 41b9a78dda..94409ca7b5 100644 --- a/apps/tlon-mobile/cosmos.imports.ts +++ b/apps/tlon-mobile/cosmos.imports.ts @@ -62,7 +62,7 @@ import * as fixture54 from './src/fixtures/ActionSheet/AddGalleryPostSheet.fixtu import * as decorator0 from './src/fixtures/cosmos.decorator'; export const rendererConfig: RendererConfig = { - "playgroundUrl": "http://localhost:5001", + "playgroundUrl": "http://localhost:5000", "rendererUrl": null }; diff --git a/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx b/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx index 306d8a116c..753d4d4384 100644 --- a/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx +++ b/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx @@ -1,5 +1,10 @@ import * as db from '@tloncorp/shared/dist/db'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useMemo, useRef, useState } from 'react'; +import { + FlatList, + NativeScrollEvent, + NativeSyntheticEvent, +} from 'react-native'; import { View } from 'tamagui'; import { triggerHaptic } from '../../utils'; @@ -10,7 +15,13 @@ import { ToggleGroupInput } from '../Form'; import { ContactListItem } from '../ListItem'; import { Text } from '../TextV2'; -export function ViewReactionsPane({ post }: { post: db.Post }) { +export function ViewReactionsPane({ + post, + setIsScrolling, +}: { + post: db.Post; + setIsScrolling?: (isScrolling: boolean) => void; +}) { const groupedReactions = useGroupedReactions(post.reactions ?? []); const allReactions = useMemo(() => { @@ -49,6 +60,41 @@ export function ViewReactionsPane({ post }: { post: db.Post }) { setCurrentTab(newTab); }, []); + const scrollPosition = useRef(0); + const handleScroll = useCallback( + (event: NativeSyntheticEvent) => { + scrollPosition.current = event.nativeEvent.contentOffset.y; + }, + [] + ); + const onTouchStart = useCallback(() => { + if (scrollPosition.current > 0) { + setIsScrolling?.(true); + } + }, [setIsScrolling]); + const onTouchEnd = useCallback( + () => setIsScrolling?.(false), + [setIsScrolling] + ); + + const renderItem = useCallback( + ({ reaction }: { reaction: { value: string; userId: string } }) => { + return ( + {getNativeEmoji(reaction.value)} + } + > + ); + }, + [] + ); + return ( @@ -58,28 +104,20 @@ export function ViewReactionsPane({ post }: { post: db.Post }) { options={tabs} /> - + - {tabData.map((reaction) => ( - {getNativeEmoji(reaction.value)} - } - > - ))} + renderItem({ reaction: item })} + keyExtractor={(item) => item.userId + item.value} + onScroll={handleScroll} + onTouchStart={onTouchStart} + onTouchEnd={onTouchEnd} + /> - + ); } diff --git a/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx b/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx index f98bfd0244..11d5dba2cd 100644 --- a/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx +++ b/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx @@ -1,5 +1,5 @@ import * as db from '@tloncorp/shared/dist/db'; -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { ActionSheet } from '../ActionSheet'; import { ViewReactionsPane } from './ViewReactionsPane'; @@ -13,6 +13,7 @@ export function ViewReactionsSheet({ open: boolean; onOpenChange: (open: boolean) => void; }) { + const [isScrolling, setIsScrolling] = useState(false); const reactionCount = useMemo( () => post.reactions?.length ?? 0, [post.reactions] @@ -24,13 +25,14 @@ export function ViewReactionsSheet({ onOpenChange={onOpenChange} snapPointsMode="percent" snapPoints={[70]} + disableDrag={isScrolling} > - + ); } From b5ba816d5957b53ac07648192af9dd6e946bbc83 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 18 Oct 2024 08:31:23 -0500 Subject: [PATCH 113/259] welcome sheet: show again if user logs out and back in --- packages/app/hooks/useHandleLogout.native.ts | 2 ++ packages/app/hooks/useHandleLogout.ts | 2 ++ packages/app/utils/splash.ts | 3 +++ 3 files changed, 7 insertions(+) diff --git a/packages/app/hooks/useHandleLogout.native.ts b/packages/app/hooks/useHandleLogout.native.ts index c8b63ba706..def9429f4d 100644 --- a/packages/app/hooks/useHandleLogout.native.ts +++ b/packages/app/hooks/useHandleLogout.native.ts @@ -6,6 +6,7 @@ import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; import { clearShipInfo, useShip } from '../contexts/ship'; import { removeHostingToken, removeHostingUserId } from '../utils/hosting'; +import { clearSplashDismissed } from '../utils/splash'; const logger = createDevLogger('logout', true); @@ -22,6 +23,7 @@ export function useHandleLogout({ resetDb }: { resetDb: () => void }) { removeHostingUserId(); clearLure(); clearDeepLink(); + clearSplashDismissed(); if (!resetDb) { logger.trackError('could not reset db on logout'); return; diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index c4ddc08fde..267fd5fec4 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -10,6 +10,7 @@ import { removeHostingToken, removeHostingUserId, } from '../utils/hosting'; +import { clearSplashDismissed } from '../utils/splash'; const logger = createDevLogger('logout', true); @@ -27,6 +28,7 @@ export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { removeHostingAuthTracking(); clearLure(); clearDeepLink(); + clearSplashDismissed(); if (!resetDb) { logger.trackError('could not reset db on logout'); return; diff --git a/packages/app/utils/splash.ts b/packages/app/utils/splash.ts index 8aa1074b02..683eba9585 100644 --- a/packages/app/utils/splash.ts +++ b/packages/app/utils/splash.ts @@ -16,3 +16,6 @@ export const isSplashDismissed = async () => { export const setSplashDismissed = () => storage.save({ key: 'splash', data: true }); + +export const clearSplashDismissed = () => + storage.save({ key: 'splash', data: false }); From 88405746e2b69c6e1f1934b05afb502f144c3a05 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 18 Oct 2024 15:28:06 +0000 Subject: [PATCH 114/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 28d1bf4f40..69f85fcb3b 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v5.3brgr.lidn5.qroqi.175ho.qbrpf.glob' 0v5.3brgr.lidn5.qroqi.175ho.qbrpf] + glob-http+['https://bootstrap.urbit.org/glob-0v4.tb96j.2436j.2paik.8b0lq.kc7m8.glob' 0v4.tb96j.2436j.2paik.8b0lq.kc7m8] base+'groups' version+[6 4 2] website+'https://tlon.io' From 4889412f3f524188b09879a90a6c8343de733484 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 18 Oct 2024 13:27:50 -0400 Subject: [PATCH 115/259] add designed onboarding loader --- apps/tlon-mobile/src/App.main.tsx | 2 +- .../screens/Onboarding/ReserveShipScreen.tsx | 106 +++++++++++++++--- packages/app/contexts/signup.tsx | 42 ++++--- packages/app/hooks/useBootSequence.ts | 4 +- packages/app/lib/bootHelpers.ts | 30 +++-- packages/ui/src/assets/arvos_discussing.svg | 1 + .../ui/src/components/ArvosDiscussing.tsx | 17 +++ packages/ui/src/index.tsx | 1 + 8 files changed, 160 insertions(+), 43 deletions(-) create mode 100644 packages/ui/src/assets/arvos_discussing.svg create mode 100644 packages/ui/src/components/ArvosDiscussing.tsx diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 9f46e66379..5dc76b7cde 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -73,7 +73,7 @@ const App = () => { - ) : isAuthenticated && !signupContext.isOngoing ? ( + ) : isAuthenticated && !signupContext.didBeginSignup ? ( ) : ( diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index fa3eff19ac..ba9785a709 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -1,8 +1,18 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; -import { BootPhaseExplanations } from '@tloncorp/app/lib/bootHelpers'; -import { Spinner, Text, View, YStack } from '@tloncorp/ui'; -import { useEffect } from 'react'; +import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; +import { + ArvosDiscussing, + IconType, + ListItem, + LoadingSpinner, + OnboardingTextBlock, + ScreenHeader, + View, + YStack, +} from '@tloncorp/ui'; +import { useLureMetadata } from 'packages/app/contexts/branch'; +import { useEffect, useMemo } from 'react'; import type { OnboardingStackParamList } from '../../types'; @@ -10,6 +20,7 @@ type Props = NativeStackScreenProps; export const ReserveShipScreen = ({ navigation }: Props) => { const signupContext = useSignupContext(); + const lureMeta = useLureMetadata(); // Disable back button once you reach this screen useEffect( @@ -27,17 +38,84 @@ export const ReserveShipScreen = ({ navigation }: Props) => { }, [signupContext]); return ( - - - - - Booting your new P2P node for the first time... - - {/* TOOD: add back in when design is ready */} - {/* - {BootPhaseExplanations[signupContext.bootPhase]} - */} - + + + + + + ); }; + +interface DisplayStep { + description: string; + icon: IconType; + startExclusive: NodeBootPhase; + endInclusive: NodeBootPhase; +} +function BootStepDisplay(props: { + bootPhase: NodeBootPhase; + withInvites: boolean; +}) { + const displaySteps = useMemo(() => { + const steps: DisplayStep[] = [ + { + description: 'Unboxing your new peer', + icon: 'Gift', + startExclusive: NodeBootPhase.IDLE, + endInclusive: NodeBootPhase.BOOTING, + }, + { + description: 'Connecting to the network', + icon: 'Link', + startExclusive: NodeBootPhase.BOOTING, + endInclusive: NodeBootPhase.CONNECTING, + }, + ]; + + if (props.withInvites) { + steps.push({ + description: 'Finding peers on the network', + icon: 'ChannelGalleries', + startExclusive: NodeBootPhase.CONNECTING, + endInclusive: NodeBootPhase.ACCEPTING_INVITES, + }); + } + + return steps; + }, [props.withInvites]); + + return ( + + {displaySteps.map((step, index) => { + const isOnStep = + props.bootPhase > step.startExclusive && + props.bootPhase <= step.endInclusive; + const hasCompleted = props.bootPhase > step.endInclusive; + return ( + + + + {step.description} + + + {isOnStep && } + {hasCompleted && } + + + ); + })} + + ); +} diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index 67b46bde2c..19d236d76d 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -130,23 +130,31 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { values.didCompleteSignup && bootPhase === NodeBootPhase.READY ) { - logger.log('running post-signup actions'); - const postSignupParams = { - nickname: values.nickname, - telemetry: values.telemetry, - notificationToken: values.notificationToken, - }; - handlePostSignup(postSignupParams); - clear(); - logger.trackEvent('hosted signup report', { - bootDuration: bootReport - ? bootReport.completedAt - bootReport.startedAt - : null, - userSatWaitingFor: values.userWasReadyAt - ? Date.now() - values.userWasReadyAt - : null, - timeUnit: 'ms', - }); + try { + logger.log('running post-signup actions'); + const postSignupParams = { + nickname: values.nickname, + telemetry: values.telemetry, + notificationToken: values.notificationToken, + }; + handlePostSignup(postSignupParams); + logger.trackEvent('hosted signup report', { + bootDuration: bootReport + ? bootReport.completedAt - bootReport.startedAt + : null, + userSatWaitingFor: values.userWasReadyAt + ? Date.now() - values.userWasReadyAt + : null, + timeUnit: 'ms', + }); + } catch (e) { + logger.trackError('post signup error', { + errorMessage: e.message, + errorStack: e.stack, + }); + } finally { + setTimeout(() => clear(), 2000); + } } }, [values, bootPhase, clear, bootReport]); diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index 77a4779eb9..e060d43f32 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -4,7 +4,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { useLureMetadata } from '../contexts/branch'; import { useShip } from '../contexts/ship'; -import { NodeBootPhase } from '../lib/bootHelpers'; +import { BootPhaseNames, NodeBootPhase } from '../lib/bootHelpers'; import BootHelpers from '../lib/bootHelpers'; import { getShipFromCookie } from '../utils/ship'; import { useConfigureUrbitClient } from './useConfigureUrbitClient'; @@ -264,7 +264,7 @@ export function useBootSequence({ lastRunPhaseRef.current = bootPhase; lastRunErrored.current = false; - logger.log(`running boot sequence phase: ${bootPhase}`); + logger.log(`running boot sequence phase: ${BootPhaseNames[bootPhase]}`); const nextBootPhase = await runBootPhase(); setBootPhase(nextBootPhase); diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts index 4c0dfa47f7..60866871c9 100644 --- a/packages/app/lib/bootHelpers.ts +++ b/packages/app/lib/bootHelpers.ts @@ -7,15 +7,15 @@ import { trackOnboardingAction } from '../utils/posthog'; import { getShipFromCookie, getShipUrl } from '../utils/ship'; export enum NodeBootPhase { - IDLE = 'idle', - RESERVING = 'reserving', - BOOTING = 'booting', - AUTHENTICATING = 'authenticating', - CONNECTING = 'connecting', - CHECKING_FOR_INVITE = 'checking-for-invite', - ACCEPTING_INVITES = 'accepting-invites', - READY = 'ready', - ERROR = 'error', + IDLE = 1, + RESERVING = 2, + BOOTING = 3, + AUTHENTICATING = 4, + CONNECTING = 5, + CHECKING_FOR_INVITE = 6, + ACCEPTING_INVITES = 7, + READY = 200, + ERROR = 400, } export const BootPhaseExplanations: Record = { @@ -31,6 +31,18 @@ export const BootPhaseExplanations: Record = { [NodeBootPhase.ERROR]: 'Your node errored while initializing', }; +export const BootPhaseNames: Record = { + [NodeBootPhase.IDLE]: 'Idle', + [NodeBootPhase.RESERVING]: 'Reserving', + [NodeBootPhase.BOOTING]: 'Booting', + [NodeBootPhase.AUTHENTICATING]: 'Authenticating', + [NodeBootPhase.CONNECTING]: 'Connecting', + [NodeBootPhase.CHECKING_FOR_INVITE]: 'Checking for Invites', + [NodeBootPhase.ACCEPTING_INVITES]: 'Accepting Invites', + [NodeBootPhase.READY]: 'Ready', + [NodeBootPhase.ERROR]: 'Error', +}; + export default { NodeBootPhase, reserveNode, diff --git a/packages/ui/src/assets/arvos_discussing.svg b/packages/ui/src/assets/arvos_discussing.svg new file mode 100644 index 0000000000..51621d4a80 --- /dev/null +++ b/packages/ui/src/assets/arvos_discussing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/ui/src/components/ArvosDiscussing.tsx b/packages/ui/src/components/ArvosDiscussing.tsx new file mode 100644 index 0000000000..2af393d78d --- /dev/null +++ b/packages/ui/src/components/ArvosDiscussing.tsx @@ -0,0 +1,17 @@ +import { styled } from 'tamagui'; + +import ArvosDiscussingSvg from '../assets/arvos_discussing.svg'; + +export const ArvosDiscussing = styled( + ArvosDiscussingSvg, + { + color: '$primaryText', + }, + { + accept: { + color: 'color', + width: 'size', + height: 'size', + }, + } +); diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index 7d4a1e50e2..646066520e 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -74,6 +74,7 @@ export * from './components/UserProfileScreenView'; export * from './components/View'; export * from './components/WelcomeSheet'; export * from './components/Image'; +export * from './components/ArvosDiscussing'; export * as Form from './components/Form'; export * from './contexts'; export * from './tamagui.config'; From fbe096366e1e4229d12d6d240a99c580e8e98b99 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 18 Oct 2024 13:32:30 -0400 Subject: [PATCH 116/259] too much excite --- apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index ba9785a709..dd7f317257 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -43,7 +43,7 @@ export const ReserveShipScreen = ({ navigation }: Props) => { title={ signupContext.bootPhase < NodeBootPhase.READY ? "We're setting you up" - : 'Setup complete!!' + : 'Setup complete!' } showSessionStatus={false} /> From ab1e639df6d8e78765494de3ca9dcfdce7ff0f61 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 18 Oct 2024 13:39:37 -0400 Subject: [PATCH 117/259] bad import --- apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index dd7f317257..747b9daef8 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -1,4 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { useLureMetadata } from '@tloncorp/app/contexts/branch'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; import { @@ -11,7 +12,6 @@ import { View, YStack, } from '@tloncorp/ui'; -import { useLureMetadata } from 'packages/app/contexts/branch'; import { useEffect, useMemo } from 'react'; import type { OnboardingStackParamList } from '../../types'; From f54f6ba893dbb5473b8ee8493eb775faf27932de Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Fri, 18 Oct 2024 13:46:12 -0400 Subject: [PATCH 118/259] ops bump version --- apps/tlon-mobile/android/app/build.gradle | 2 +- apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/tlon-mobile/android/app/build.gradle b/apps/tlon-mobile/android/app/build.gradle index 6603e28a5f..4ae092d499 100644 --- a/apps/tlon-mobile/android/app/build.gradle +++ b/apps/tlon-mobile/android/app/build.gradle @@ -88,7 +88,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion compileSdk rootProject.ext.compileSdkVersion versionCode 108 - versionName "4.0.3" + versionName "4.1.0" buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString()) } diff --git a/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj b/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj index 76206dad3c..0e17d10661 100644 --- a/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj +++ b/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj @@ -1395,7 +1395,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.0.3; + MARKETING_VERSION = 4.1.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -1433,7 +1433,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.0.3; + MARKETING_VERSION = 4.1.0; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", From 1f9ff6d7d68e0b1bbb65a0c645d71c270cc2621c Mon Sep 17 00:00:00 2001 From: David Lee Date: Sat, 28 Sep 2024 12:31:41 -0700 Subject: [PATCH 119/259] [wip] Stow channel content configuration in structured channel description --- .../shared/src/api/channelContentConfig.ts | 109 ++++++++++++++++++ packages/shared/src/api/chatApi.ts | 28 ++++- packages/shared/src/api/groupsApi.ts | 22 +++- packages/shared/src/api/index.ts | 1 + ...tarantula.sql => 0000_old_gorilla_man.sql} | 1 + .../src/db/migrations/meta/0000_snapshot.json | 9 +- .../src/db/migrations/meta/_journal.json | 4 +- .../shared/src/db/migrations/migrations.js | 2 +- packages/shared/src/db/queries.ts | 3 +- packages/shared/src/db/schema.ts | 2 + packages/shared/src/store/channelActions.ts | 21 +++- 11 files changed, 191 insertions(+), 11 deletions(-) create mode 100644 packages/shared/src/api/channelContentConfig.ts rename packages/shared/src/db/migrations/{0000_tidy_tarantula.sql => 0000_old_gorilla_man.sql} (99%) diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts new file mode 100644 index 0000000000..1d6be68511 --- /dev/null +++ b/packages/shared/src/api/channelContentConfig.ts @@ -0,0 +1,109 @@ +type PostContent = 'TODO: PostContent'; + +type RenderTarget = JSX.Element; + +type DraftInputId = Nominal; +type PostContentType = Nominal; +type PostContentRendererId = Nominal; + +export enum CollectionRendererId { + listBottomToTop = 'tlon.r0.list-bottom-to-top', + listTopToBottom = 'tlon.r0.list-top-to-bottom', + grid = 'tlon.r0.grid', +} + +/** + * Configures the custom components used to create content in a channel. + */ +export interface ChannelContentConfiguration { + /** + * Which controls are available when composing a new post? + */ + draftInputs: DraftInputId[]; + + /** + * How should we render a given post content type? + * + * This spec takes precedence over the client's default renderer mapping, but + * does not take precedence over any mapping specified in a post's metadata. + */ + defaultPostContentRenderers: Array<{ + /** + * A post's content type is checked against this field - if it matches, + * we'll use the renderer specified here. + */ + match: PostContentType; + + renderer: PostContentRendererId; + }>; + + /** + * How should we render the entire collection of posts? (list, grid, etc) + */ + defaultPostCollectionRenderer: CollectionRendererId; +} + +/** + * How does a given post content renderer render a post content? + */ +export interface PostContentRendererDescription { + render: (props: { content: PostContent }) => RenderTarget; +} + +/** + * How does a given draft input render its controls? + */ +export interface DraftInputDescription { + render: (props: { ref: React.Ref<{ value: Payload }> }) => RenderTarget; +} + +/** + * Singleton registries of all available tagged components. + * + * If a channel or post specifies a draft input ID or post content + * renderer ID that is not registered here, this client does not support it. + */ +export const kits = { + postContentRenderers: {} as { + [id in PostContentRendererId]: PostContentRendererDescription; + }, + + draftInputs: {} as { + [id in DraftInputId]: DraftInputDescription; + }, + + draftInputIds: { + chat: 'tlon.r0.chat-input' as DraftInputId, + }, +}; + +/** + * We use a channel's `description` field to store structured data. This + * module provides helpers for managing that data. + */ +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace StructuredChannelDescriptionPayload { + type Encoded = string; + interface Decoded { + channelContentConfiguration: ChannelContentConfiguration; + description?: string; + } + + export function encode(payload: Decoded): Encoded { + return JSON.stringify(payload); + } + export function decodeOrNull(encoded: Encoded): Decoded | null { + // TODO: This should be validated - we'll be deserializing untrusted data + try { + return JSON.parse(encoded); + } catch (_err) { + return null; + } + } +} + +// -------- Helpers below here -------- // + +type _NominalTag = { __nominalTag: Tag }; + +type Nominal = BaseType & _NominalTag; diff --git a/packages/shared/src/api/chatApi.ts b/packages/shared/src/api/chatApi.ts index e88d51911f..1ecd2c35e2 100644 --- a/packages/shared/src/api/chatApi.ts +++ b/packages/shared/src/api/chatApi.ts @@ -8,6 +8,10 @@ import { getCanonicalPostId, toClientMeta, } from './apiUtils'; +import { + ChannelContentConfiguration, + StructuredChannelDescriptionPayload, +} from './channelContentConfig'; import { toPostData, toPostReplyData, toReplyMeta } from './postsApi'; import { getCurrentUserId, poke, scry, subscribe, trackedPoke } from './urbit'; @@ -303,7 +307,7 @@ export const getGroupDms = async (): Promise => { export const toClientGroupDms = (groupDms: ub.Clubs): GetDmsResponse => { const currentUserId = getCurrentUserId(); return Object.entries(groupDms) - .map(([id, club]) => { + .map(([id, club]): db.Channel | null => { const joinedMembers = club.team.map( (member): db.ChatMember => ({ contactId: member, @@ -333,12 +337,32 @@ export const toClientGroupDms = (groupDms: ub.Clubs): GetDmsResponse => { return null; } + const metaFields = toClientMeta(club.meta); + + // Decode structured description payload if possible. + const decodedDesc = + metaFields.description == null + ? null + : StructuredChannelDescriptionPayload.decodeOrNull( + metaFields.description + ); + let contentConfiguration: ChannelContentConfiguration | undefined; + if (decodedDesc != null) { + // If the `description` field on API was a structured payload, unpack + // the payload's interior `description` field into our local + // `description` field. + metaFields.description = decodedDesc.description; + + contentConfiguration = decodedDesc.channelContentConfiguration; + } + return { id, type: 'groupDm', - ...toClientMeta(club.meta), + ...metaFields, isDmInvite: !isJoined && isInvited, members: [...joinedMembers, ...invitedMembers], + contentConfiguration, }; }) .filter(Boolean) as db.Channel[]; diff --git a/packages/shared/src/api/groupsApi.ts b/packages/shared/src/api/groupsApi.ts index 33079e613d..f6967c7e6e 100644 --- a/packages/shared/src/api/groupsApi.ts +++ b/packages/shared/src/api/groupsApi.ts @@ -13,6 +13,10 @@ import { getJoinStatusFromGang, } from '../urbit'; import { parseGroupId, toClientMeta } from './apiUtils'; +import { + ChannelContentConfiguration, + StructuredChannelDescriptionPayload, +} from './channelContentConfig'; import { getCurrentUserId, poke, @@ -1455,6 +1459,21 @@ function toClientChannel({ channel: ub.GroupChannel; groupId: string; }): db.Channel { + // Decode structured description payload if possible. + let description: string | null = channel.meta.description; + const decodedDesc = + description == null || description.length === 0 + ? null + : StructuredChannelDescriptionPayload.decodeOrNull(description); + let contentConfiguration: ChannelContentConfiguration | undefined; + if (decodedDesc != null) { + // If the `description` field on API was a structured payload, unpack + // the payload's interior `description` field into our local + // `description` field. + description = omitEmpty(decodedDesc.description ?? ''); + + contentConfiguration = decodedDesc.channelContentConfiguration; + } return { id, groupId, @@ -1462,7 +1481,8 @@ function toClientChannel({ iconImage: omitEmpty(channel.meta.image), title: omitEmpty(channel.meta.title), coverImage: omitEmpty(channel.meta.cover), - description: omitEmpty(channel.meta.description), + description, + contentConfiguration, }; } diff --git a/packages/shared/src/api/index.ts b/packages/shared/src/api/index.ts index b89ea29f41..7065b2c729 100644 --- a/packages/shared/src/api/index.ts +++ b/packages/shared/src/api/index.ts @@ -1,3 +1,4 @@ +export * from './channelContentConfig'; export * from './channelsApi'; export * from './chatApi'; export * from './contactsApi'; diff --git a/packages/shared/src/db/migrations/0000_tidy_tarantula.sql b/packages/shared/src/db/migrations/0000_old_gorilla_man.sql similarity index 99% rename from packages/shared/src/db/migrations/0000_tidy_tarantula.sql rename to packages/shared/src/db/migrations/0000_old_gorilla_man.sql index c296309e1f..5a21b1b719 100644 --- a/packages/shared/src/db/migrations/0000_tidy_tarantula.sql +++ b/packages/shared/src/db/migrations/0000_old_gorilla_man.sql @@ -64,6 +64,7 @@ CREATE TABLE `channels` ( `remote_updated_at` integer, `last_viewed_at` integer, `is_default_welcome_channel` integer, + `content_configuration` text, FOREIGN KEY (`group_id`) REFERENCES `groups`(`id`) ON UPDATE no action ON DELETE cascade ); --> statement-breakpoint diff --git a/packages/shared/src/db/migrations/meta/0000_snapshot.json b/packages/shared/src/db/migrations/meta/0000_snapshot.json index dbe29df1b0..319d3d565a 100644 --- a/packages/shared/src/db/migrations/meta/0000_snapshot.json +++ b/packages/shared/src/db/migrations/meta/0000_snapshot.json @@ -1,7 +1,7 @@ { "version": "5", "dialect": "sqlite", - "id": "d3b5845c-7fa4-48d9-ba18-3e237654d040", + "id": "c5048b06-4a47-473f-b579-03a848864cdc", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "activity_events": { @@ -416,6 +416,13 @@ "primaryKey": false, "notNull": false, "autoincrement": false + }, + "content_configuration": { + "name": "content_configuration", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false } }, "indexes": { diff --git a/packages/shared/src/db/migrations/meta/_journal.json b/packages/shared/src/db/migrations/meta/_journal.json index 2bc2d2fc54..3bf266abc6 100644 --- a/packages/shared/src/db/migrations/meta/_journal.json +++ b/packages/shared/src/db/migrations/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1723573491052, - "tag": "0000_tidy_tarantula", + "when": 1727490999066, + "tag": "0000_old_gorilla_man", "breakpoints": true } ] diff --git a/packages/shared/src/db/migrations/migrations.js b/packages/shared/src/db/migrations/migrations.js index 2391fe2fd5..4be6266255 100644 --- a/packages/shared/src/db/migrations/migrations.js +++ b/packages/shared/src/db/migrations/migrations.js @@ -1,7 +1,7 @@ // This file is required for Expo/React Native SQLite migrations - https://orm.drizzle.team/quick-sqlite/expo import journal from './meta/_journal.json'; -import m0000 from './0000_tidy_tarantula.sql'; +import m0000 from './0000_old_gorilla_man.sql'; export default { journal, diff --git a/packages/shared/src/db/queries.ts b/packages/shared/src/db/queries.ts index 61bf466d0e..5ccb282ba8 100644 --- a/packages/shared/src/db/queries.ts +++ b/packages/shared/src/db/queries.ts @@ -407,7 +407,8 @@ export const insertGroups = createWriteQuery( $channels.description, $channels.addedToGroupAt, $channels.type, - $channels.isPendingChannel + $channels.isPendingChannel, + $channels.contentConfiguration ), }); } diff --git a/packages/shared/src/db/schema.ts b/packages/shared/src/db/schema.ts index 8a234cd60f..f7ae7fa2a8 100644 --- a/packages/shared/src/db/schema.ts +++ b/packages/shared/src/db/schema.ts @@ -702,6 +702,8 @@ export const channels = sqliteTable( * True if this channel was autocreated during new group creation (on this client) */ isDefaultWelcomeChannel: boolean('is_default_welcome_channel'), + + contentConfiguration: text('content_configuration', { mode: 'json' }), }, (table) => ({ lastPostIdIndex: index('last_post_id').on(table.lastPostId), diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index d16c1e58e4..385aa7448f 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -1,4 +1,8 @@ import * as api from '../api'; +import { + ChannelContentConfiguration, + StructuredChannelDescriptionPayload, +} from '../api/channelContentConfig'; import * as db from '../db'; import { createDevLogger } from '../debug'; import * as logic from '../logic'; @@ -11,8 +15,9 @@ export async function createChannel({ channelId, name, title, - description, + description: rawDescription, channelType, + contentConfiguration, }: { groupId: string; channelId: string; @@ -20,12 +25,14 @@ export async function createChannel({ title: string; description?: string; channelType: Omit; + contentConfiguration?: ChannelContentConfiguration; }) { // optimistic update const newChannel: db.Channel = { id: channelId, title, - description: description ?? '', + description: rawDescription, + contentConfiguration, type: channelType as db.ChannelType, groupId, addedToGroupAt: Date.now(), @@ -33,6 +40,14 @@ export async function createChannel({ }; await db.insertChannels([newChannel]); + const encodedDescription = + contentConfiguration == null + ? rawDescription + : StructuredChannelDescriptionPayload.encode({ + description: rawDescription, + channelContentConfiguration: contentConfiguration, + }); + try { await api.addChannelToGroup({ groupId, channelId, sectionId: 'default' }); await api.createChannel({ @@ -41,7 +56,7 @@ export async function createChannel({ group: groupId, name, title, - description: description ?? '', + description: encodedDescription ?? '', readers: [], writers: [], }); From 692db08e7bde72d559c616e89f2ca93371c6aca9 Mon Sep 17 00:00:00 2001 From: David Lee Date: Wed, 9 Oct 2024 14:34:54 -0700 Subject: [PATCH 120/259] Pull post content rendering switch into component --- .../ui/src/components/Channel/Scroller.tsx | 2 +- packages/ui/src/components/Channel/index.tsx | 33 +++++++++++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 7652e0c79a..81e0fdd6bd 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -64,7 +64,7 @@ type RenderItemFunction = (props: { isHighlighted?: boolean; }) => ReactElement | null; -type RenderItemType = +export type RenderItemType = | RenderItemFunction | React.MemoExoticComponent; diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 52f03d58f4..5106177138 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -18,6 +18,7 @@ import { ChannelProvider, GroupsProvider, NavigationProvider, + useChannelContext, useCurrentUserId, } from '../../contexts'; import { Attachment, AttachmentProvider } from '../../contexts/attachment'; @@ -39,7 +40,7 @@ import { ChannelFooter } from './ChannelFooter'; import { ChannelHeader, ChannelHeaderItemsProvider } from './ChannelHeader'; import { DmInviteOptions } from './DmInviteOptions'; import { EmptyChannelNotice } from './EmptyChannelNotice'; -import Scroller, { ScrollAnchor } from './Scroller'; +import Scroller, { RenderItemType, ScrollAnchor } from './Scroller'; export { INITIAL_POSTS_PER_PAGE } from './Scroller'; @@ -139,11 +140,6 @@ export function Channel({ ); const isChatChannel = channel ? getIsChatChannel(channel) : true; - const renderItem = isChatChannel - ? ChatMessage - : channel.type === 'notebook' - ? NotebookPost - : GalleryPost; const renderEmptyComponent = useCallback(() => { return ; @@ -317,7 +313,7 @@ export function Channel({ collectionLayout.scrollDirection === 'bottom-to-top' } - renderItem={renderItem} + renderItem={PostView} renderEmptyComponent={renderEmptyComponent} anchor={scrollerAnchor} posts={posts} @@ -437,3 +433,26 @@ function NegotionMismatchNotice() { ); } + +const PostView: RenderItemType = (props) => { + const channel = useChannelContext(); + + const SpecificPostComponent = useMemo(() => { + switch (channel.type) { + case 'chat': + // fallthrough + case 'dm': + // fallthrough + case 'groupDm': + return ChatMessage; + + case 'notebook': + return NotebookPost; + + case 'gallery': + return GalleryPost; + } + }, [channel.type]); + + return ; +}; From c38b04f95d05b33f1e4ab9eadbf81622fb35db60 Mon Sep 17 00:00:00 2001 From: David Lee Date: Wed, 9 Oct 2024 17:25:19 -0700 Subject: [PATCH 121/259] Control draft input and post content renderer using content configuration --- packages/app/hooks/useGroupContext.ts | 40 +++ .../shared/src/api/channelContentConfig.ts | 49 +-- .../ui/src/components/Channel/Scroller.tsx | 23 +- packages/ui/src/components/Channel/index.tsx | 340 ++++++++++-------- packages/ui/src/contexts/componentsKits.tsx | 118 ++++++ 5 files changed, 365 insertions(+), 205 deletions(-) create mode 100644 packages/ui/src/contexts/componentsKits.tsx diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index 11f5553fb3..d00eb56aad 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -1,4 +1,9 @@ import { sync } from '@tloncorp/shared'; +import { + ChannelContentConfiguration, + CollectionRendererId, + PostContentRendererId, +} from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; import { assembleNewChannelIdAndName } from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; @@ -129,6 +134,8 @@ export const useGroupContext = ({ title, description, channelType, + contentConfiguration: + channelContentConfigurationForChannelType(channelType), }); } }, @@ -396,3 +403,36 @@ export const useGroupContext = ({ groupPrivacyType, }; }; + +function channelContentConfigurationForChannelType( + channelType: Omit +): ChannelContentConfiguration { + switch (channelType) { + case 'chat': + return { + draftInput: 'tlon.r0.input.chat', + defaultPostContentRenderers: { + chat: PostContentRendererId.create('tlon.r0.content.chat'), + }, + defaultPostCollectionRenderer: CollectionRendererId.chat, + }; + case 'notebook': + return { + draftInput: 'tlon.r0.input.notebook', + defaultPostContentRenderers: { + block: PostContentRendererId.create('tlon.r0.content.notebook'), + }, + defaultPostCollectionRenderer: CollectionRendererId.notebook, + }; + case 'gallery': + return { + draftInput: 'tlon.r0.input.gallery', + defaultPostContentRenderers: { + chat: PostContentRendererId.create('tlon.r0.content.gallery'), + }, + defaultPostCollectionRenderer: CollectionRendererId.gallery, + }; + } + + throw new Error('Unknown channel type'); +} diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index 1d6be68511..a7ca93fe30 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -2,14 +2,21 @@ type PostContent = 'TODO: PostContent'; type RenderTarget = JSX.Element; -type DraftInputId = Nominal; -type PostContentType = Nominal; +type DraftInputId = string; +type PostContentType = 'block' | 'chat' | 'notice' | 'note' | 'reply'; type PostContentRendererId = Nominal; +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace PostContentRendererId { + export function create(id: string): PostContentRendererId { + return id as PostContentRendererId; + } +} + export enum CollectionRendererId { - listBottomToTop = 'tlon.r0.list-bottom-to-top', - listTopToBottom = 'tlon.r0.list-top-to-bottom', - grid = 'tlon.r0.grid', + notebook = 'tlon.r0.notebook', + chat = 'tlon.r0.chat', + gallery = 'tlon.r0.gallery', } /** @@ -19,7 +26,7 @@ export interface ChannelContentConfiguration { /** * Which controls are available when composing a new post? */ - draftInputs: DraftInputId[]; + draftInput: DraftInputId; /** * How should we render a given post content type? @@ -27,14 +34,8 @@ export interface ChannelContentConfiguration { * This spec takes precedence over the client's default renderer mapping, but * does not take precedence over any mapping specified in a post's metadata. */ - defaultPostContentRenderers: Array<{ - /** - * A post's content type is checked against this field - if it matches, - * we'll use the renderer specified here. - */ - match: PostContentType; - - renderer: PostContentRendererId; + defaultPostContentRenderers: Partial<{ + [Match in PostContentType]: PostContentRendererId; }>; /** @@ -57,26 +58,6 @@ export interface DraftInputDescription { render: (props: { ref: React.Ref<{ value: Payload }> }) => RenderTarget; } -/** - * Singleton registries of all available tagged components. - * - * If a channel or post specifies a draft input ID or post content - * renderer ID that is not registered here, this client does not support it. - */ -export const kits = { - postContentRenderers: {} as { - [id in PostContentRendererId]: PostContentRendererDescription; - }, - - draftInputs: {} as { - [id in DraftInputId]: DraftInputDescription; - }, - - draftInputIds: { - chat: 'tlon.r0.chat-input' as DraftInputId, - }, -}; - /** * We use a channel's `description` field to store structured data. This * module provides helpers for managing that data. diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 81e0fdd6bd..0949fe8e88 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -7,7 +7,6 @@ import { import { createDevLogger } from '@tloncorp/shared/dist'; import * as db from '@tloncorp/shared/dist/db'; import { isSameDay } from '@tloncorp/shared/dist/logic'; -import { Story } from '@tloncorp/shared/dist/urbit'; import { isEqual } from 'lodash'; import React, { PropsWithChildren, @@ -34,6 +33,7 @@ import Animated from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { View, styled, useStyle, useTheme } from 'tamagui'; +import { RenderItemType } from '../../contexts/componentsKits'; import { useLivePost } from '../../contexts/requests'; import { useScrollDirectionTracker } from '../../contexts/scroll'; import { ChatMessageActions } from '../ChatMessage/ChatMessageActions/Component'; @@ -47,27 +47,6 @@ interface PostWithNeighbors { older: db.Post | null; } -type RenderItemFunction = (props: { - post: db.Post; - showAuthor?: boolean; - showReplies?: boolean; - onPress?: (post: db.Post) => void; - onPressReplies?: (post: db.Post) => void; - onPressImage?: (post: db.Post, imageUri?: string) => void; - onLongPress?: (post: db.Post) => void; - editing?: boolean; - setEditingPost?: (post: db.Post | undefined) => void; - setViewReactionsPost?: (post: db.Post) => void; - editPost?: (post: db.Post, content: Story) => Promise; - onPressRetry: (post: db.Post) => void; - onPressDelete: (post: db.Post) => void; - isHighlighted?: boolean; -}) => ReactElement | null; - -export type RenderItemType = - | RenderItemFunction - | React.MemoExoticComponent; - const logger = createDevLogger('scroller', false); export const INITIAL_POSTS_PER_PAGE = 30; diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 5106177138..a500254084 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -9,6 +9,7 @@ import { import * as db from '@tloncorp/shared/dist/db'; import { JSONContent, Story } from '@tloncorp/shared/dist/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; +import { ChannelContentConfiguration } from 'packages/shared/dist/api'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FlatList } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; @@ -22,6 +23,11 @@ import { useCurrentUserId, } from '../../contexts'; import { Attachment, AttachmentProvider } from '../../contexts/attachment'; +import { + PostContentRendererContextProvider, + RenderItemType, + usePostContentRenderersContext, +} from '../../contexts/componentsKits'; import { RequestsProvider } from '../../contexts/requests'; import { ScrollContextProvider } from '../../contexts/scroll'; import * as utils from '../../utils'; @@ -29,18 +35,13 @@ import { ChatMessage } from '../ChatMessage'; import { GalleryPost } from '../GalleryPost'; import { GroupPreviewAction, GroupPreviewSheet } from '../GroupPreviewSheet'; import { NotebookPost } from '../NotebookPost'; -import { - ChatInput, - DraftInputContext, - GalleryInput, - NotebookInput, -} from '../draftInputs'; +import { DraftInputContext } from '../draftInputs'; import { DraftInputHandle, GalleryDraftType } from '../draftInputs/shared'; import { ChannelFooter } from './ChannelFooter'; import { ChannelHeader, ChannelHeaderItemsProvider } from './ChannelHeader'; import { DmInviteOptions } from './DmInviteOptions'; import { EmptyChannelNotice } from './EmptyChannelNotice'; -import Scroller, { RenderItemType, ScrollAnchor } from './Scroller'; +import Scroller, { ScrollAnchor } from './Scroller'; export { INITIAL_POSTS_PER_PAGE } from './Scroller'; @@ -255,161 +256,178 @@ export function Channel({ ] ); + const channelContentConfiguration = channel.contentConfiguration as + | ChannelContentConfiguration + | undefined; + return ( - {}} - > - + {}} > - - - - - <> - - draftInputPresentationMode === 'fullscreen' && - draftInputRef.current != null - ? draftInputRef.current.exitFullscreen() - : goBack() - } - showSearchButton={isChatChannel} - goToSearch={goToSearch} - showSpinner={isLoadingPosts} - showMenuButton={true} - /> - - - {draftInputPresentationMode !== 'fullscreen' && ( - - {channel && posts && ( - 0 - ? initialChannelUnread?.firstUnreadPostId - : null - } - unreadCount={ - initialChannelUnread?.countWithoutThreads ?? - 0 - } - onPressPost={ - isChatChannel ? undefined : goToPost - } - onPressReplies={goToPost} - onPressImage={goToImageViewer} - onEndReached={onScrollEndReached} - onStartReached={onScrollStartReached} - onPressRetry={onPressRetry} - onPressDelete={onPressDelete} - activeMessage={activeMessage} - setActiveMessage={setActiveMessage} - ref={flatListRef} - headerMode={headerMode} - /> - )} - - )} - - - {canWrite && ( - <> - {isChatChannel && - !channel.isDmInvite && - (negotiationMatch ? ( - - ) : ( - - - - ))} - - {channel.type === 'gallery' && ( - + + + + + <> + + draftInputPresentationMode === 'fullscreen' && + draftInputRef.current != null + ? draftInputRef.current.exitFullscreen() + : goBack() + } + showSearchButton={isChatChannel} + goToSearch={goToSearch} + showSpinner={isLoadingPosts} + showMenuButton={true} + /> + + + {draftInputPresentationMode !== 'fullscreen' && ( + + {channel && posts && ( + 0 + ? initialChannelUnread?.firstUnreadPostId + : null + } + unreadCount={ + initialChannelUnread?.countWithoutThreads ?? + 0 + } + onPressPost={ + isChatChannel ? undefined : goToPost + } + onPressReplies={goToPost} + onPressImage={goToImageViewer} + onEndReached={onScrollEndReached} + onStartReached={onScrollStartReached} + onPressRetry={onPressRetry} + onPressDelete={onPressDelete} + activeMessage={activeMessage} + setActiveMessage={setActiveMessage} + ref={flatListRef} + headerMode={headerMode} + /> + )} + )} + + + {canWrite && + (channelContentConfiguration == null ? ( + <> + {isChatChannel && + !channel.isDmInvite && + (negotiationMatch ? ( + + ) : ( + + + + ))} + + {channel.type === 'gallery' && ( + + )} - {channel.type === 'notebook' && ( - + )} + + ) : ( + - )} - - )} + ))} - {channel.isDmInvite && ( - + )} + + {headerMode === 'next' ? ( + - )} - - {headerMode === 'next' ? ( - setGroupPreview(null)} + onActionComplete={handleGroupAction} /> - ) : null} - setGroupPreview(null)} - onActionComplete={handleGroupAction} - /> - - - - - - - + + + + + + + + @@ -436,8 +454,21 @@ function NegotionMismatchNotice() { const PostView: RenderItemType = (props) => { const channel = useChannelContext(); + const { renderers } = usePostContentRenderersContext(); const SpecificPostComponent = useMemo(() => { + const contentConfig = channel.contentConfiguration as + | ChannelContentConfiguration + | undefined; + if (contentConfig != null) { + const rendererId = + contentConfig.defaultPostContentRenderers[props.post.type]; + if (rendererId != null && renderers[rendererId] != null) { + return renderers[rendererId]; + } + } + + // content config did not provide a renderer, fall back to default switch (channel.type) { case 'chat': // fallthrough @@ -452,7 +483,18 @@ const PostView: RenderItemType = (props) => { case 'gallery': return GalleryPost; } - }, [channel.type]); + }, [channel.type, channel.contentConfiguration, props.post.type, renderers]); return ; }; + +function DraftInputView(props: { + draftInputContext: DraftInputContext; + type: string; +}) { + const { inputs } = usePostContentRenderersContext(); + const InputComponent = inputs[props.type]; + if (InputComponent) { + return ; + } +} diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx new file mode 100644 index 0000000000..f74756330c --- /dev/null +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -0,0 +1,118 @@ +import * as db from '@tloncorp/shared/dist/db'; +import { Story } from '@tloncorp/shared/dist/urbit'; +import { + ReactElement, + createContext, + useCallback, + useContext, + useMemo, + useState, +} from 'react'; + +import { ChatMessage } from '../components/ChatMessage'; +import { GalleryPost } from '../components/GalleryPost'; +import { + ChatInput, + DraftInputContext, + GalleryInput, + NotebookInput, +} from '../components/draftInputs'; + +type RenderItemFunction = (props: { + post: db.Post; + showAuthor?: boolean; + showReplies?: boolean; + onPress?: (post: db.Post) => void; + onPressReplies?: (post: db.Post) => void; + onPressImage?: (post: db.Post, imageUri?: string) => void; + onLongPress?: (post: db.Post) => void; + editing?: boolean; + setEditingPost?: (post: db.Post | undefined) => void; + setViewReactionsPost?: (post: db.Post) => void; + editPost?: (post: db.Post, content: Story) => Promise; + onPressRetry: (post: db.Post) => void; + onPressDelete: (post: db.Post) => void; + isHighlighted?: boolean; +}) => ReactElement | null; + +export type RenderItemType = + | RenderItemFunction + | React.MemoExoticComponent; + +type DraftInputRendererComponent = React.ComponentType<{ + draftInputContext: DraftInputContext; +}>; + +interface PostContentRendererContextValue { + renderers: Readonly<{ [id: string]: RenderItemType }>; + inputs: Readonly<{ [id: string]: DraftInputRendererComponent }>; + + // TODO: Remove + registerRenderer: ( + id: string, + renderer: RenderItemType + ) => { unregister: () => void }; +} + +const _globalContextValue: PostContentRendererContextValue = { + renderers: {}, + inputs: {}, + registerRenderer(id, renderer) { + this.renderers[id] = renderer; + return { + unregister: () => { + delete this.renderers[id]; + }, + }; + }, +}; + +const PostContentRendererContext = + createContext(_globalContextValue); + +export function usePostContentRenderersContext() { + return useContext(PostContentRendererContext); +} + +export function PostContentRendererContextProvider({ + children, +}: { + children: React.ReactNode; +}) { + const [renderers, setRenderers] = useState<{ [id: string]: RenderItemType }>({ + 'tlon.r0.content.chat': ChatMessage, + 'tlon.r0.content.gallery': GalleryPost, + }); + const [inputs] = useState<{ [id: string]: DraftInputRendererComponent }>({ + 'tlon.r0.input.chat': ChatInput, + 'tlon.r0.input.gallery': GalleryInput, + 'tlon.r0.input.notebook': NotebookInput, + }); + + const registerRenderer = useCallback( + (id: string, renderer: RenderItemType) => { + setRenderers((prev) => ({ ...prev, [id]: renderer })); + return { + unregister: () => { + setRenderers((prev) => { + const next = { ...prev }; + delete next[id]; + return next; + }); + }, + }; + }, + [setRenderers] + ); + + const value = useMemo( + () => ({ renderers, inputs, registerRenderer }), + [renderers, inputs, registerRenderer] + ); + + return ( + + {children} + + ); +} From 1d1eace944f1f1f955fdd77cc50f7e2e08212f6d Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 10:12:56 -0700 Subject: [PATCH 122/259] Use $text() type assertion for channels.content_configuration --- packages/shared/src/db/schema.ts | 5 ++++- packages/ui/src/components/Channel/index.tsx | 13 +++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/shared/src/db/schema.ts b/packages/shared/src/db/schema.ts index f7ae7fa2a8..96244689d7 100644 --- a/packages/shared/src/db/schema.ts +++ b/packages/shared/src/db/schema.ts @@ -8,6 +8,7 @@ import { uniqueIndex, } from 'drizzle-orm/sqlite-core'; +import { ChannelContentConfiguration } from '../api'; import { ExtendedEventType, NotificationLevel, Rank } from '../urbit'; const boolean = (name: string) => { @@ -703,7 +704,9 @@ export const channels = sqliteTable( */ isDefaultWelcomeChannel: boolean('is_default_welcome_channel'), - contentConfiguration: text('content_configuration', { mode: 'json' }), + contentConfiguration: text('content_configuration', { + mode: 'json', + }).$type(), }, (table) => ({ lastPostIdIndex: index('last_post_id').on(table.lastPostId), diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index a500254084..b58eea69e9 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -9,7 +9,6 @@ import { import * as db from '@tloncorp/shared/dist/db'; import { JSONContent, Story } from '@tloncorp/shared/dist/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; -import { ChannelContentConfiguration } from 'packages/shared/dist/api'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FlatList } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; @@ -256,10 +255,6 @@ export function Channel({ ] ); - const channelContentConfiguration = channel.contentConfiguration as - | ChannelContentConfiguration - | undefined; - return ( @@ -360,7 +355,7 @@ export function Channel({ {canWrite && - (channelContentConfiguration == null ? ( + (channel.contentConfiguration == null ? ( <> {isChatChannel && !channel.isDmInvite && @@ -394,7 +389,7 @@ export function Channel({ ) : ( ))} @@ -457,9 +452,7 @@ const PostView: RenderItemType = (props) => { const { renderers } = usePostContentRenderersContext(); const SpecificPostComponent = useMemo(() => { - const contentConfig = channel.contentConfiguration as - | ChannelContentConfiguration - | undefined; + const contentConfig = channel.contentConfiguration; if (contentConfig != null) { const rendererId = contentConfig.defaultPostContentRenderers[props.post.type]; From 0fb4fbdaa5fc525bf9c7a40e70d3c3ab3fd188ef Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 10:16:01 -0700 Subject: [PATCH 123/259] Switch to singular post content renderer in config --- packages/app/hooks/useGroupContext.ts | 18 +++++++++--------- .../shared/src/api/channelContentConfig.ts | 5 +---- packages/ui/src/components/Channel/index.tsx | 5 ++--- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index d00eb56aad..ec08fa073d 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -411,25 +411,25 @@ function channelContentConfigurationForChannelType( case 'chat': return { draftInput: 'tlon.r0.input.chat', - defaultPostContentRenderers: { - chat: PostContentRendererId.create('tlon.r0.content.chat'), - }, + defaultPostContentRenderer: PostContentRendererId.create( + 'tlon.r0.content.chat' + ), defaultPostCollectionRenderer: CollectionRendererId.chat, }; case 'notebook': return { draftInput: 'tlon.r0.input.notebook', - defaultPostContentRenderers: { - block: PostContentRendererId.create('tlon.r0.content.notebook'), - }, + defaultPostContentRenderer: PostContentRendererId.create( + 'tlon.r0.content.notebook' + ), defaultPostCollectionRenderer: CollectionRendererId.notebook, }; case 'gallery': return { draftInput: 'tlon.r0.input.gallery', - defaultPostContentRenderers: { - chat: PostContentRendererId.create('tlon.r0.content.gallery'), - }, + defaultPostContentRenderer: PostContentRendererId.create( + 'tlon.r0.content.gallery' + ), defaultPostCollectionRenderer: CollectionRendererId.gallery, }; } diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index a7ca93fe30..184d296e2a 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -3,7 +3,6 @@ type PostContent = 'TODO: PostContent'; type RenderTarget = JSX.Element; type DraftInputId = string; -type PostContentType = 'block' | 'chat' | 'notice' | 'note' | 'reply'; type PostContentRendererId = Nominal; // eslint-disable-next-line @typescript-eslint/no-namespace @@ -34,9 +33,7 @@ export interface ChannelContentConfiguration { * This spec takes precedence over the client's default renderer mapping, but * does not take precedence over any mapping specified in a post's metadata. */ - defaultPostContentRenderers: Partial<{ - [Match in PostContentType]: PostContentRendererId; - }>; + defaultPostContentRenderer: PostContentRendererId; /** * How should we render the entire collection of posts? (list, grid, etc) diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index b58eea69e9..a13712228b 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -454,8 +454,7 @@ const PostView: RenderItemType = (props) => { const SpecificPostComponent = useMemo(() => { const contentConfig = channel.contentConfiguration; if (contentConfig != null) { - const rendererId = - contentConfig.defaultPostContentRenderers[props.post.type]; + const rendererId = contentConfig.defaultPostContentRenderer; if (rendererId != null && renderers[rendererId] != null) { return renderers[rendererId]; } @@ -476,7 +475,7 @@ const PostView: RenderItemType = (props) => { case 'gallery': return GalleryPost; } - }, [channel.type, channel.contentConfiguration, props.post.type, renderers]); + }, [channel.type, channel.contentConfiguration, renderers]); return ; }; From a60c08f8dfef06748be7095aa90247f4758a706d Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 10:46:25 -0700 Subject: [PATCH 124/259] Use enums for dynamic component IDs instead of strings --- packages/app/hooks/useGroupContext.ts | 19 +++++------- .../shared/src/api/channelContentConfig.ts | 30 ++++++++----------- packages/shared/src/index.ts | 5 ++++ packages/ui/src/components/Channel/index.tsx | 12 +++++--- packages/ui/src/contexts/componentsKits.tsx | 21 ++++++++----- 5 files changed, 47 insertions(+), 40 deletions(-) diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index ec08fa073d..5f383ff0a1 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -2,6 +2,7 @@ import { sync } from '@tloncorp/shared'; import { ChannelContentConfiguration, CollectionRendererId, + DraftInputId, PostContentRendererId, } from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; @@ -410,26 +411,20 @@ function channelContentConfigurationForChannelType( switch (channelType) { case 'chat': return { - draftInput: 'tlon.r0.input.chat', - defaultPostContentRenderer: PostContentRendererId.create( - 'tlon.r0.content.chat' - ), + draftInput: DraftInputId.chat, + defaultPostContentRenderer: PostContentRendererId.chat, defaultPostCollectionRenderer: CollectionRendererId.chat, }; case 'notebook': return { - draftInput: 'tlon.r0.input.notebook', - defaultPostContentRenderer: PostContentRendererId.create( - 'tlon.r0.content.notebook' - ), + draftInput: DraftInputId.notebook, + defaultPostContentRenderer: PostContentRendererId.notebook, defaultPostCollectionRenderer: CollectionRendererId.notebook, }; case 'gallery': return { - draftInput: 'tlon.r0.input.gallery', - defaultPostContentRenderer: PostContentRendererId.create( - 'tlon.r0.content.gallery' - ), + draftInput: DraftInputId.gallery, + defaultPostContentRenderer: PostContentRendererId.gallery, defaultPostCollectionRenderer: CollectionRendererId.gallery, }; } diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index 184d296e2a..10abf91206 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -2,20 +2,22 @@ type PostContent = 'TODO: PostContent'; type RenderTarget = JSX.Element; -type DraftInputId = string; -type PostContentRendererId = Nominal; +export enum CollectionRendererId { + notebook = 'tlon.r0.collection.notebook', + chat = 'tlon.r0.collection.chat', + gallery = 'tlon.r0.collection.gallery', +} -// eslint-disable-next-line @typescript-eslint/no-namespace -export namespace PostContentRendererId { - export function create(id: string): PostContentRendererId { - return id as PostContentRendererId; - } +export enum DraftInputId { + notebook = 'tlon.r0.input.notebook', + chat = 'tlon.r0.input.chat', + gallery = 'tlon.r0.input.gallery', } -export enum CollectionRendererId { - notebook = 'tlon.r0.notebook', - chat = 'tlon.r0.chat', - gallery = 'tlon.r0.gallery', +export enum PostContentRendererId { + notebook = 'tlon.r0.input.notebook', + chat = 'tlon.r0.input.chat', + gallery = 'tlon.r0.input.gallery', } /** @@ -79,9 +81,3 @@ export namespace StructuredChannelDescriptionPayload { } } } - -// -------- Helpers below here -------- // - -type _NominalTag = { __nominalTag: Tag }; - -type Nominal = BaseType & _NominalTag; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index b8dea04d3b..d22fa72a34 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -17,6 +17,11 @@ export { layoutForType, layoutTypeFromChannel, } from './types/PostCollectionConfiguration'; +export { + CollectionRendererId, + DraftInputId, + PostContentRendererId, +} from './api/channelContentConfig'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; export * from './store'; diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index a13712228b..06c4125602 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -1,4 +1,8 @@ -import { layoutForType, layoutTypeFromChannel } from '@tloncorp/shared'; +import { + DraftInputId, + layoutForType, + layoutTypeFromChannel, +} from '@tloncorp/shared'; import { isChatChannel as getIsChatChannel, useChannel as useChannelFromStore, @@ -362,7 +366,7 @@ export function Channel({ (negotiationMatch ? ( ) : ( )} {channel.type === 'notebook' && ( )} diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index f74756330c..0a556eb8df 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -1,3 +1,4 @@ +import { DraftInputId, PostContentRendererId } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import { Story } from '@tloncorp/shared/dist/urbit'; import { @@ -11,6 +12,7 @@ import { import { ChatMessage } from '../components/ChatMessage'; import { GalleryPost } from '../components/GalleryPost'; +import { NotebookPost } from '../components/NotebookPost'; import { ChatInput, DraftInputContext, @@ -44,8 +46,12 @@ type DraftInputRendererComponent = React.ComponentType<{ }>; interface PostContentRendererContextValue { - renderers: Readonly<{ [id: string]: RenderItemType }>; - inputs: Readonly<{ [id: string]: DraftInputRendererComponent }>; + renderers: Readonly< + Partial<{ [Id in PostContentRendererId]: RenderItemType }> + >; + inputs: Readonly< + Partial<{ [Id in DraftInputId]: DraftInputRendererComponent }> + >; // TODO: Remove registerRenderer: ( @@ -80,13 +86,14 @@ export function PostContentRendererContextProvider({ children: React.ReactNode; }) { const [renderers, setRenderers] = useState<{ [id: string]: RenderItemType }>({ - 'tlon.r0.content.chat': ChatMessage, - 'tlon.r0.content.gallery': GalleryPost, + [PostContentRendererId.chat]: ChatMessage, + [PostContentRendererId.gallery]: GalleryPost, + [PostContentRendererId.notebook]: NotebookPost, }); const [inputs] = useState<{ [id: string]: DraftInputRendererComponent }>({ - 'tlon.r0.input.chat': ChatInput, - 'tlon.r0.input.gallery': GalleryInput, - 'tlon.r0.input.notebook': NotebookInput, + [DraftInputId.chat]: ChatInput, + [DraftInputId.gallery]: GalleryInput, + [DraftInputId.notebook]: NotebookInput, }); const registerRenderer = useCallback( From ba58377b04b5c590530fdb71c886431ee31f8d0b Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 10:46:45 -0700 Subject: [PATCH 125/259] Pull collection config from content config when available --- .../src/types/PostCollectionConfiguration.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 8054151368..e779406513 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -1,3 +1,4 @@ +import { CollectionRendererId } from '../api'; import * as db from '../db'; import * as ChannelAction from './ChannelActions'; @@ -21,6 +22,25 @@ export function layoutTypeFromChannel( export function layoutTypeFromChannel( channel: db.Channel | null ): PostCollectionLayoutType | null { + const configCollectionRendererId = + channel?.contentConfiguration?.defaultPostCollectionRenderer; + if (configCollectionRendererId != null) { + switch (configCollectionRendererId) { + case CollectionRendererId.notebook: + return 'comfy-list-top-to-bottom'; + + case CollectionRendererId.chat: + return 'compact-list-bottom-to-top'; + + case CollectionRendererId.gallery: + return 'grid'; + + default: + // fallthrough to legacy logic + break; + } + } + switch (channel?.type) { case null: // fallthrough From 1f94da7cceca2059e768969758790244790d86b2 Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 10:55:19 -0700 Subject: [PATCH 126/259] Rename PostContentRendererContext -> ComponentsKitContext --- packages/ui/src/components/Channel/index.tsx | 32 ++++++++++++-------- packages/ui/src/contexts/componentsKits.tsx | 18 +++++------ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 06c4125602..562fa80de7 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -27,9 +27,9 @@ import { } from '../../contexts'; import { Attachment, AttachmentProvider } from '../../contexts/attachment'; import { - PostContentRendererContextProvider, + ComponentsKitContextProvider, RenderItemType, - usePostContentRenderersContext, + useComponentsKitContext, } from '../../contexts/componentsKits'; import { RequestsProvider } from '../../contexts/requests'; import { ScrollContextProvider } from '../../contexts/scroll'; @@ -263,7 +263,7 @@ export function Channel({ - + - + @@ -453,15 +453,23 @@ function NegotionMismatchNotice() { const PostView: RenderItemType = (props) => { const channel = useChannelContext(); - const { renderers } = usePostContentRenderersContext(); + const { renderers } = useComponentsKitContext(); const SpecificPostComponent = useMemo(() => { - const contentConfig = channel.contentConfiguration; - if (contentConfig != null) { - const rendererId = contentConfig.defaultPostContentRenderer; - if (rendererId != null && renderers[rendererId] != null) { - return renderers[rendererId]; + // why do this iife? + // without it, TypeScript thinks the value from `renderers[]` may be null. + // sad! + const rendererFromContentConfig = (() => { + const contentConfig = channel.contentConfiguration; + if ( + contentConfig != null && + renderers[contentConfig.defaultPostContentRenderer] != null + ) { + return renderers[contentConfig.defaultPostContentRenderer]; } + })(); + if (rendererFromContentConfig != null) { + return rendererFromContentConfig; } // content config did not provide a renderer, fall back to default @@ -486,9 +494,9 @@ const PostView: RenderItemType = (props) => { function DraftInputView(props: { draftInputContext: DraftInputContext; - type: string; + type: DraftInputId; }) { - const { inputs } = usePostContentRenderersContext(); + const { inputs } = useComponentsKitContext(); const InputComponent = inputs[props.type]; if (InputComponent) { return ; diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index 0a556eb8df..86833baf3f 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -45,7 +45,7 @@ type DraftInputRendererComponent = React.ComponentType<{ draftInputContext: DraftInputContext; }>; -interface PostContentRendererContextValue { +interface ComponentsKitContextValue { renderers: Readonly< Partial<{ [Id in PostContentRendererId]: RenderItemType }> >; @@ -60,7 +60,7 @@ interface PostContentRendererContextValue { ) => { unregister: () => void }; } -const _globalContextValue: PostContentRendererContextValue = { +const _globalContextValue: ComponentsKitContextValue = { renderers: {}, inputs: {}, registerRenderer(id, renderer) { @@ -73,14 +73,14 @@ const _globalContextValue: PostContentRendererContextValue = { }, }; -const PostContentRendererContext = - createContext(_globalContextValue); +const ComponentsKitContext = + createContext(_globalContextValue); -export function usePostContentRenderersContext() { - return useContext(PostContentRendererContext); +export function useComponentsKitContext() { + return useContext(ComponentsKitContext); } -export function PostContentRendererContextProvider({ +export function ComponentsKitContextProvider({ children, }: { children: React.ReactNode; @@ -118,8 +118,8 @@ export function PostContentRendererContextProvider({ ); return ( - + {children} - + ); } From cf4d74ef59d803664b7f674bb8fcf1e5d060edf8 Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 11:22:43 -0700 Subject: [PATCH 127/259] Pull group ctx createChannel into `shared` --- packages/app/hooks/useGroupContext.ts | 75 ++-------------- packages/shared/src/logic/index.ts | 1 + packages/shared/src/logic/useCreateChannel.ts | 88 +++++++++++++++++++ 3 files changed, 94 insertions(+), 70 deletions(-) create mode 100644 packages/shared/src/logic/useCreateChannel.ts diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index 5f383ff0a1..5119ea923f 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -1,12 +1,5 @@ -import { sync } from '@tloncorp/shared'; -import { - ChannelContentConfiguration, - CollectionRendererId, - DraftInputId, - PostContentRendererId, -} from '@tloncorp/shared/dist/api'; +import { sync, useCreateChannel } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; -import { assembleNewChannelIdAndName } from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import { useCallback, useEffect, useMemo } from 'react'; @@ -106,43 +99,12 @@ export const useGroupContext = ({ } }, [group]); - const { data: existingChannels } = store.useAllChannels({ - enabled: isFocused, + const createChannel = useCreateChannel({ + group, + currentUserId, + disabled: !isFocused, }); - const createChannel = useCallback( - async ({ - title, - description, - channelType, - }: { - title: string; - description?: string; - channelType: Omit; - }) => { - const { name, id } = assembleNewChannelIdAndName({ - title, - channelType, - existingChannels: existingChannels ?? [], - currentUserId, - }); - - if (group) { - await store.createChannel({ - groupId: group.id, - name, - channelId: id, - title, - description, - channelType, - contentConfiguration: - channelContentConfigurationForChannelType(channelType), - }); - } - }, - [group, currentUserId, existingChannels] - ); - const deleteChannel = useCallback( async (channelId: string) => { if (group) { @@ -404,30 +366,3 @@ export const useGroupContext = ({ groupPrivacyType, }; }; - -function channelContentConfigurationForChannelType( - channelType: Omit -): ChannelContentConfiguration { - switch (channelType) { - case 'chat': - return { - draftInput: DraftInputId.chat, - defaultPostContentRenderer: PostContentRendererId.chat, - defaultPostCollectionRenderer: CollectionRendererId.chat, - }; - case 'notebook': - return { - draftInput: DraftInputId.notebook, - defaultPostContentRenderer: PostContentRendererId.notebook, - defaultPostCollectionRenderer: CollectionRendererId.notebook, - }; - case 'gallery': - return { - draftInput: DraftInputId.gallery, - defaultPostContentRenderer: PostContentRendererId.gallery, - defaultPostCollectionRenderer: CollectionRendererId.gallery, - }; - } - - throw new Error('Unknown channel type'); -} diff --git a/packages/shared/src/logic/index.ts b/packages/shared/src/logic/index.ts index e460101969..de3bcacf46 100644 --- a/packages/shared/src/logic/index.ts +++ b/packages/shared/src/logic/index.ts @@ -7,3 +7,4 @@ export * from './activity'; export * from './branch'; export * from './deeplinks'; export * from './analytics'; +export * from './useCreateChannel'; diff --git a/packages/shared/src/logic/useCreateChannel.ts b/packages/shared/src/logic/useCreateChannel.ts new file mode 100644 index 0000000000..e8d2a09133 --- /dev/null +++ b/packages/shared/src/logic/useCreateChannel.ts @@ -0,0 +1,88 @@ +import { useCallback } from 'react'; + +import { + ChannelContentConfiguration, + CollectionRendererId, + DraftInputId, + PostContentRendererId, +} from '../api/channelContentConfig'; +import * as db from '../db'; +import * as store from '../store'; + +export function useCreateChannel({ + group, + currentUserId, + disabled = false, +}: { + group?: db.Group | null; + currentUserId: string; + disabled?: boolean; +}) { + const { data: existingChannels } = store.useAllChannels({ + enabled: !disabled, + }); + + return useCallback( + async ({ + title, + description, + channelType, + }: { + title: string; + description?: string; + channelType: Omit; + }) => { + const { name, id } = db.assembleNewChannelIdAndName({ + title, + channelType, + existingChannels: existingChannels ?? [], + currentUserId, + }); + + if (group) { + await store.createChannel({ + groupId: group.id, + name, + channelId: id, + title, + description, + channelType: channelType === 'custom' ? 'chat' : channelType, + contentConfiguration: + channelType === 'custom' + ? (() => { + throw new Error('Not implemented'); + })() + : channelContentConfigurationForChannelType(channelType), + }); + } + }, + [group, currentUserId, existingChannels] + ); +} + +function channelContentConfigurationForChannelType( + channelType: Omit +): ChannelContentConfiguration { + switch (channelType) { + case 'chat': + return { + draftInput: DraftInputId.chat, + defaultPostContentRenderer: PostContentRendererId.chat, + defaultPostCollectionRenderer: CollectionRendererId.chat, + }; + case 'notebook': + return { + draftInput: DraftInputId.notebook, + defaultPostContentRenderer: PostContentRendererId.notebook, + defaultPostCollectionRenderer: CollectionRendererId.notebook, + }; + case 'gallery': + return { + draftInput: DraftInputId.gallery, + defaultPostContentRenderer: PostContentRendererId.gallery, + defaultPostCollectionRenderer: CollectionRendererId.gallery, + }; + } + + throw new Error('Unknown channel type'); +} From e57a016ec32532c5fdaa1d2fe89af6257248b6cb Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 11:31:49 -0700 Subject: [PATCH 128/259] Stop plumbing createChannel all the way down; use hook instead --- .../CreateChannelSheet.fixture.tsx | 6 ++--- .../features/groups/ManageChannelsScreen.tsx | 4 +-- .../app/features/top/GroupChannelsScreen.tsx | 7 +---- .../components/GroupChannelsScreenView.tsx | 26 +++---------------- .../ManageChannels/CreateChannelSheet.tsx | 20 +++++++------- .../ManageChannelsScreenView.tsx | 24 ++++------------- 6 files changed, 24 insertions(+), 63 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx b/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx index 23ad98df53..888b4ee23e 100644 --- a/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx @@ -1,5 +1,5 @@ import { CreateChannelSheet } from '@tloncorp/ui/src/components/ManageChannels/CreateChannelSheet'; -export default ( - {}} createChannel={() => {}} /> -); +import { group } from '../fakeData'; + +export default {}} />; diff --git a/packages/app/features/groups/ManageChannelsScreen.tsx b/packages/app/features/groups/ManageChannelsScreen.tsx index 2df7c7ee1e..ff8e7e6969 100644 --- a/packages/app/features/groups/ManageChannelsScreen.tsx +++ b/packages/app/features/groups/ManageChannelsScreen.tsx @@ -13,11 +13,11 @@ export function ManageChannelsScreen(props: Props) { const { groupId } = props.route.params; const { + group, groupNavSectionsWithChannels, moveNavSection, moveChannel, moveChannelToNavSection, - createChannel, createNavSection, deleteNavSection, updateNavSection, @@ -29,11 +29,11 @@ export function ManageChannelsScreen(props: Props) { goToEditChannel={(channelId) => { props.navigation.navigate('EditChannel', { groupId, channelId }); }} + group={group} groupNavSectionsWithChannels={groupNavSectionsWithChannels} moveNavSection={moveNavSection} moveChannelWithinNavSection={moveChannel} moveChannelToNavSection={moveChannelToNavSection} - createChannel={createChannel} createNavSection={createNavSection} deleteNavSection={deleteNavSection} updateNavSection={updateNavSection} diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index d96bcaf440..1371d4bc0e 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -10,7 +10,6 @@ import { import { useCallback, useMemo, useState } from 'react'; import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation'; -import { useCurrentUserId } from '../../hooks/useCurrentUser'; import { useGroupContext } from '../../hooks/useGroupContext'; import type { RootStackParamList } from '../../navigation/types'; @@ -18,9 +17,7 @@ type Props = NativeStackScreenProps; export function GroupChannelsScreen({ navigation, route }: Props) { const groupParam = route.params.group; - const { id } = route.params.group; - const currentUser = useCurrentUserId(); const isFocused = useIsFocused(); const { data: pins } = store.usePins({ enabled: isFocused, @@ -28,7 +25,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { const [inviteSheetGroup, setInviteSheetGroup] = useState( null ); - const { group, createChannel } = useGroupContext({ groupId: id, isFocused }); + const { group } = useGroupContext({ groupId: groupParam.id, isFocused }); const pinnedItems = useMemo(() => { return pins ?? []; @@ -60,8 +57,6 @@ export function GroupChannelsScreen({ navigation, route }: Props) { void; onBackPressed: () => void; - currentUser: string; - createChannel: ({ - title, - description, - channelType, - }: { - title: string; - description?: string; - channelType: ChannelTypeName; - }) => Promise; }; export function GroupChannelsScreenView({ group, onChannelPressed, onBackPressed, - createChannel, }: GroupChannelsScreenViewProps) { const chatOptionsSheetRef = useRef(null); const [showCreateChannel, setShowCreateChannel] = useState(false); @@ -127,16 +113,10 @@ export function GroupChannelsScreenView({ )} - {showCreateChannel && ( + {showCreateChannel && group && ( setShowCreateChannel(open)} - createChannel={async ({ title, description, channelType }) => - createChannel({ - title, - description, - channelType, - }) - } + group={group} /> )} diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index eeddcd7198..337ec84e11 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -1,6 +1,9 @@ +import { useCreateChannel } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/dist/db'; import { useCallback } from 'react'; import { useForm } from 'react-hook-form'; +import { useCurrentUserId } from '../../contexts'; import { ActionSheet } from '../ActionSheet'; import { Button } from '../Button'; import * as Form from '../Form'; @@ -30,18 +33,10 @@ const channelTypes: Form.ListItemInputOption[] = [ export function CreateChannelSheet({ onOpenChange, - createChannel, + group, }: { onOpenChange: (open: boolean) => void; - createChannel: ({ - title, - description, - channelType, - }: { - title: string; - description?: string; - channelType: ChannelTypeName; - }) => void; + group: db.Group; }) { const { control, handleSubmit } = useForm({ defaultValues: { @@ -50,6 +45,11 @@ export function CreateChannelSheet({ }, }); + const currentUserId = useCurrentUserId(); + const createChannel = useCreateChannel({ + group, + currentUserId, + }); const handlePressSave = useCallback( async (data: { title: string; channelType: string }) => { createChannel({ diff --git a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx index edc137d5ef..94447dab15 100644 --- a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx +++ b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx @@ -11,7 +11,7 @@ import { DraggableItem } from '../DraggableItem'; import { Icon } from '../Icon'; import Pressable from '../Pressable'; import { ScreenHeader } from '../ScreenHeader'; -import { ChannelTypeName, CreateChannelSheet } from './CreateChannelSheet'; +import { CreateChannelSheet } from './CreateChannelSheet'; import { EditSectionNameSheet } from './EditSectionNameSheet'; export type Section = { @@ -178,6 +178,7 @@ interface ManageChannelsScreenViewProps { goBack: () => void; goToEditChannel: (channelId: string) => void; groupNavSectionsWithChannels: GroupNavSectionWithChannels[]; + group: db.Group | null; moveNavSection: (navSectionId: string, newIndex: number) => Promise; moveChannelWithinNavSection: ( channelId: string, @@ -188,28 +189,19 @@ interface ManageChannelsScreenViewProps { channelId: string, navSectionId: string ) => Promise; - createChannel: ({ - title, - description, - channelType, - }: { - title: string; - description?: string; - channelType: ChannelTypeName; - }) => Promise; createNavSection: ({ title }: { title: string }) => Promise; deleteNavSection: (navSectionId: string) => Promise; updateNavSection: (navSection: db.GroupNavSection) => Promise; } export function ManageChannelsScreenView({ + group, groupNavSectionsWithChannels, goBack, goToEditChannel, moveNavSection, moveChannelWithinNavSection, moveChannelToNavSection, - createChannel, createNavSection, deleteNavSection, updateNavSection, @@ -562,16 +554,10 @@ export function ManageChannelsScreenView({ - {showCreateChannel && ( + {showCreateChannel && group && ( setShowCreateChannel(open)} - createChannel={async ({ title, description, channelType }) => - createChannel({ - title, - description, - channelType, - }) - } /> )} Date: Thu, 10 Oct 2024 17:47:40 -0700 Subject: [PATCH 129/259] Reduce import cycles --- packages/shared/src/api/index.ts | 1 - packages/shared/src/logic/useCreateChannel.ts | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/api/index.ts b/packages/shared/src/api/index.ts index 7065b2c729..9e51f0b88e 100644 --- a/packages/shared/src/api/index.ts +++ b/packages/shared/src/api/index.ts @@ -2,7 +2,6 @@ export * from './channelContentConfig'; export * from './channelsApi'; export * from './chatApi'; export * from './contactsApi'; -export * from './contactsApi'; export * from './groupsApi'; export * from './landscapeApi'; export * from './postsApi'; diff --git a/packages/shared/src/logic/useCreateChannel.ts b/packages/shared/src/logic/useCreateChannel.ts index e8d2a09133..b0801b857e 100644 --- a/packages/shared/src/logic/useCreateChannel.ts +++ b/packages/shared/src/logic/useCreateChannel.ts @@ -6,8 +6,10 @@ import { DraftInputId, PostContentRendererId, } from '../api/channelContentConfig'; -import * as db from '../db'; -import * as store from '../store'; +import { assembleNewChannelIdAndName } from '../db/modelBuilders'; +import * as db from '../db/types'; +import { createChannel } from '../store/channelActions'; +import { useAllChannels } from '../store/dbHooks'; export function useCreateChannel({ group, @@ -18,7 +20,7 @@ export function useCreateChannel({ currentUserId: string; disabled?: boolean; }) { - const { data: existingChannels } = store.useAllChannels({ + const { data: existingChannels } = useAllChannels({ enabled: !disabled, }); @@ -32,7 +34,7 @@ export function useCreateChannel({ description?: string; channelType: Omit; }) => { - const { name, id } = db.assembleNewChannelIdAndName({ + const { name, id } = assembleNewChannelIdAndName({ title, channelType, existingChannels: existingChannels ?? [], @@ -40,7 +42,7 @@ export function useCreateChannel({ }); if (group) { - await store.createChannel({ + await createChannel({ groupId: group.id, name, channelId: id, From dc7e0f2568754330c5a9425ebc52f1d67743b3f1 Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 10 Oct 2024 17:48:23 -0700 Subject: [PATCH 130/259] Export ChannelContentConfiguration from @tloncorp/shared main entry --- packages/shared/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index d22fa72a34..0cefbc2504 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -21,6 +21,7 @@ export { CollectionRendererId, DraftInputId, PostContentRendererId, + ChannelContentConfiguration, } from './api/channelContentConfig'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; From 65f570418eb811f03da57f22be67869cdda29cb2 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 11 Oct 2024 11:37:43 -0700 Subject: [PATCH 131/259] Pull in drawing input / content components --- apps/tlon-mobile/ios/Podfile.lock | 12 +- apps/tlon-mobile/package.json | 1 + .../shared/src/api/channelContentConfig.ts | 8 +- packages/ui/package.json | 1 + .../src/components/Channel/PictoMessage.tsx | 65 + packages/ui/src/components/DrawingInput.tsx | 395 ++++++ packages/ui/src/contexts/componentsKits.tsx | 4 + pnpm-lock.yaml | 1165 +++++++++++++++-- 8 files changed, 1562 insertions(+), 89 deletions(-) create mode 100644 packages/ui/src/components/Channel/PictoMessage.tsx create mode 100644 packages/ui/src/components/DrawingInput.tsx diff --git a/apps/tlon-mobile/ios/Podfile.lock b/apps/tlon-mobile/ios/Podfile.lock index 57a709f540..3acf3c9558 100644 --- a/apps/tlon-mobile/ios/Podfile.lock +++ b/apps/tlon-mobile/ios/Podfile.lock @@ -1161,6 +1161,12 @@ PODS: - React-Core - react-native-safe-area-context (4.9.0): - React-Core + - react-native-skia (1.4.2): + - glog + - RCT-Folly (= 2022.05.16.00) + - React + - React-callinvoker + - React-Core - react-native-webview (13.6.4): - glog - RCT-Folly (= 2022.05.16.00) @@ -1465,6 +1471,7 @@ DEPENDENCIES: - react-native-get-random-values (from `../../../node_modules/react-native-get-random-values`) - "react-native-netinfo (from `../../../node_modules/@react-native-community/netinfo`)" - react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`) + - "react-native-skia (from `../../../node_modules/@shopify/react-native-skia`)" - react-native-webview (from `../../../node_modules/react-native-webview`) - React-nativeconfig (from `../../../node_modules/react-native/ReactCommon`) - React-NativeModulesApple (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) @@ -1672,6 +1679,8 @@ EXTERNAL SOURCES: :path: "../../../node_modules/@react-native-community/netinfo" react-native-safe-area-context: :path: "../../../node_modules/react-native-safe-area-context" + react-native-skia: + :path: "../../../node_modules/@shopify/react-native-skia" react-native-webview: :path: "../../../node_modules/react-native-webview" React-nativeconfig: @@ -1837,6 +1846,7 @@ SPEC CHECKSUMS: react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06 react-native-netinfo: 3aa5637c18834966e0c932de8ae1ae56fea20a97 react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b + react-native-skia: c7d8d8a380d4dbf8463343e2738bceaf49a9c084 react-native-webview: ad868affda04ff2b204de83546193bc0325a8280 React-nativeconfig: 44cd3076b158c39cb6758f238cd3e65953e989c0 React-NativeModulesApple: af58ca346cf42c3bb4dab9173b6edd0c83c2a21c @@ -1880,7 +1890,7 @@ SPEC CHECKSUMS: sqlite3: f163dbbb7aa3339ad8fc622782c2d9d7b72f7e9c tentap: 4871503ab3d587fe80fe13f6fe712fde98b57525 UMAppLoader: 5df85360d65cabaef544be5424ac64672e648482 - Yoga: fb61b2337c7688c81a137e5560b3cbb515289f91 + Yoga: 4dbfeceb9bb0f62899d0a53d37a1ddd58898d3f2 PODFILE CHECKSUM: 0cb7a78e5777e69c86c1bf4bb5135fd660376dbe diff --git a/apps/tlon-mobile/package.json b/apps/tlon-mobile/package.json index 9a8e3707a2..aa17fc9b10 100644 --- a/apps/tlon-mobile/package.json +++ b/apps/tlon-mobile/package.json @@ -56,6 +56,7 @@ "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", "@shopify/flash-list": "1.6.3", + "@shopify/react-native-skia": "^1.3.9", "@tanstack/react-query": "~5.32.1", "@tloncorp/app": "workspace:*", "@tloncorp/editor": "workspace:*", diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index 10abf91206..bd624c3104 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -12,12 +12,14 @@ export enum DraftInputId { notebook = 'tlon.r0.input.notebook', chat = 'tlon.r0.input.chat', gallery = 'tlon.r0.input.gallery', + picto = 'tlon.r0.input.picto', } export enum PostContentRendererId { - notebook = 'tlon.r0.input.notebook', - chat = 'tlon.r0.input.chat', - gallery = 'tlon.r0.input.gallery', + notebook = 'tlon.r0.content.notebook', + chat = 'tlon.r0.content.chat', + gallery = 'tlon.r0.content.gallery', + picto = 'tlon.r0.content.picto', } /** diff --git a/packages/ui/package.json b/packages/ui/package.json index d04420478e..c16fdf7c20 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -53,6 +53,7 @@ }, "peerDependencies": { "@10play/tentap-editor": "~0.5.11", + "@shopify/react-native-skia": "^1.3.9", "@urbit/sigil-js": "^2.2.0", "expo-image": "*", "react": "*", diff --git a/packages/ui/src/components/Channel/PictoMessage.tsx b/packages/ui/src/components/Channel/PictoMessage.tsx new file mode 100644 index 0000000000..e7c4068d7f --- /dev/null +++ b/packages/ui/src/components/Channel/PictoMessage.tsx @@ -0,0 +1,65 @@ +import { extractContentTypesFromPost } from '@tloncorp/shared/dist'; +import * as db from '@tloncorp/shared/dist/db'; +import * as ub from '@tloncorp/shared/dist/urbit'; +import { Story } from '@tloncorp/shared/dist/urbit'; +import { useMemo } from 'react'; +import { Image, View, XStack } from 'tamagui'; + +import { useContact } from '../../contexts'; +import { ContactAvatar } from '../Avatar'; +import ContactName from '../ContactName'; + +export function PictoMessage({ + post, +}: { + post: db.Post; + showAuthor?: boolean; + showReplies?: boolean; + onPress?: (post: db.Post) => void; + onPressReplies?: (post: db.Post) => void; + onPressImage?: (post: db.Post, imageUri?: string) => void; + onLongPress?: (post: db.Post) => void; + editing?: boolean; + setEditingPost?: (post: db.Post | undefined) => void; + editPost?: (post: db.Post, content: Story) => Promise; + onPressRetry: (post: db.Post) => void; + onPressDelete: (post: db.Post) => void; +}) { + const image = useMemo(() => { + const content = extractContentTypesFromPost(post); + return content.blocks.find((b): b is ub.Image => 'image' in b); + }, [post]); + const postContact = useContact(post.authorId); + + if (!image) return null; + return ( + + + + + + + + + + ); +} diff --git a/packages/ui/src/components/DrawingInput.tsx b/packages/ui/src/components/DrawingInput.tsx new file mode 100644 index 0000000000..044f296913 --- /dev/null +++ b/packages/ui/src/components/DrawingInput.tsx @@ -0,0 +1,395 @@ +import * as sk from '@shopify/react-native-skia'; +import { Skia } from '@shopify/react-native-skia'; +import * as db from '@tloncorp/shared/dist/db'; +import { Story } from '@tloncorp/shared/dist/urbit'; +import * as FileSystem from 'expo-file-system'; +import { + ComponentProps, + useCallback, + useEffect, + useRef, + useState, +} from 'react'; +import { Gesture, GestureDetector } from 'react-native-gesture-handler'; +import { + interpolate, + useDerivedValue, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { styled } from 'tamagui'; +import { View, XStack, YStack } from 'tamagui'; + +import { UploadedImageAttachment, useAttachmentContext } from '../contexts'; +import { ActionSheet } from './ActionSheet'; +import { Button } from './Button'; +import { Icon } from './Icon'; +import { Sheet } from './Sheet'; +import { DraftInputContext } from './draftInputs'; + +const pixelated = Skia.RuntimeEffect.Make(` + uniform vec2 amount; // number of pixels per axis + uniform vec2 resolution; + uniform shader image; + + half4 main(vec2 uv) { + vec2 blockSize = resolution / amount; + vec2 coord = floor((floor(uv / blockSize) + 0.5) * blockSize); + return floor(image.eval(coord) + .25); + }`)!; + +const rec = Skia.PictureRecorder(); +rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1)); +const emptyPicture = rec.finishRecordingAsPicture(); + +const drawPaint = Skia.Paint(); +drawPaint.setColor(Skia.Color(0xff000000)); +drawPaint.setAntiAlias(false); +drawPaint.setStrokeWidth(10); +drawPaint.setStyle(sk.PaintStyle.Stroke); +drawPaint.setStrokeCap(sk.StrokeCap.Round); +drawPaint.setStrokeJoin(sk.StrokeJoin.Round); + +const erasePaint = Skia.Paint(); +erasePaint.setColor(Skia.Color(0xffffffff)); +erasePaint.setAntiAlias(false); +erasePaint.setStrokeWidth(10); +erasePaint.setStyle(sk.PaintStyle.Stroke); + +const renderPath = ( + path: sk.SkPath, + paint: sk.SkPaint, + lastPicture?: sk.SkPicture +) => { + 'worklet'; + const recorder = Skia.PictureRecorder(); + const canvas = recorder.beginRecording( + Skia.XYWHRect(0, 0, 2_000_000, 2_000_000) + ); + if (lastPicture) { + canvas.drawPicture(lastPicture); + } + canvas.drawPath(path, paint); + return recorder.finishRecordingAsPicture(); +}; + +const brushSizes = [4, 10]; + +export const DrawingInput = ({ + filter, + onPressAttach, + inputAspect, + finishedAction = 'attach', +}: { + filter?: 'pixel'; + onPressAttach: () => void; + inputAspect?: number; + finishedAction: 'attach' | 'send'; +}) => { + const currentPath = useSharedValue(Skia.Path.Make()); + const isDrawing = useSharedValue(false); + const pointerPosition = useSharedValue({ x: 0, y: 0 }); + const picture = useSharedValue(emptyPicture); + const canvasRef = useRef(null); + + const [tool, setTool] = useState<'draw' | 'erase'>('draw'); + const [size, setSize] = useState<'small' | 'large'>('small'); + const paintRef = useSharedValue(drawPaint); + const canvasSize = useSharedValue({ width: 0, height: 0 }); + const pan = Gesture.Pan() + .averageTouches(true) + .minDistance(0) + .shouldCancelWhenOutside(false) + .maxPointers(1) + .onBegin((e) => { + currentPath.value.reset(); + currentPath.value.moveTo(e.x, e.y); + console.log('begin'); + isDrawing.value = true; + pointerPosition.value = { x: e.x, y: e.y }; + }) + .onChange((e) => { + pointerPosition.value = { + x: interpolate(0.4, [0, 1], [pointerPosition.value.x, e.x]), + y: interpolate(0.4, [0, 1], [pointerPosition.value.y, e.y]), + }; + currentPath.value.lineTo( + pointerPosition.value.x, + pointerPosition.value.y + ); + sk.notifyChange(currentPath); + pointerPosition.value = { x: e.x, y: e.y }; + }) + .onEnd(() => { + console.log('end', tool); + picture.value = renderPath( + currentPath.value, + paintRef.value, + picture.value + ); + currentPath.value.reset(); + sk.notifyChange(currentPath); + isDrawing.value = false; + }); + + const [w, h] = [142, 256]; + const scale = 3; + const uniforms = { + amount: [w / scale, h / scale], // grid 20x20; + resolution: [142, 256], + }; + + useEffect(() => { + if (size === 'small') { + paintRef.value.setStrokeWidth(brushSizes[0]); + } else { + paintRef.value.setStrokeWidth(brushSizes[1]); + } + if (tool === 'draw') { + paintRef.value.setColor(Skia.Color(0xff000000)); + } else { + paintRef.value.setColor(Skia.Color(0xffffffff)); + } + sk.notifyChange(paintRef); + }, [tool, size, paintRef]); + + const handlePressErase = useCallback(() => { + setTool(`erase`); + }, []); + + const handlePressDraw = useCallback(() => { + setTool(`draw`); + }, []); + + const handlePressSizeLarge = useCallback(() => { + setSize(`large`); + }, []); + + const handlePressSizeSmall = useCallback(() => { + setSize('small'); + }, []); + + const handlePressClear = useCallback(() => { + picture.value = emptyPicture; + }, [picture]); + + const [isAttaching, setIsAttaching] = useState(false); + const { attachAssets, attachments } = useAttachmentContext(); + const translateY = useSharedValue(0); + const transform = useDerivedValue(() => { + return [{ translateY: translateY.value }]; + }, [translateY]); + + const handlePressAttach = useCallback(async () => { + const result = await canvasRef.current?.makeImageSnapshotAsync(); + const str = result?.encodeToBase64(); + const uri = FileSystem.cacheDirectory + `drawing-${Date.now()}.png`; + await FileSystem.writeAsStringAsync(uri, str ?? '', { + encoding: 'base64', + }); + attachAssets([ + { + type: 'image', + uri, + width: Math.round(canvasSize.value.width), + height: Math.round(canvasSize.value.height), + }, + ]); + setIsAttaching(true); + }, [attachAssets, canvasSize]); + + useEffect(() => { + if (attachments.length && isAttaching) { + setIsAttaching(false); + translateY.value = withTiming( + -canvasSize.value.height, + { duration: 300 }, + () => { + picture.value = emptyPicture; + translateY.value = 0; + } + ); + onPressAttach(); + } + }, [ + attachments, + handlePressClear, + isAttaching, + onPressAttach, + canvasSize, + picture, + translateY, + ]); + + return ( + + + + + + + + ) : undefined + } + > + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const IconGroup = styled(XStack, { + borderColor: '$border', + borderWidth: 1, + alignItems: 'center', + borderRadius: '$s', + overflow: 'hidden', +}); + +const ToolbarIcon = styled(Icon, { + width: '$3xl', + height: '$3xl', + color: '$tertiaryText', + variants: { + isSelected: { + true: { + color: '$primaryText', + borderColor: '$activeBorder', + backgroundColor: '$secondaryBackground', + }, + }, + } as const, +}); + +export function StandaloneDrawingInput({ + draftInputContext: { + channel, + send: onSend + }, +}: { + draftInputContext: DraftInputContext; +}) { + const { waitForAttachmentUploads, clearAttachments } = useAttachmentContext(); + const handleDrawingAttached = useCallback(async () => { + const finalAttachments = await waitForAttachmentUploads(); + const imageAttachment = finalAttachments.find( + (f): f is UploadedImageAttachment => f.type === 'image' + ); + clearAttachments(); + if (imageAttachment) { + await onSend?.( + [ + { + block: { + image: { + src: imageAttachment.uploadState.remoteUri, + width: imageAttachment.file.width, + height: imageAttachment.file.height, + alt: '', + }, + }, + }, + ], + channel.id + ); + } else { + throw new Error('no image'); + } + }, [clearAttachments, channel.id, onSend, waitForAttachmentUploads]); + + const { bottom } = useSafeAreaInsets(); + + return ( + + + + ); +} + +export function SheetDrawingInput({ + onFinished, + ...props +}: ComponentProps & { + onFinished: () => void; +}) { + return ( + + + + + + ); +} diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index 86833baf3f..bf268df573 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -10,7 +10,9 @@ import { useState, } from 'react'; +import { PictoMessage } from '../components/Channel/PictoMessage'; import { ChatMessage } from '../components/ChatMessage'; +import { StandaloneDrawingInput } from '../components/DrawingInput'; import { GalleryPost } from '../components/GalleryPost'; import { NotebookPost } from '../components/NotebookPost'; import { @@ -89,11 +91,13 @@ export function ComponentsKitContextProvider({ [PostContentRendererId.chat]: ChatMessage, [PostContentRendererId.gallery]: GalleryPost, [PostContentRendererId.notebook]: NotebookPost, + [PostContentRendererId.picto]: PictoMessage, }); const [inputs] = useState<{ [id: string]: DraftInputRendererComponent }>({ [DraftInputId.chat]: ChatInput, [DraftInputId.gallery]: GalleryInput, [DraftInputId.notebook]: NotebookInput, + [DraftInputId.picto]: StandaloneDrawingInput, }); const registerRenderer = useCallback( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 478ed1bd5d..6beaf93438 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,7 +92,7 @@ importers: version: 8.0.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(postcss@8.4.35)(typescript@5.4.5) vitest: specifier: ^1.2.2 - version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) apps/tlon-mobile: dependencies: @@ -153,6 +153,9 @@ importers: '@shopify/flash-list': specifier: 1.6.3 version: 1.6.3(@babel/runtime@7.25.6)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@shopify/react-native-skia': + specifier: ^1.3.9 + version: 1.4.2(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tanstack/react-query': specifier: ~5.32.1 version: 5.32.1(react@18.2.0) @@ -257,7 +260,7 @@ importers: version: 4.17.21 posthog-react-native: specifier: ^2.7.1 - version: 2.11.3(jwrxiw3lzqzjxcpw4mvkvmmdfa) + version: 2.11.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(expo-application@5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-device@5.9.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-file-system@16.0.9(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-localization@14.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(react-native-device-info@10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))) react: specifier: ^18.2.0 version: 18.2.0 @@ -426,7 +429,7 @@ importers: version: 3.4.1 vitest: specifier: ^1.0.4 - version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) apps/tlon-web: dependencies: @@ -798,7 +801,7 @@ importers: version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@2.79.1)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) workbox-precaching: specifier: ^6.5.4 version: 6.6.0 @@ -889,10 +892,10 @@ importers: version: 2.0.1 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 1.1.0(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) '@welldone-software/why-did-you-render': specifier: ^7.0.1 version: 7.0.1(react@18.2.0) @@ -934,7 +937,7 @@ importers: version: 6.1.1 react-cosmos-plugin-vite: specifier: 6.1.1 - version: 6.1.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 6.1.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -943,7 +946,7 @@ importers: version: 4.0.0 rollup-plugin-visualizer: specifier: ^5.6.0 - version: 5.12.0(rollup@2.79.1) + version: 5.12.0(rollup@4.13.0) tailwindcss: specifier: ^3.2.7 version: 3.4.1 @@ -958,13 +961,13 @@ importers: version: 1.1.4(typescript@5.4.5) vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + version: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) vite-plugin-pwa: specifier: ^0.17.5 - version: 0.17.5(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) + version: 0.17.5(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) vitest: specifier: ^0.34.1 - version: 0.34.6(jsdom@23.2.0)(terser@5.19.1) + version: 0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -1348,7 +1351,7 @@ importers: version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) workbox-precaching: specifier: ^6.5.4 version: 6.6.0 @@ -1442,10 +1445,10 @@ importers: version: 2.0.1 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 1.1.0(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) '@welldone-software/why-did-you-render': specifier: ^7.0.1 version: 7.0.1(react@18.2.0) @@ -1490,7 +1493,7 @@ importers: version: 6.1.1 react-cosmos-plugin-vite: specifier: 6.1.1 - version: 6.1.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 6.1.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -1514,13 +1517,13 @@ importers: version: 1.1.4(typescript@5.4.5) vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + version: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) vite-plugin-pwa: specifier: ^0.17.5 - version: 0.17.5(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) + version: 0.17.5(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) vitest: specifier: ^0.34.1 - version: 0.34.6(jsdom@23.2.0)(terser@5.19.1) + version: 0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -1566,7 +1569,7 @@ importers: dependencies: '@10play/tentap-editor': specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1591,7 +1594,7 @@ importers: version: 6.21.0(eslint@8.56.0)(typescript@5.4.5) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) eslint: specifier: ^8.50.0 version: 8.56.0 @@ -1603,13 +1606,13 @@ importers: version: 5.4.5 vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + version: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) vite-plugin-singlefile: specifier: ^2.0.1 - version: 2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) vitest: specifier: ^1.0.4 - version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) packages/shared: dependencies: @@ -1680,7 +1683,7 @@ importers: version: 5.4.5 vitest: specifier: ^1.4.0 - version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) packages/ui: dependencies: @@ -1696,6 +1699,9 @@ importers: '@react-native-clipboard/clipboard': specifier: ^1.14.0 version: 1.14.0(react-native-macos@0.73.24(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-windows@0.73.11(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@shopify/react-native-skia': + specifier: ^1.3.9 + version: 1.4.2(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tamagui/animations-moti': specifier: ~1.112.12 version: 1.112.12(moti@0.28.1(react-dom@18.2.0(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react@18.2.0))(react@18.2.0) @@ -5125,6 +5131,19 @@ packages: react: '*' react-native: '*' + '@shopify/react-native-skia@1.4.2': + resolution: {integrity: sha512-Qg1H/MglY5BJiL4g2+8Tz97fZZp8XM48lb1xjGHqKmo54KwCmhc3GREnL/MYqcTcuJnIUNVYQmAJUw5xT3Chsg==} + hasBin: true + peerDependencies: + react: '>=18.0' + react-native: '>=0.64' + react-native-reanimated: '>=2.0.0' + peerDependenciesMeta: + react-native: + optional: true + react-native-reanimated: + optional: true + '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -6706,6 +6725,9 @@ packages: '@vitest/utils@1.5.0': resolution: {integrity: sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==} + '@webgpu/types@0.1.21': + resolution: {integrity: sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow==} + '@welldone-software/why-did-you-render@7.0.1': resolution: {integrity: sha512-Qe/8Xxa2G+LMdI6VoazescPzjjkHYduCDa8aHOJR50e9Bgs8ihkfMBY+ev7B4oc3N59Zm547Sgjf8h5y0FOyoA==} peerDependencies: @@ -7292,6 +7314,9 @@ packages: caniuse-lite@1.0.30001650: resolution: {integrity: sha512-fgEc7hP/LB7iicdXHUI9VsBsMZmUmlVJeQP2qqQW+3lkqVhbmjEU8zp+h5stWeilX+G7uXuIUIIlWlDw9jdt8g==} + canvaskit-wasm@0.39.1: + resolution: {integrity: sha512-Gy3lCmhUdKq+8bvDrs9t8+qf7RvcjuQn+we7vTVVyqgOVO1UVfHpsnBxkTZw+R4ApEJ3D5fKySl9TU11hmjl/A==} + chai@4.4.1: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} @@ -11646,6 +11671,12 @@ packages: react-native-svg: optional: true + react-reconciler@0.27.0: + resolution: {integrity: sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^18.0.0 + react-redux@7.2.8: resolution: {integrity: sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==} peerDependencies: @@ -12042,6 +12073,9 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} + scheduler@0.21.0: + resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} + scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} @@ -13669,6 +13703,43 @@ packages: snapshots: + '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bold': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bullet-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code-block': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) + '@tiptap/extension-document': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-heading': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-history': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-horizontal-rule': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-italic': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-link': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-list-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-ordered-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-placeholder': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-strike': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-task-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-task-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/pm': 2.6.6 + '@tiptap/react': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) + lodash: 4.17.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview: 13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + transitivePeerDependencies: + - '@tiptap/core' + '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) @@ -14562,6 +14633,19 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14575,6 +14659,13 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14582,6 +14673,17 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14593,6 +14695,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14639,6 +14752,16 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14657,6 +14780,13 @@ snapshots: '@babel/helper-plugin-utils@7.24.8': {} + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14664,6 +14794,13 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14746,11 +14883,23 @@ snapshots: dependencies: '@babel/types': 7.25.6 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14758,12 +14907,26 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.25.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14772,6 +14935,12 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14785,6 +14954,12 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14797,18 +14972,39 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -14818,12 +15014,25 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14831,10 +15040,19 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14845,11 +15063,21 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14860,41 +15088,81 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14905,75 +15173,153 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.7)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14983,22 +15329,45 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15006,6 +15375,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15018,58 +15399,117 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/template': 7.25.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15077,28 +15517,58 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15107,6 +15577,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-simple-access': 7.22.5 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15116,6 +15595,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-identifier': 7.22.20 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15126,6 +15615,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15134,29 +15631,61 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15166,18 +15695,37 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.25.2) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15185,17 +15733,36 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15204,11 +15771,21 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15250,6 +15827,17 @@ snapshots: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) '@babel/types': 7.25.6 + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15267,17 +15855,40 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + regenerator-transform: 0.15.2 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15290,32 +15901,66 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15324,29 +15969,138 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/preset-env@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + core-js-compat: 3.35.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/preset-env@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15440,6 +16194,13 @@ snapshots: '@babel/helper-validator-option': 7.24.8 '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.25.2) + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.25.6 + esutils: 2.0.3 + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -17816,6 +18577,13 @@ snapshots: '@react-native/assets-registry@0.73.1': {} + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -17823,6 +18591,54 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-react-jsx': 7.25.2(@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) + '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/template': 7.25.0 + '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.23.7) + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17871,6 +18687,19 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/parser': 7.25.3 + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + flow-parser: 0.206.0 + glob: 7.2.3 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/parser': 7.25.3 @@ -17905,6 +18734,27 @@ snapshots: - supports-color - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-tools': 12.3.7(encoding@0.1.13) + '@react-native/dev-middleware': 0.73.8(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + chalk: 4.1.2 + execa: 5.1.1 + metro: 0.80.5(encoding@0.1.13) + metro-config: 0.80.5(encoding@0.1.13) + metro-core: 0.80.5 + node-fetch: 2.6.12(encoding@0.1.13) + readline: 1.3.0 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) @@ -17951,6 +18801,16 @@ snapshots: '@react-native/js-polyfills@0.73.1': {} + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@react-native/babel-preset': 0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + hermes-parser: 0.15.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17978,6 +18838,12 @@ snapshots: '@react-native/normalize-colors@0.74.84': {} + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))': dependencies: invariant: 2.2.4 @@ -18080,14 +18946,6 @@ snapshots: picomatch: 2.3.1 rollup: 2.79.1 - '@rollup/pluginutils@5.1.0(rollup@2.79.1)': - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - optionalDependencies: - rollup: 2.79.1 - '@rollup/pluginutils@5.1.0(rollup@4.13.0)': dependencies: '@types/estree': 1.0.5 @@ -18151,6 +19009,15 @@ snapshots: recyclerlistview: 4.2.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) tslib: 2.4.0 + '@shopify/react-native-skia@1.4.2(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + canvaskit-wasm: 0.39.1 + react: 18.2.0 + react-reconciler: 0.27.0(react@18.2.0) + optionalDependencies: + react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) + react-native-reanimated: 3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -20322,33 +21189,33 @@ snapshots: graphql: 15.8.0 wonka: 4.0.15 - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))': dependencies: - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))': dependencies: - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) - '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))': + '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))': 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.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))': + '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))': 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.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - supports-color @@ -20438,6 +21305,8 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 + '@webgpu/types@0.1.21': {} + '@welldone-software/why-did-you-render@7.0.1(react@18.2.0)': dependencies: lodash: 4.17.21 @@ -20814,6 +21683,15 @@ snapshots: cosmiconfig: 7.1.0 resolve: 1.22.4 + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.7): + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.25.2): dependencies: '@babel/compat-data': 7.25.2 @@ -20823,6 +21701,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20831,6 +21717,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20839,6 +21733,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20850,6 +21751,12 @@ snapshots: babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.23.7): + dependencies: + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + transitivePeerDependencies: + - '@babel/core' + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2): dependencies: '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) @@ -21154,6 +22061,10 @@ snapshots: caniuse-lite@1.0.30001650: {} + canvaskit-wasm@0.39.1: + dependencies: + '@webgpu/types': 0.1.21 + chai@4.4.1: dependencies: assertion-error: 1.1.0 @@ -24380,6 +25291,31 @@ snapshots: jsc-safe-url@0.2.4: {} + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)): + dependencies: + '@babel/core': 7.25.2 + '@babel/parser': 7.25.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.25.2) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.25.2) + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + '@babel/preset-flow': 7.23.3(@babel/core@7.25.2) + '@babel/preset-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/register': 7.23.7(@babel/core@7.25.2) + babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) + chalk: 4.1.2 + flow-parser: 0.206.0 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.21.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.25.2)): dependencies: '@babel/core': 7.25.2 @@ -25726,8 +26662,8 @@ snapshots: dependencies: fflate: 0.4.8 - posthog-react-native@2.11.3(jwrxiw3lzqzjxcpw4mvkvmmdfa): - optionalDependencies: + ? posthog-react-native@2.11.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(expo-application@5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-device@5.9.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-file-system@16.0.9(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-localization@14.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(react-native-device-info@10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))) + : optionalDependencies: '@react-native-async-storage/async-storage': 1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)) '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) expo-application: 5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)) @@ -26070,17 +27006,17 @@ snapshots: react-cosmos-core: 6.1.1 react-cosmos-renderer: 6.1.1 - react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)): + react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: react-cosmos-core: 6.1.1 react-cosmos-dom: 6.1.1 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) - react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): + react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: react-cosmos-core: 6.1.1 react-cosmos-dom: 6.1.1 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) react-cosmos-renderer@6.1.1: dependencies: @@ -26413,6 +27349,13 @@ snapshots: transitivePeerDependencies: - encoding + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): + dependencies: + escape-string-regexp: 2.0.0 + invariant: 2.2.4 + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: escape-string-regexp: 2.0.0 @@ -26474,6 +27417,55 @@ snapshots: - supports-color - utf-8-validate + react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-android': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 12.3.7(encoding@0.1.13) + '@react-native/assets-registry': 0.73.1 + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13) + '@react-native/gradle-plugin': 0.73.4 + '@react-native/js-polyfills': 0.73.1 + '@react-native/normalize-colors': 0.73.2 + '@react-native/virtualized-lists': 0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0)) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + deprecated-react-native-prop-types: 5.0.0 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.5 + metro-source-map: 0.80.5 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 4.28.5 + react-refresh: 0.14.0 + react-shallow-renderer: 16.15.0(react@18.2.0) + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0): dependencies: '@jest/create-cache-key-function': 29.7.0 @@ -26537,6 +27529,12 @@ snapshots: optionalDependencies: react-native-svg: 15.0.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-reconciler@0.27.0(react@18.2.0): + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.21.0 + react-redux@7.2.8(react-dom@18.2.0(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.23.8 @@ -26891,15 +27889,6 @@ snapshots: serialize-javascript: 4.0.0 terser: 5.19.1 - rollup-plugin-visualizer@5.12.0(rollup@2.79.1): - dependencies: - open: 8.4.2 - picomatch: 2.3.1 - source-map: 0.7.4 - yargs: 17.7.2 - optionalDependencies: - rollup: 2.79.1 - rollup-plugin-visualizer@5.12.0(rollup@4.13.0): dependencies: open: 8.4.2 @@ -26995,6 +27984,10 @@ snapshots: dependencies: xmlchars: 2.2.0 + scheduler@0.21.0: + dependencies: + loose-envify: 1.4.0 + scheduler@0.23.0: dependencies: loose-envify: 1.4.0 @@ -28201,14 +29194,14 @@ snapshots: react-dom: 18.2.0(react@18.2.0) redux: 4.2.0 - vite-node@0.34.6(@types/node@20.10.8)(terser@5.19.1): + vite-node@0.34.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 mlly: 1.5.0 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -28219,13 +29212,13 @@ snapshots: - supports-color - terser - vite-node@1.2.2(@types/node@20.14.10)(terser@5.19.1): + vite-node@1.2.2(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -28236,13 +29229,13 @@ snapshots: - supports-color - terser - vite-node@1.5.0(@types/node@20.14.10)(terser@5.19.1): + vite-node@1.5.0(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -28253,57 +29246,57 @@ snapshots: - supports-color - terser - vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): + vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) workbox-build: 7.0.0(@types/babel__core@7.20.5) workbox-window: 7.0.0 transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): + vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) workbox-build: 7.0.0(@types/babel__core@7.20.5) workbox-window: 7.0.0 transitivePeerDependencies: - supports-color - vite-plugin-singlefile@2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): + vite-plugin-singlefile@2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: micromatch: 4.0.5 rollup: 4.13.0 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) - vite-plugin-svgr@4.2.0(rollup@2.79.1)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)): + vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: - '@rollup/pluginutils': 5.1.0(rollup@2.79.1) + '@rollup/pluginutils': 5.1.0(rollup@4.13.0) '@svgr/core': 8.1.0(typescript@5.4.5) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): + vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.13.0) '@svgr/core': 8.1.0(typescript@5.4.5) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite@5.1.6(@types/node@20.10.8)(terser@5.19.1): + vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1): dependencies: esbuild: 0.19.12 postcss: 8.4.35 @@ -28311,9 +29304,10 @@ snapshots: optionalDependencies: '@types/node': 20.10.8 fsevents: 2.3.3 + lightningcss: 1.19.0 terser: 5.19.1 - vite@5.1.6(@types/node@20.14.10)(terser@5.19.1): + vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): dependencies: esbuild: 0.19.12 postcss: 8.4.35 @@ -28321,9 +29315,10 @@ snapshots: optionalDependencies: '@types/node': 20.14.10 fsevents: 2.3.3 + lightningcss: 1.19.0 terser: 5.19.1 - vitest@0.34.6(jsdom@23.2.0)(terser@5.19.1): + vitest@0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): dependencies: '@types/chai': 4.3.11 '@types/chai-subset': 1.3.5 @@ -28346,8 +29341,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.7.0 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) - vite-node: 0.34.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite-node: 0.34.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: jsdom: 23.2.0 @@ -28360,7 +29355,7 @@ snapshots: - supports-color - terser - vitest@1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1): + vitest@1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): dependencies: '@vitest/expect': 1.2.2 '@vitest/runner': 1.2.2 @@ -28380,8 +29375,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.2 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) - vite-node: 1.2.2(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite-node: 1.2.2(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.10 @@ -28395,7 +29390,7 @@ snapshots: - supports-color - terser - vitest@1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1): + vitest@1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): dependencies: '@vitest/expect': 1.5.0 '@vitest/runner': 1.5.0 @@ -28414,8 +29409,8 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.4 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) - vite-node: 1.5.0(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite-node: 1.5.0(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.10 From e4e9fd8f41d266545039eddb0170431b1145d9e9 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 11 Oct 2024 11:38:10 -0700 Subject: [PATCH 132/259] Enable passing content config to useCreateChannel --- packages/shared/src/logic/useCreateChannel.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/shared/src/logic/useCreateChannel.ts b/packages/shared/src/logic/useCreateChannel.ts index b0801b857e..c1f7a9cc98 100644 --- a/packages/shared/src/logic/useCreateChannel.ts +++ b/packages/shared/src/logic/useCreateChannel.ts @@ -29,10 +29,12 @@ export function useCreateChannel({ title, description, channelType, + contentConfiguration, }: { title: string; description?: string; channelType: Omit; + contentConfiguration?: ChannelContentConfiguration; }) => { const { name, id } = assembleNewChannelIdAndName({ title, @@ -50,11 +52,8 @@ export function useCreateChannel({ description, channelType: channelType === 'custom' ? 'chat' : channelType, contentConfiguration: - channelType === 'custom' - ? (() => { - throw new Error('Not implemented'); - })() - : channelContentConfigurationForChannelType(channelType), + contentConfiguration ?? + channelContentConfigurationForChannelType(channelType), }); } }, From f14e8865f43d9b289e6674116eb9261137540735 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 11 Oct 2024 12:45:05 -0700 Subject: [PATCH 133/259] Add custom channel config to create channel sheet --- .../ManageChannels/CreateChannelSheet.tsx | 213 +++++++++++++++--- 1 file changed, 180 insertions(+), 33 deletions(-) diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 337ec84e11..7386dfb53e 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -1,6 +1,19 @@ -import { useCreateChannel } from '@tloncorp/shared'; +import { + ChannelContentConfiguration, + CollectionRendererId, + DraftInputId, + PostContentRendererId, + useCreateChannel, +} from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; -import { useCallback } from 'react'; +import { + ElementRef, + forwardRef, + useCallback, + useImperativeHandle, + useMemo, + useRef, +} from 'react'; import { useForm } from 'react-hook-form'; import { useCurrentUserId } from '../../contexts'; @@ -8,7 +21,7 @@ import { ActionSheet } from '../ActionSheet'; import { Button } from '../Button'; import * as Form from '../Form'; -export type ChannelTypeName = 'chat' | 'notebook' | 'gallery'; +export type ChannelTypeName = 'chat' | 'notebook' | 'gallery' | 'custom'; const channelTypes: Form.ListItemInputOption[] = [ { @@ -29,6 +42,12 @@ const channelTypes: Form.ListItemInputOption[] = [ value: 'gallery', icon: 'ChannelGalleries', }, + { + title: 'Custom', + subtitle: 'go crazzy', + value: 'custom', + icon: 'ChannelGalleries', + }, ]; export function CreateChannelSheet({ @@ -38,7 +57,12 @@ export function CreateChannelSheet({ onOpenChange: (open: boolean) => void; group: db.Group; }) { - const { control, handleSubmit } = useForm({ + const customChannelConfigRef = + useRef>(null); + const { control, handleSubmit, watch } = useForm<{ + title: string; + channelType: ChannelTypeName; + }>({ defaultValues: { title: '', channelType: 'chat', @@ -51,10 +75,15 @@ export function CreateChannelSheet({ currentUserId, }); const handlePressSave = useCallback( - async (data: { title: string; channelType: string }) => { + async (data: { title: string; channelType: ChannelTypeName }) => { + let contentConfiguration: ChannelContentConfiguration | undefined; + if (data.channelType === 'custom') { + contentConfiguration = customChannelConfigRef.current?.getFormValue(); + } createChannel({ title: data.title, - channelType: data.channelType as ChannelTypeName, + channelType: data.channelType, + contentConfiguration, }); onOpenChange(false); }, @@ -62,32 +91,150 @@ export function CreateChannelSheet({ ); return ( - - - - - - - - - - - - - - + <> + + + + + + + + + + {watch('channelType') === 'custom' && ( + + )} + + + + + + ; + ); } + +function labelForDraftInput(draftInputId: DraftInputId): string { + switch (draftInputId) { + case DraftInputId.chat: + return 'Chat'; + case DraftInputId.gallery: + return 'Gallery'; + case DraftInputId.notebook: + return 'Notebook'; + case DraftInputId.picto: + return 'Drawing'; + } +} +function labelForContentRenderer(r: PostContentRendererId): string { + switch (r) { + case PostContentRendererId.chat: + return 'Chat'; + case PostContentRendererId.gallery: + return 'Gallery'; + case PostContentRendererId.notebook: + return 'Notebook'; + case PostContentRendererId.picto: + return 'Drawing'; + } +} +function labelForCollectionLayout(l: CollectionRendererId): string { + switch (l) { + case CollectionRendererId.chat: + return 'Chat'; + case CollectionRendererId.gallery: + return 'Gallery'; + case CollectionRendererId.notebook: + return 'Notebook'; + } +} + +const CustomChannelConfigurationForm = forwardRef<{ + getFormValue: () => ChannelContentConfiguration; +}>(function CustomChannelConfigurationForm(_props, ref) { + const { control, getValues } = useForm({ + defaultValues: { + draftInput: DraftInputId.chat, + defaultPostContentRenderer: PostContentRendererId.chat, + defaultPostCollectionRenderer: CollectionRendererId.chat, + }, + }); + + const options = useMemo( + () => ({ + inputs: [ + DraftInputId.chat, + DraftInputId.gallery, + DraftInputId.notebook, + DraftInputId.picto, + ].map((id) => ({ + title: labelForDraftInput(id), + value: id, + })), + content: [ + PostContentRendererId.chat, + PostContentRendererId.gallery, + PostContentRendererId.notebook, + PostContentRendererId.picto, + ].map((id) => ({ + title: labelForContentRenderer(id), + value: id, + })), + collection: [ + CollectionRendererId.chat, + CollectionRendererId.gallery, + CollectionRendererId.notebook, + ].map((id) => ({ + title: labelForCollectionLayout(id), + value: id, + })), + }), + [] + ); + + useImperativeHandle(ref, () => ({ + getFormValue: () => getValues(), + })); + + return ( + <> + + + + + + + + + + + ); +}); From 0828a9bedb5d29ba7f3ee268a6ca98d9d30744fb Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 11 Oct 2024 13:34:14 -0700 Subject: [PATCH 134/259] Add "yo" input --- .../shared/src/api/channelContentConfig.ts | 1 + .../ManageChannels/CreateChannelSheet.tsx | 3 ++ .../components/draftInputs/ButtonInput.tsx | 41 +++++++++++++++++++ packages/ui/src/contexts/componentsKits.tsx | 8 ++++ 4 files changed, 53 insertions(+) create mode 100644 packages/ui/src/components/draftInputs/ButtonInput.tsx diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index bd624c3104..f6bdaa67d0 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -13,6 +13,7 @@ export enum DraftInputId { chat = 'tlon.r0.input.chat', gallery = 'tlon.r0.input.gallery', picto = 'tlon.r0.input.picto', + yo = 'tlon.r0.input.yo', } export enum PostContentRendererId { diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 7386dfb53e..1561a755b8 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -137,6 +137,8 @@ function labelForDraftInput(draftInputId: DraftInputId): string { return 'Notebook'; case DraftInputId.picto: return 'Drawing'; + case DraftInputId.yo: + return 'Yo'; } } function labelForContentRenderer(r: PostContentRendererId): string { @@ -180,6 +182,7 @@ const CustomChannelConfigurationForm = forwardRef<{ DraftInputId.gallery, DraftInputId.notebook, DraftInputId.picto, + DraftInputId.yo, ].map((id) => ({ title: labelForDraftInput(id), value: id, diff --git a/packages/ui/src/components/draftInputs/ButtonInput.tsx b/packages/ui/src/components/draftInputs/ButtonInput.tsx new file mode 100644 index 0000000000..64b061600e --- /dev/null +++ b/packages/ui/src/components/draftInputs/ButtonInput.tsx @@ -0,0 +1,41 @@ +import { SafeAreaView } from 'react-native-safe-area-context'; +import { Button, View } from 'tamagui'; + +import { DraftInputContext } from './shared'; + +export function ButtonInput({ + draftInputContext, + messageText, + labelText, +}: { + draftInputContext: DraftInputContext; + messageText: string; + labelText: string; +}) { + return ( + + + + ); +} diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index bf268df573..e0f72ee855 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -21,6 +21,7 @@ import { GalleryInput, NotebookInput, } from '../components/draftInputs'; +import { ButtonInput } from '../components/draftInputs/ButtonInput'; type RenderItemFunction = (props: { post: db.Post; @@ -98,6 +99,13 @@ export function ComponentsKitContextProvider({ [DraftInputId.gallery]: GalleryInput, [DraftInputId.notebook]: NotebookInput, [DraftInputId.picto]: StandaloneDrawingInput, + [DraftInputId.yo]: ({ draftInputContext }) => ( + + ), }); const registerRenderer = useCallback( From d01ecd62fd38d30ac8bba83d08236e47d369a0ef Mon Sep 17 00:00:00 2001 From: David Lee Date: Tue, 15 Oct 2024 12:38:03 -0700 Subject: [PATCH 135/259] Move useCreateChannel into store directory to avoid dependency cycle --- packages/shared/src/logic/index.ts | 1 - packages/shared/src/store/index.ts | 1 + packages/shared/src/{logic => store}/useCreateChannel.ts | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename packages/shared/src/{logic => store}/useCreateChannel.ts (100%) diff --git a/packages/shared/src/logic/index.ts b/packages/shared/src/logic/index.ts index de3bcacf46..e460101969 100644 --- a/packages/shared/src/logic/index.ts +++ b/packages/shared/src/logic/index.ts @@ -7,4 +7,3 @@ export * from './activity'; export * from './branch'; export * from './deeplinks'; export * from './analytics'; -export * from './useCreateChannel'; diff --git a/packages/shared/src/store/index.ts b/packages/shared/src/store/index.ts index 7af001443b..514ec628ee 100644 --- a/packages/shared/src/store/index.ts +++ b/packages/shared/src/store/index.ts @@ -3,6 +3,7 @@ export * from './reactQuery'; export * from './sync'; export * from './useChannelPosts'; export * from './useChannelSearch'; +export * from './useCreateChannel'; export * from './postActions'; export * from './channelActions'; export * from './groupActions'; diff --git a/packages/shared/src/logic/useCreateChannel.ts b/packages/shared/src/store/useCreateChannel.ts similarity index 100% rename from packages/shared/src/logic/useCreateChannel.ts rename to packages/shared/src/store/useCreateChannel.ts From 1ab279967d5296a4ea2ebec41b1324d0f572088d Mon Sep 17 00:00:00 2001 From: David Lee Date: Tue, 15 Oct 2024 12:38:25 -0700 Subject: [PATCH 136/259] Fix tests, add model builders to catch schema test failures via TS --- packages/shared/src/db/modelBuilders.ts | 105 +++++++++++++++ packages/shared/src/store/sync.test.ts | 162 +++++++----------------- 2 files changed, 149 insertions(+), 118 deletions(-) diff --git a/packages/shared/src/db/modelBuilders.ts b/packages/shared/src/db/modelBuilders.ts index 0df2b0d11a..ce5cb9d5e8 100644 --- a/packages/shared/src/db/modelBuilders.ts +++ b/packages/shared/src/db/modelBuilders.ts @@ -240,3 +240,108 @@ export function buildPendingSingleDmChannel( members: [partnerMember], }; } + +type Optional = Omit< + Base, + OptionalProperties +> & + Partial>; + +export function buildChannel( + overrides: Optional< + db.Channel, + | 'addedToGroupAt' + | 'contactId' + | 'contentConfiguration' + | 'coverImage' + | 'coverImageColor' + | 'currentUserIsMember' + | 'description' + | 'firstUnreadPostId' + | 'groupId' + | 'iconImage' + | 'iconImageColor' + | 'isDefaultWelcomeChannel' + | 'isDmInvite' + | 'isPendingChannel' + | 'lastPostAt' + | 'lastPostId' + | 'lastViewedAt' + | 'members' + | 'postCount' + | 'remoteUpdatedAt' + | 'syncedAt' + | 'title' + | 'unreadCount' + > +): db.Channel { + return { + addedToGroupAt: null, + contactId: null, + contentConfiguration: null, + coverImage: null, + coverImageColor: null, + currentUserIsMember: null, + description: '', + firstUnreadPostId: null, + groupId: null, + iconImage: null, + iconImageColor: null, + isDefaultWelcomeChannel: null, + isDmInvite: false, + isPendingChannel: null, + lastPostAt: null, + lastPostId: null, + lastViewedAt: null, + members: [], + postCount: null, + remoteUpdatedAt: null, + syncedAt: null, + title: '', + unreadCount: null, + ...overrides, + }; +} + +export function buildChatMember( + overrides: Optional< + db.ChatMember, + 'chatId' | 'contact' | 'joinedAt' | 'status' + > +): db.ChatMember { + return { + chatId: null, + contact: null, + joinedAt: null, + status: null, + ...overrides, + }; +} + +interface ChatMembersBuilder { + add( + ...overrides: Array< + Optional, 'contact'> + > + ): ChatMembersBuilder; + build(): db.ChatMember[]; +} + +export function buildChatMembers( + commonFields: Pick +): ChatMembersBuilder { + const members: db.ChatMember[] = []; + + return { + add(...overridesList) { + for (const overrides of overridesList) { + const member = buildChatMember({ ...commonFields, ...overrides }); + members.push(member); + } + return this; + }, + build() { + return members; + }, + }; +} diff --git a/packages/shared/src/store/sync.test.ts b/packages/shared/src/store/sync.test.ts index 10c9fad3bb..72be024d1d 100644 --- a/packages/shared/src/store/sync.test.ts +++ b/packages/shared/src/store/sync.test.ts @@ -145,128 +145,54 @@ test('syncs dms', async () => { id: '~solfer-magfed', includeMembers: true, }); - expect(singleChannel).toEqual({ - id: '~solfer-magfed', - type: 'dm', - groupId: null, - contactId: '~solfer-magfed', - iconImage: null, - iconImageColor: null, - coverImage: null, - coverImageColor: null, - title: '', - description: '', - addedToGroupAt: null, - currentUserIsMember: null, - postCount: null, - unreadCount: null, - firstUnreadPostId: null, - lastPostId: null, - lastPostAt: null, - syncedAt: null, - remoteUpdatedAt: null, - isPendingChannel: null, - isDmInvite: false, - isDefaultWelcomeChannel: null, - lastViewedAt: null, - members: [ - { - chatId: '~solfer-magfed', - contactId: '~solfer-magfed', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: null, - }, - ], - }); + expect(singleChannel).toEqual( + db.buildChannel({ + id: '~solfer-magfed', + type: 'dm', + contactId: '~solfer-magfed', + title: '', + description: '', + members: [ + { + chatId: '~solfer-magfed', + contactId: '~solfer-magfed', + contact: null, + joinedAt: null, + membershipType: 'channel', + status: null, + }, + ], + }) + ); const groupDmChannel = await db.getChannel({ id: groupDmId, includeMembers: true, }); - expect(groupDmChannel).toEqual({ - id: '0v4.00000.qd4p2.it253.qs53q.s53qs', - type: 'groupDm', - groupId: null, - contactId: null, - iconImage: null, - iconImageColor: '#f0ebbd', - coverImage: null, - coverImageColor: null, - title: 'Pensacola 2024-04', - description: '', - addedToGroupAt: null, - currentUserIsMember: null, - postCount: null, - unreadCount: null, - firstUnreadPostId: null, - lastPostId: null, - lastPostAt: null, - syncedAt: null, - remoteUpdatedAt: null, - isPendingChannel: null, - isDmInvite: false, - isDefaultWelcomeChannel: null, - lastViewedAt: null, - members: [ - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contactId: '~finned-palmer', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: 'joined', - }, - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contact: null, - contactId: '~latter-bolden', - joinedAt: null, - membershipType: 'channel', - status: 'invited', - }, - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contactId: '~nocsyx-lassul', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: 'joined', - }, - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contactId: '~palfun-foslup', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: 'joined', - }, - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contactId: '~pondus-watbel', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: 'joined', - }, - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contactId: '~rilfun-lidlen', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: 'joined', - }, - { - chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', - contactId: '~solfer-magfed', - contact: null, - joinedAt: null, - membershipType: 'channel', - status: 'joined', - }, - ], - }); + expect(groupDmChannel).toEqual( + db.buildChannel({ + id: '0v4.00000.qd4p2.it253.qs53q.s53qs', + type: 'groupDm', + contactId: null, + iconImageColor: '#f0ebbd', + title: 'Pensacola 2024-04', + description: '', + members: db + .buildChatMembers({ + chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', + membershipType: 'channel', + }) + .add( + { contactId: '~finned-palmer', status: 'joined' }, + { contactId: '~latter-bolden', status: 'invited' }, + { contactId: '~nocsyx-lassul', status: 'joined' }, + { contactId: '~palfun-foslup', status: 'joined' }, + { contactId: '~pondus-watbel', status: 'joined' }, + { contactId: '~rilfun-lidlen', status: 'joined' }, + { contactId: '~solfer-magfed', status: 'joined' } + ) + .build(), + }) + ); }); const groupId = '~solfer-magfed/test-group'; From 4da48735b07390e5ec1258827d994cf2e360ef69 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 10:32:25 -0700 Subject: [PATCH 137/259] Fix merge artifact --- .../ManageChannels/CreateChannelSheet.tsx | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 1561a755b8..eb7b1b01b4 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -91,39 +91,36 @@ export function CreateChannelSheet({ ); return ( - <> - - - - - - - - - - {watch('channelType') === 'custom' && ( - - )} - - - - - - ; - + + + + + + + + + + {watch('channelType') === 'custom' && ( + + )} + + + + + ); } From 387ac58a715e1da7b0ef830db207abfe10604760 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 10:38:12 -0700 Subject: [PATCH 138/259] Make component kits immutable --- packages/ui/src/contexts/componentsKits.tsx | 86 +++++++-------------- 1 file changed, 26 insertions(+), 60 deletions(-) diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index e0f72ee855..191172b8f2 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -1,14 +1,7 @@ import { DraftInputId, PostContentRendererId } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import { Story } from '@tloncorp/shared/dist/urbit'; -import { - ReactElement, - createContext, - useCallback, - useContext, - useMemo, - useState, -} from 'react'; +import { ReactElement, createContext, useContext, useMemo } from 'react'; import { PictoMessage } from '../components/Channel/PictoMessage'; import { ChatMessage } from '../components/ChatMessage'; @@ -55,25 +48,11 @@ interface ComponentsKitContextValue { inputs: Readonly< Partial<{ [Id in DraftInputId]: DraftInputRendererComponent }> >; - - // TODO: Remove - registerRenderer: ( - id: string, - renderer: RenderItemType - ) => { unregister: () => void }; } const _globalContextValue: ComponentsKitContextValue = { renderers: {}, inputs: {}, - registerRenderer(id, renderer) { - this.renderers[id] = renderer; - return { - unregister: () => { - delete this.renderers[id]; - }, - }; - }, }; const ComponentsKitContext = @@ -83,50 +62,37 @@ export function useComponentsKitContext() { return useContext(ComponentsKitContext); } +const BUILTIN_CONTENT_RENDERERS: { [id: string]: RenderItemType } = { + [PostContentRendererId.chat]: ChatMessage, + [PostContentRendererId.gallery]: GalleryPost, + [PostContentRendererId.notebook]: NotebookPost, + [PostContentRendererId.picto]: PictoMessage, +}; +const BUILTIN_DRAFT_INPUTS: { [id: string]: DraftInputRendererComponent } = { + [DraftInputId.chat]: ChatInput, + [DraftInputId.gallery]: GalleryInput, + [DraftInputId.notebook]: NotebookInput, + [DraftInputId.picto]: StandaloneDrawingInput, + [DraftInputId.yo]: ({ draftInputContext }) => ( + + ), +}; + export function ComponentsKitContextProvider({ children, }: { children: React.ReactNode; }) { - const [renderers, setRenderers] = useState<{ [id: string]: RenderItemType }>({ - [PostContentRendererId.chat]: ChatMessage, - [PostContentRendererId.gallery]: GalleryPost, - [PostContentRendererId.notebook]: NotebookPost, - [PostContentRendererId.picto]: PictoMessage, - }); - const [inputs] = useState<{ [id: string]: DraftInputRendererComponent }>({ - [DraftInputId.chat]: ChatInput, - [DraftInputId.gallery]: GalleryInput, - [DraftInputId.notebook]: NotebookInput, - [DraftInputId.picto]: StandaloneDrawingInput, - [DraftInputId.yo]: ({ draftInputContext }) => ( - - ), - }); - - const registerRenderer = useCallback( - (id: string, renderer: RenderItemType) => { - setRenderers((prev) => ({ ...prev, [id]: renderer })); - return { - unregister: () => { - setRenderers((prev) => { - const next = { ...prev }; - delete next[id]; - return next; - }); - }, - }; - }, - [setRenderers] - ); - const value = useMemo( - () => ({ renderers, inputs, registerRenderer }), - [renderers, inputs, registerRenderer] + () => ({ + renderers: BUILTIN_CONTENT_RENDERERS, + inputs: BUILTIN_DRAFT_INPUTS, + }), + [] ); return ( From c38a83fe70304116797d4ba2e948c22cd8428ba4 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 10:46:54 -0700 Subject: [PATCH 139/259] Gate custom channel creation behind a feature flag --- .../app/features/top/GroupChannelsScreen.tsx | 4 ++++ packages/app/lib/featureFlags.ts | 4 ++++ .../components/GroupChannelsScreenView.tsx | 3 +++ .../ManageChannels/CreateChannelSheet.tsx | 19 +++++++++++++++++-- .../ManageChannelsScreenView.tsx | 3 +++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index 1371d4bc0e..da4a7de98a 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -7,6 +7,7 @@ import { GroupChannelsScreenView, InviteUsersSheet, } from '@tloncorp/ui'; +import { useFeatureFlag } from 'packages/app/lib/featureFlags'; import { useCallback, useMemo, useState } from 'react'; import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation'; @@ -44,6 +45,8 @@ export function GroupChannelsScreen({ navigation, route }: Props) { navigation.goBack(); }, [navigation]); + const [enableCustomChannels] = useFeatureFlag('customChannels'); + return ( ; export type FeatureName = keyof typeof featureMeta; diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index c34ecc8c9e..0009935d4c 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -15,12 +15,14 @@ type GroupChannelsScreenViewProps = { group: db.Group | null; onChannelPressed: (channel: db.Channel) => void; onBackPressed: () => void; + enableCustomChannels?: boolean; }; export function GroupChannelsScreenView({ group, onChannelPressed, onBackPressed, + enableCustomChannels = false, }: GroupChannelsScreenViewProps) { const chatOptionsSheetRef = useRef(null); const [showCreateChannel, setShowCreateChannel] = useState(false); @@ -117,6 +119,7 @@ export function GroupChannelsScreenView({ setShowCreateChannel(open)} group={group} + enableCustomChannels={enableCustomChannels} /> )} diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index eb7b1b01b4..f52e3f8239 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -53,9 +53,11 @@ const channelTypes: Form.ListItemInputOption[] = [ export function CreateChannelSheet({ onOpenChange, group, + enableCustomChannels = false, }: { onOpenChange: (open: boolean) => void; group: db.Group; + enableCustomChannels?: boolean; }) { const customChannelConfigRef = useRef>(null); @@ -90,10 +92,23 @@ export function CreateChannelSheet({ [createChannel, onOpenChange] ); + const availableChannelTypes = useMemo( + () => + enableCustomChannels + ? channelTypes + : channelTypes.filter((t) => t.value !== 'custom'), + [enableCustomChannels] + ); + return ( - + diff --git a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx index 94447dab15..9d3652a5d3 100644 --- a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx +++ b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx @@ -179,6 +179,7 @@ interface ManageChannelsScreenViewProps { goToEditChannel: (channelId: string) => void; groupNavSectionsWithChannels: GroupNavSectionWithChannels[]; group: db.Group | null; + enableCustomChannels?: boolean; moveNavSection: (navSectionId: string, newIndex: number) => Promise; moveChannelWithinNavSection: ( channelId: string, @@ -205,6 +206,7 @@ export function ManageChannelsScreenView({ createNavSection, deleteNavSection, updateNavSection, + enableCustomChannels = false, }: ManageChannelsScreenViewProps) { const [sections, setSections] = useState(() => { console.log('componentDidMount', groupNavSectionsWithChannels); @@ -558,6 +560,7 @@ export function ManageChannelsScreenView({ setShowCreateChannel(open)} + enableCustomChannels={enableCustomChannels} /> )} Date: Fri, 18 Oct 2024 10:50:39 -0700 Subject: [PATCH 140/259] Update CreateChannelSheet fixture to enable toggling custom channels --- .../ActionSheet/CreateChannelSheet.fixture.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx b/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx index 888b4ee23e..54538bc1a9 100644 --- a/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/ActionSheet/CreateChannelSheet.fixture.tsx @@ -1,5 +1,17 @@ +import { QueryClientProvider, queryClient } from '@tloncorp/shared'; +import { AppDataContextProvider } from '@tloncorp/ui'; import { CreateChannelSheet } from '@tloncorp/ui/src/components/ManageChannels/CreateChannelSheet'; import { group } from '../fakeData'; -export default {}} />; +export default ( + + + {}} + enableCustomChannels={false} + /> + + +); From c373c2ad4de1d4e17737f48319ea5b1c9d4cc16c Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 10:52:08 -0700 Subject: [PATCH 141/259] Rearrange custom channel config form to make a lil more sense --- .../ManageChannels/CreateChannelSheet.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index f52e3f8239..196b508d55 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -228,26 +228,26 @@ const CustomChannelConfigurationForm = forwardRef<{ <> From e499ee4283db6da8707e316ea842162f09cc9a1d Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 11:14:52 -0700 Subject: [PATCH 142/259] Use percent snap point instead of content max height for tall sheet --- .../ManageChannels/CreateChannelSheet.tsx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 196b508d55..a839795de9 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -101,14 +101,25 @@ export function CreateChannelSheet({ ); return ( - + - + Date: Fri, 18 Oct 2024 11:20:50 -0700 Subject: [PATCH 143/259] Remove unused types --- .../shared/src/api/channelContentConfig.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index f6bdaa67d0..11e75fb947 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -1,7 +1,3 @@ -type PostContent = 'TODO: PostContent'; - -type RenderTarget = JSX.Element; - export enum CollectionRendererId { notebook = 'tlon.r0.collection.notebook', chat = 'tlon.r0.collection.chat', @@ -46,20 +42,6 @@ export interface ChannelContentConfiguration { defaultPostCollectionRenderer: CollectionRendererId; } -/** - * How does a given post content renderer render a post content? - */ -export interface PostContentRendererDescription { - render: (props: { content: PostContent }) => RenderTarget; -} - -/** - * How does a given draft input render its controls? - */ -export interface DraftInputDescription { - render: (props: { ref: React.Ref<{ value: Payload }> }) => RenderTarget; -} - /** * We use a channel's `description` field to store structured data. This * module provides helpers for managing that data. From e73aa9638614435e19de1bb3f155e5a9a6093ed1 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:10:19 -0700 Subject: [PATCH 144/259] Reduce code duplication when decoding structured channel description --- .../shared/src/api/channelContentConfig.ts | 22 +++++++++++++--- packages/shared/src/api/chatApi.ts | 25 ++++++------------- packages/shared/src/api/groupsApi.ts | 24 +++--------------- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index 11e75fb947..6e4a4ba53e 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -48,21 +48,35 @@ export interface ChannelContentConfiguration { */ // eslint-disable-next-line @typescript-eslint/no-namespace export namespace StructuredChannelDescriptionPayload { - type Encoded = string; + type Encoded = string | null | undefined; interface Decoded { - channelContentConfiguration: ChannelContentConfiguration; + channelContentConfiguration?: ChannelContentConfiguration; description?: string; } export function encode(payload: Decoded): Encoded { return JSON.stringify(payload); } - export function decodeOrNull(encoded: Encoded): Decoded | null { + + /** + * Attempts to decode a `description` string into a structured payload. + * + * - If `description` is null/undefined, returns a payload with no + * description nor configuration. + * - If `description` is not valid JSON, returns a payload with the + * description as the input string. + * - If `description` validates as the expected + * `StructuredChannelDescriptionPayload` JSON, returns the decoded payload. + */ + export function decode(encoded: Encoded): Decoded { // TODO: This should be validated - we'll be deserializing untrusted data + if (encoded == null) { + return {}; + } try { return JSON.parse(encoded); } catch (_err) { - return null; + return { description: encoded.length === 0 ? undefined : encoded }; } } } diff --git a/packages/shared/src/api/chatApi.ts b/packages/shared/src/api/chatApi.ts index 1ecd2c35e2..7077d59e0e 100644 --- a/packages/shared/src/api/chatApi.ts +++ b/packages/shared/src/api/chatApi.ts @@ -339,22 +339,12 @@ export const toClientGroupDms = (groupDms: ub.Clubs): GetDmsResponse => { const metaFields = toClientMeta(club.meta); - // Decode structured description payload if possible. - const decodedDesc = - metaFields.description == null - ? null - : StructuredChannelDescriptionPayload.decodeOrNull( - metaFields.description - ); - let contentConfiguration: ChannelContentConfiguration | undefined; - if (decodedDesc != null) { - // If the `description` field on API was a structured payload, unpack - // the payload's interior `description` field into our local - // `description` field. - metaFields.description = decodedDesc.description; - - contentConfiguration = decodedDesc.channelContentConfiguration; - } + // Channel meta is different from other metas, since we can overload the + // `description` to fit other channel-specific data. + // Attempt to decode that extra info here. + const decodedDesc = StructuredChannelDescriptionPayload.decode( + metaFields.description + ); return { id, @@ -362,7 +352,8 @@ export const toClientGroupDms = (groupDms: ub.Clubs): GetDmsResponse => { ...metaFields, isDmInvite: !isJoined && isInvited, members: [...joinedMembers, ...invitedMembers], - contentConfiguration, + contentConfiguration: decodedDesc.channelContentConfiguration, + description: decodedDesc.description, }; }) .filter(Boolean) as db.Channel[]; diff --git a/packages/shared/src/api/groupsApi.ts b/packages/shared/src/api/groupsApi.ts index f6967c7e6e..47b41b9bd7 100644 --- a/packages/shared/src/api/groupsApi.ts +++ b/packages/shared/src/api/groupsApi.ts @@ -13,10 +13,7 @@ import { getJoinStatusFromGang, } from '../urbit'; import { parseGroupId, toClientMeta } from './apiUtils'; -import { - ChannelContentConfiguration, - StructuredChannelDescriptionPayload, -} from './channelContentConfig'; +import { StructuredChannelDescriptionPayload } from './channelContentConfig'; import { getCurrentUserId, poke, @@ -1459,21 +1456,8 @@ function toClientChannel({ channel: ub.GroupChannel; groupId: string; }): db.Channel { - // Decode structured description payload if possible. - let description: string | null = channel.meta.description; - const decodedDesc = - description == null || description.length === 0 - ? null - : StructuredChannelDescriptionPayload.decodeOrNull(description); - let contentConfiguration: ChannelContentConfiguration | undefined; - if (decodedDesc != null) { - // If the `description` field on API was a structured payload, unpack - // the payload's interior `description` field into our local - // `description` field. - description = omitEmpty(decodedDesc.description ?? ''); - - contentConfiguration = decodedDesc.channelContentConfiguration; - } + const { description, channelContentConfiguration } = + StructuredChannelDescriptionPayload.decode(channel.meta.description); return { id, groupId, @@ -1482,7 +1466,7 @@ function toClientChannel({ title: omitEmpty(channel.meta.title), coverImage: omitEmpty(channel.meta.cover), description, - contentConfiguration, + contentConfiguration: channelContentConfiguration, }; } From 0e50488497991a5f049dfef0e639de72ab344eae Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:13:44 -0700 Subject: [PATCH 145/259] Remove unused createChannel from useGroupContext --- packages/app/hooks/useGroupContext.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index 5119ea923f..59415bc1b8 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -99,12 +99,6 @@ export const useGroupContext = ({ } }, [group]); - const createChannel = useCreateChannel({ - group, - currentUserId, - disabled: !isFocused, - }); - const deleteChannel = useCallback( async (channelId: string) => { if (group) { @@ -339,7 +333,6 @@ export const useGroupContext = ({ setGroupMetadata, setGroupPrivacy, deleteGroup, - createChannel, deleteChannel, updateChannel, createNavSection, From 0d8cbc17123c8980e479b326623e8adf91180ffb Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:16:57 -0700 Subject: [PATCH 146/259] Pull DraftInputView, PostView into own files --- .../src/components/Channel/DraftInputView.tsx | 15 +++++ .../ui/src/components/Channel/PostView.tsx | 51 +++++++++++++++ packages/ui/src/components/Channel/index.tsx | 64 +------------------ 3 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 packages/ui/src/components/Channel/DraftInputView.tsx create mode 100644 packages/ui/src/components/Channel/PostView.tsx diff --git a/packages/ui/src/components/Channel/DraftInputView.tsx b/packages/ui/src/components/Channel/DraftInputView.tsx new file mode 100644 index 0000000000..13e69d513c --- /dev/null +++ b/packages/ui/src/components/Channel/DraftInputView.tsx @@ -0,0 +1,15 @@ +import { DraftInputId } from '@tloncorp/shared'; + +import { useComponentsKitContext } from '../../contexts/componentsKits'; +import { DraftInputContext } from '../draftInputs'; + +export function DraftInputView(props: { + draftInputContext: DraftInputContext; + type: DraftInputId; +}) { + const { inputs } = useComponentsKitContext(); + const InputComponent = inputs[props.type]; + if (InputComponent) { + return ; + } +} diff --git a/packages/ui/src/components/Channel/PostView.tsx b/packages/ui/src/components/Channel/PostView.tsx new file mode 100644 index 0000000000..2ec91938c4 --- /dev/null +++ b/packages/ui/src/components/Channel/PostView.tsx @@ -0,0 +1,51 @@ +import { useMemo } from 'react'; + +import { useChannelContext } from '../../contexts'; +import { + RenderItemType, + useComponentsKitContext, +} from '../../contexts/componentsKits'; +import { ChatMessage } from '../ChatMessage'; +import { GalleryPost } from '../GalleryPost'; +import { NotebookPost } from '../NotebookPost'; + +export const PostView: RenderItemType = (props) => { + const channel = useChannelContext(); + const { renderers } = useComponentsKitContext(); + + const SpecificPostComponent = useMemo(() => { + // why do this iife? + // without it, TypeScript thinks the value from `renderers[]` may be null. + // sad! + const rendererFromContentConfig = (() => { + const contentConfig = channel.contentConfiguration; + if ( + contentConfig != null && + renderers[contentConfig.defaultPostContentRenderer] != null + ) { + return renderers[contentConfig.defaultPostContentRenderer]; + } + })(); + if (rendererFromContentConfig != null) { + return rendererFromContentConfig; + } + + // content config did not provide a renderer, fall back to default + switch (channel.type) { + case 'chat': + // fallthrough + case 'dm': + // fallthrough + case 'groupDm': + return ChatMessage; + + case 'notebook': + return NotebookPost; + + case 'gallery': + return GalleryPost; + } + }, [channel.type, channel.contentConfiguration, renderers]); + + return ; +}; diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 562fa80de7..4651ea3032 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -22,28 +22,22 @@ import { ChannelProvider, GroupsProvider, NavigationProvider, - useChannelContext, useCurrentUserId, } from '../../contexts'; import { Attachment, AttachmentProvider } from '../../contexts/attachment'; -import { - ComponentsKitContextProvider, - RenderItemType, - useComponentsKitContext, -} from '../../contexts/componentsKits'; +import { ComponentsKitContextProvider } from '../../contexts/componentsKits'; import { RequestsProvider } from '../../contexts/requests'; import { ScrollContextProvider } from '../../contexts/scroll'; import * as utils from '../../utils'; -import { ChatMessage } from '../ChatMessage'; -import { GalleryPost } from '../GalleryPost'; import { GroupPreviewAction, GroupPreviewSheet } from '../GroupPreviewSheet'; -import { NotebookPost } from '../NotebookPost'; import { DraftInputContext } from '../draftInputs'; import { DraftInputHandle, GalleryDraftType } from '../draftInputs/shared'; import { ChannelFooter } from './ChannelFooter'; import { ChannelHeader, ChannelHeaderItemsProvider } from './ChannelHeader'; import { DmInviteOptions } from './DmInviteOptions'; +import { DraftInputView } from './DraftInputView'; import { EmptyChannelNotice } from './EmptyChannelNotice'; +import { PostView } from './PostView'; import Scroller, { ScrollAnchor } from './Scroller'; export { INITIAL_POSTS_PER_PAGE } from './Scroller'; @@ -450,55 +444,3 @@ function NegotionMismatchNotice() { ); } - -const PostView: RenderItemType = (props) => { - const channel = useChannelContext(); - const { renderers } = useComponentsKitContext(); - - const SpecificPostComponent = useMemo(() => { - // why do this iife? - // without it, TypeScript thinks the value from `renderers[]` may be null. - // sad! - const rendererFromContentConfig = (() => { - const contentConfig = channel.contentConfiguration; - if ( - contentConfig != null && - renderers[contentConfig.defaultPostContentRenderer] != null - ) { - return renderers[contentConfig.defaultPostContentRenderer]; - } - })(); - if (rendererFromContentConfig != null) { - return rendererFromContentConfig; - } - - // content config did not provide a renderer, fall back to default - switch (channel.type) { - case 'chat': - // fallthrough - case 'dm': - // fallthrough - case 'groupDm': - return ChatMessage; - - case 'notebook': - return NotebookPost; - - case 'gallery': - return GalleryPost; - } - }, [channel.type, channel.contentConfiguration, renderers]); - - return ; -}; - -function DraftInputView(props: { - draftInputContext: DraftInputContext; - type: DraftInputId; -}) { - const { inputs } = useComponentsKitContext(); - const InputComponent = inputs[props.type]; - if (InputComponent) { - return ; - } -} From 4ec9a7af0e8b1a14954385c2614fcd6b0ba480bc Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 18 Oct 2024 14:27:00 -0500 Subject: [PATCH 147/259] detail views: fix bad layouts for comments --- .../src/types/PostCollectionConfiguration.ts | 15 ++++++++++++--- packages/ui/src/components/Channel/Scroller.tsx | 4 +++- packages/ui/src/components/DetailView.tsx | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 8054151368..8e6bf53d18 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -13,13 +13,16 @@ export type PostCollectionLayoutType = // If the caller has a non-nullable `channel`, they can then get a // non-nullable return value - nice, right? export function layoutTypeFromChannel( - channel: db.Channel + channel: db.Channel, + detailView?: boolean ): PostCollectionLayoutType; export function layoutTypeFromChannel( - channel: db.Channel | null + channel: db.Channel | null, + detailView?: boolean ): PostCollectionLayoutType | null; export function layoutTypeFromChannel( - channel: db.Channel | null + channel: db.Channel | null, + detailView?: boolean ): PostCollectionLayoutType | null { switch (channel?.type) { case null: @@ -35,9 +38,15 @@ export function layoutTypeFromChannel( return 'compact-list-bottom-to-top'; case 'notebook': + if (detailView) { + return 'compact-list-bottom-to-top'; + } return 'comfy-list-top-to-bottom'; case 'gallery': + if (detailView) { + return 'compact-list-bottom-to-top'; + } return 'grid'; } } diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 7652e0c79a..96518ade72 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -94,6 +94,7 @@ const Scroller = forwardRef( renderEmptyComponent: renderEmptyComponentFn, posts, channel, + detailView, firstUnreadId, unreadCount, onStartReached, @@ -118,6 +119,7 @@ const Scroller = forwardRef( renderEmptyComponent?: () => ReactElement; posts: db.Post[] | null; channel: db.Channel; + detailView?: boolean; firstUnreadId?: string | null; unreadCount?: number | null; onStartReached?: () => void; @@ -141,7 +143,7 @@ const Scroller = forwardRef( ref ) => { const collectionLayoutType = useMemo( - () => layoutTypeFromChannel(channel), + () => layoutTypeFromChannel(channel, detailView), [channel] ); const collectionLayout = useMemo( diff --git a/packages/ui/src/components/DetailView.tsx b/packages/ui/src/components/DetailView.tsx index dae316018f..86b3d0329d 100644 --- a/packages/ui/src/components/DetailView.tsx +++ b/packages/ui/src/components/DetailView.tsx @@ -64,6 +64,7 @@ export const DetailView = ({ inverted renderItem={ChatMessage} channel={channel} + detailView editingPost={editingPost} setEditingPost={setEditingPost} posts={resolvedPosts ?? null} @@ -97,6 +98,7 @@ export const DetailView = ({ setActiveMessage, setEditingPost, headerMode, + channel ]); return isChat ? ( From 63b274a2d1f62649cbd1000db3acb4a1f084d548 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:32:16 -0700 Subject: [PATCH 148/259] Fix import (from "packages/..." instead of package name) --- packages/app/features/top/GroupChannelsScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index da4a7de98a..08a8b30606 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -7,11 +7,11 @@ import { GroupChannelsScreenView, InviteUsersSheet, } from '@tloncorp/ui'; -import { useFeatureFlag } from 'packages/app/lib/featureFlags'; import { useCallback, useMemo, useState } from 'react'; import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation'; import { useGroupContext } from '../../hooks/useGroupContext'; +import { useFeatureFlag } from '../../lib/featureFlags'; import type { RootStackParamList } from '../../navigation/types'; type Props = NativeStackScreenProps; From 4eb0205923bce7058307320725ad3231c2aeac62 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:33:08 -0700 Subject: [PATCH 149/259] Revert code to reduce diff --- packages/app/features/top/GroupChannelsScreen.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index 08a8b30606..376ba7eb50 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -18,6 +18,7 @@ type Props = NativeStackScreenProps; export function GroupChannelsScreen({ navigation, route }: Props) { const groupParam = route.params.group; + const { id } = route.params.group; const isFocused = useIsFocused(); const { data: pins } = store.usePins({ @@ -26,7 +27,7 @@ export function GroupChannelsScreen({ navigation, route }: Props) { const [inviteSheetGroup, setInviteSheetGroup] = useState( null ); - const { group } = useGroupContext({ groupId: groupParam.id, isFocused }); + const { group } = useGroupContext({ groupId: id, isFocused }); const pinnedItems = useMemo(() => { return pins ?? []; From 5ec22c96ab627042b303ae332b426799b18e2e56 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:35:49 -0700 Subject: [PATCH 150/259] Add documentation --- packages/shared/src/db/modelBuilders.ts | 12 ++++++++++++ packages/shared/src/store/channelActions.ts | 5 +++++ packages/shared/src/store/useCreateChannel.ts | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/packages/shared/src/db/modelBuilders.ts b/packages/shared/src/db/modelBuilders.ts index ce5cb9d5e8..d4ea3eaac6 100644 --- a/packages/shared/src/db/modelBuilders.ts +++ b/packages/shared/src/db/modelBuilders.ts @@ -327,6 +327,18 @@ interface ChatMembersBuilder { build(): db.ChatMember[]; } +/** + * Build a list of chat members, specifying common fields in one place. + * + * ```ts + * const channel = { + * members: buildChatMembers({ chatId: '1', membershipType: 'channel' }) + * .add({ contactId: '2', status: 'joined' }) + * .add({ contactId: '3', status: 'invited' }) + * .build() + * }; + * ``` + */ export function buildChatMembers( commonFields: Pick ): ChatMembersBuilder { diff --git a/packages/shared/src/store/channelActions.ts b/packages/shared/src/store/channelActions.ts index 385aa7448f..137b6b762e 100644 --- a/packages/shared/src/store/channelActions.ts +++ b/packages/shared/src/store/channelActions.ts @@ -15,6 +15,8 @@ export async function createChannel({ channelId, name, title, + // Alias to `rawDescription`, since we might need to synthesize a new + // `description` API value by merging with `contentConfiguration` below. description: rawDescription, channelType, contentConfiguration, @@ -40,6 +42,9 @@ export async function createChannel({ }; await db.insertChannels([newChannel]); + // If we have a `contentConfiguration`, we need to merge these fields to make + // a `StructuredChannelDescriptionPayload`, and use that as the `description` + // on the API. const encodedDescription = contentConfiguration == null ? rawDescription diff --git a/packages/shared/src/store/useCreateChannel.ts b/packages/shared/src/store/useCreateChannel.ts index c1f7a9cc98..5300bc9403 100644 --- a/packages/shared/src/store/useCreateChannel.ts +++ b/packages/shared/src/store/useCreateChannel.ts @@ -61,6 +61,12 @@ export function useCreateChannel({ ); } +/** + * Creates a `ChannelContentConfiguration` matching our built-in legacy + * channel types. With this configuration in place, we can treat these channels + * as we would any other custom channel, and avoid switching on `channel.type` + * in client code. + */ function channelContentConfigurationForChannelType( channelType: Omit ): ChannelContentConfiguration { From 2ca0b4dc827d9cbc4ddc0b6839bb1c6c30a72e57 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:56:18 -0700 Subject: [PATCH 151/259] Remove picto message + input types --- apps/tlon-mobile/ios/Podfile.lock | 10 - apps/tlon-mobile/package.json | 1 - .../shared/src/api/channelContentConfig.ts | 2 - packages/ui/package.json | 1 - .../src/components/Channel/PictoMessage.tsx | 65 --- packages/ui/src/components/DrawingInput.tsx | 395 ------------------ .../ManageChannels/CreateChannelSheet.tsx | 6 - packages/ui/src/contexts/componentsKits.tsx | 4 - pnpm-lock.yaml | 66 +-- 9 files changed, 5 insertions(+), 545 deletions(-) delete mode 100644 packages/ui/src/components/Channel/PictoMessage.tsx delete mode 100644 packages/ui/src/components/DrawingInput.tsx diff --git a/apps/tlon-mobile/ios/Podfile.lock b/apps/tlon-mobile/ios/Podfile.lock index 3acf3c9558..30d0aadb52 100644 --- a/apps/tlon-mobile/ios/Podfile.lock +++ b/apps/tlon-mobile/ios/Podfile.lock @@ -1161,12 +1161,6 @@ PODS: - React-Core - react-native-safe-area-context (4.9.0): - React-Core - - react-native-skia (1.4.2): - - glog - - RCT-Folly (= 2022.05.16.00) - - React - - React-callinvoker - - React-Core - react-native-webview (13.6.4): - glog - RCT-Folly (= 2022.05.16.00) @@ -1471,7 +1465,6 @@ DEPENDENCIES: - react-native-get-random-values (from `../../../node_modules/react-native-get-random-values`) - "react-native-netinfo (from `../../../node_modules/@react-native-community/netinfo`)" - react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`) - - "react-native-skia (from `../../../node_modules/@shopify/react-native-skia`)" - react-native-webview (from `../../../node_modules/react-native-webview`) - React-nativeconfig (from `../../../node_modules/react-native/ReactCommon`) - React-NativeModulesApple (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) @@ -1679,8 +1672,6 @@ EXTERNAL SOURCES: :path: "../../../node_modules/@react-native-community/netinfo" react-native-safe-area-context: :path: "../../../node_modules/react-native-safe-area-context" - react-native-skia: - :path: "../../../node_modules/@shopify/react-native-skia" react-native-webview: :path: "../../../node_modules/react-native-webview" React-nativeconfig: @@ -1846,7 +1837,6 @@ SPEC CHECKSUMS: react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06 react-native-netinfo: 3aa5637c18834966e0c932de8ae1ae56fea20a97 react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b - react-native-skia: c7d8d8a380d4dbf8463343e2738bceaf49a9c084 react-native-webview: ad868affda04ff2b204de83546193bc0325a8280 React-nativeconfig: 44cd3076b158c39cb6758f238cd3e65953e989c0 React-NativeModulesApple: af58ca346cf42c3bb4dab9173b6edd0c83c2a21c diff --git a/apps/tlon-mobile/package.json b/apps/tlon-mobile/package.json index aa17fc9b10..9a8e3707a2 100644 --- a/apps/tlon-mobile/package.json +++ b/apps/tlon-mobile/package.json @@ -56,7 +56,6 @@ "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", "@shopify/flash-list": "1.6.3", - "@shopify/react-native-skia": "^1.3.9", "@tanstack/react-query": "~5.32.1", "@tloncorp/app": "workspace:*", "@tloncorp/editor": "workspace:*", diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index 6e4a4ba53e..0e93e7b93b 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -8,7 +8,6 @@ export enum DraftInputId { notebook = 'tlon.r0.input.notebook', chat = 'tlon.r0.input.chat', gallery = 'tlon.r0.input.gallery', - picto = 'tlon.r0.input.picto', yo = 'tlon.r0.input.yo', } @@ -16,7 +15,6 @@ export enum PostContentRendererId { notebook = 'tlon.r0.content.notebook', chat = 'tlon.r0.content.chat', gallery = 'tlon.r0.content.gallery', - picto = 'tlon.r0.content.picto', } /** diff --git a/packages/ui/package.json b/packages/ui/package.json index c16fdf7c20..d04420478e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -53,7 +53,6 @@ }, "peerDependencies": { "@10play/tentap-editor": "~0.5.11", - "@shopify/react-native-skia": "^1.3.9", "@urbit/sigil-js": "^2.2.0", "expo-image": "*", "react": "*", diff --git a/packages/ui/src/components/Channel/PictoMessage.tsx b/packages/ui/src/components/Channel/PictoMessage.tsx deleted file mode 100644 index e7c4068d7f..0000000000 --- a/packages/ui/src/components/Channel/PictoMessage.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { extractContentTypesFromPost } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import * as ub from '@tloncorp/shared/dist/urbit'; -import { Story } from '@tloncorp/shared/dist/urbit'; -import { useMemo } from 'react'; -import { Image, View, XStack } from 'tamagui'; - -import { useContact } from '../../contexts'; -import { ContactAvatar } from '../Avatar'; -import ContactName from '../ContactName'; - -export function PictoMessage({ - post, -}: { - post: db.Post; - showAuthor?: boolean; - showReplies?: boolean; - onPress?: (post: db.Post) => void; - onPressReplies?: (post: db.Post) => void; - onPressImage?: (post: db.Post, imageUri?: string) => void; - onLongPress?: (post: db.Post) => void; - editing?: boolean; - setEditingPost?: (post: db.Post | undefined) => void; - editPost?: (post: db.Post, content: Story) => Promise; - onPressRetry: (post: db.Post) => void; - onPressDelete: (post: db.Post) => void; -}) { - const image = useMemo(() => { - const content = extractContentTypesFromPost(post); - return content.blocks.find((b): b is ub.Image => 'image' in b); - }, [post]); - const postContact = useContact(post.authorId); - - if (!image) return null; - return ( - - - - - - - - - - ); -} diff --git a/packages/ui/src/components/DrawingInput.tsx b/packages/ui/src/components/DrawingInput.tsx deleted file mode 100644 index 044f296913..0000000000 --- a/packages/ui/src/components/DrawingInput.tsx +++ /dev/null @@ -1,395 +0,0 @@ -import * as sk from '@shopify/react-native-skia'; -import { Skia } from '@shopify/react-native-skia'; -import * as db from '@tloncorp/shared/dist/db'; -import { Story } from '@tloncorp/shared/dist/urbit'; -import * as FileSystem from 'expo-file-system'; -import { - ComponentProps, - useCallback, - useEffect, - useRef, - useState, -} from 'react'; -import { Gesture, GestureDetector } from 'react-native-gesture-handler'; -import { - interpolate, - useDerivedValue, - useSharedValue, - withTiming, -} from 'react-native-reanimated'; -import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { styled } from 'tamagui'; -import { View, XStack, YStack } from 'tamagui'; - -import { UploadedImageAttachment, useAttachmentContext } from '../contexts'; -import { ActionSheet } from './ActionSheet'; -import { Button } from './Button'; -import { Icon } from './Icon'; -import { Sheet } from './Sheet'; -import { DraftInputContext } from './draftInputs'; - -const pixelated = Skia.RuntimeEffect.Make(` - uniform vec2 amount; // number of pixels per axis - uniform vec2 resolution; - uniform shader image; - - half4 main(vec2 uv) { - vec2 blockSize = resolution / amount; - vec2 coord = floor((floor(uv / blockSize) + 0.5) * blockSize); - return floor(image.eval(coord) + .25); - }`)!; - -const rec = Skia.PictureRecorder(); -rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1)); -const emptyPicture = rec.finishRecordingAsPicture(); - -const drawPaint = Skia.Paint(); -drawPaint.setColor(Skia.Color(0xff000000)); -drawPaint.setAntiAlias(false); -drawPaint.setStrokeWidth(10); -drawPaint.setStyle(sk.PaintStyle.Stroke); -drawPaint.setStrokeCap(sk.StrokeCap.Round); -drawPaint.setStrokeJoin(sk.StrokeJoin.Round); - -const erasePaint = Skia.Paint(); -erasePaint.setColor(Skia.Color(0xffffffff)); -erasePaint.setAntiAlias(false); -erasePaint.setStrokeWidth(10); -erasePaint.setStyle(sk.PaintStyle.Stroke); - -const renderPath = ( - path: sk.SkPath, - paint: sk.SkPaint, - lastPicture?: sk.SkPicture -) => { - 'worklet'; - const recorder = Skia.PictureRecorder(); - const canvas = recorder.beginRecording( - Skia.XYWHRect(0, 0, 2_000_000, 2_000_000) - ); - if (lastPicture) { - canvas.drawPicture(lastPicture); - } - canvas.drawPath(path, paint); - return recorder.finishRecordingAsPicture(); -}; - -const brushSizes = [4, 10]; - -export const DrawingInput = ({ - filter, - onPressAttach, - inputAspect, - finishedAction = 'attach', -}: { - filter?: 'pixel'; - onPressAttach: () => void; - inputAspect?: number; - finishedAction: 'attach' | 'send'; -}) => { - const currentPath = useSharedValue(Skia.Path.Make()); - const isDrawing = useSharedValue(false); - const pointerPosition = useSharedValue({ x: 0, y: 0 }); - const picture = useSharedValue(emptyPicture); - const canvasRef = useRef(null); - - const [tool, setTool] = useState<'draw' | 'erase'>('draw'); - const [size, setSize] = useState<'small' | 'large'>('small'); - const paintRef = useSharedValue(drawPaint); - const canvasSize = useSharedValue({ width: 0, height: 0 }); - const pan = Gesture.Pan() - .averageTouches(true) - .minDistance(0) - .shouldCancelWhenOutside(false) - .maxPointers(1) - .onBegin((e) => { - currentPath.value.reset(); - currentPath.value.moveTo(e.x, e.y); - console.log('begin'); - isDrawing.value = true; - pointerPosition.value = { x: e.x, y: e.y }; - }) - .onChange((e) => { - pointerPosition.value = { - x: interpolate(0.4, [0, 1], [pointerPosition.value.x, e.x]), - y: interpolate(0.4, [0, 1], [pointerPosition.value.y, e.y]), - }; - currentPath.value.lineTo( - pointerPosition.value.x, - pointerPosition.value.y - ); - sk.notifyChange(currentPath); - pointerPosition.value = { x: e.x, y: e.y }; - }) - .onEnd(() => { - console.log('end', tool); - picture.value = renderPath( - currentPath.value, - paintRef.value, - picture.value - ); - currentPath.value.reset(); - sk.notifyChange(currentPath); - isDrawing.value = false; - }); - - const [w, h] = [142, 256]; - const scale = 3; - const uniforms = { - amount: [w / scale, h / scale], // grid 20x20; - resolution: [142, 256], - }; - - useEffect(() => { - if (size === 'small') { - paintRef.value.setStrokeWidth(brushSizes[0]); - } else { - paintRef.value.setStrokeWidth(brushSizes[1]); - } - if (tool === 'draw') { - paintRef.value.setColor(Skia.Color(0xff000000)); - } else { - paintRef.value.setColor(Skia.Color(0xffffffff)); - } - sk.notifyChange(paintRef); - }, [tool, size, paintRef]); - - const handlePressErase = useCallback(() => { - setTool(`erase`); - }, []); - - const handlePressDraw = useCallback(() => { - setTool(`draw`); - }, []); - - const handlePressSizeLarge = useCallback(() => { - setSize(`large`); - }, []); - - const handlePressSizeSmall = useCallback(() => { - setSize('small'); - }, []); - - const handlePressClear = useCallback(() => { - picture.value = emptyPicture; - }, [picture]); - - const [isAttaching, setIsAttaching] = useState(false); - const { attachAssets, attachments } = useAttachmentContext(); - const translateY = useSharedValue(0); - const transform = useDerivedValue(() => { - return [{ translateY: translateY.value }]; - }, [translateY]); - - const handlePressAttach = useCallback(async () => { - const result = await canvasRef.current?.makeImageSnapshotAsync(); - const str = result?.encodeToBase64(); - const uri = FileSystem.cacheDirectory + `drawing-${Date.now()}.png`; - await FileSystem.writeAsStringAsync(uri, str ?? '', { - encoding: 'base64', - }); - attachAssets([ - { - type: 'image', - uri, - width: Math.round(canvasSize.value.width), - height: Math.round(canvasSize.value.height), - }, - ]); - setIsAttaching(true); - }, [attachAssets, canvasSize]); - - useEffect(() => { - if (attachments.length && isAttaching) { - setIsAttaching(false); - translateY.value = withTiming( - -canvasSize.value.height, - { duration: 300 }, - () => { - picture.value = emptyPicture; - translateY.value = 0; - } - ); - onPressAttach(); - } - }, [ - attachments, - handlePressClear, - isAttaching, - onPressAttach, - canvasSize, - picture, - translateY, - ]); - - return ( - - - - - - - - ) : undefined - } - > - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -const IconGroup = styled(XStack, { - borderColor: '$border', - borderWidth: 1, - alignItems: 'center', - borderRadius: '$s', - overflow: 'hidden', -}); - -const ToolbarIcon = styled(Icon, { - width: '$3xl', - height: '$3xl', - color: '$tertiaryText', - variants: { - isSelected: { - true: { - color: '$primaryText', - borderColor: '$activeBorder', - backgroundColor: '$secondaryBackground', - }, - }, - } as const, -}); - -export function StandaloneDrawingInput({ - draftInputContext: { - channel, - send: onSend - }, -}: { - draftInputContext: DraftInputContext; -}) { - const { waitForAttachmentUploads, clearAttachments } = useAttachmentContext(); - const handleDrawingAttached = useCallback(async () => { - const finalAttachments = await waitForAttachmentUploads(); - const imageAttachment = finalAttachments.find( - (f): f is UploadedImageAttachment => f.type === 'image' - ); - clearAttachments(); - if (imageAttachment) { - await onSend?.( - [ - { - block: { - image: { - src: imageAttachment.uploadState.remoteUri, - width: imageAttachment.file.width, - height: imageAttachment.file.height, - alt: '', - }, - }, - }, - ], - channel.id - ); - } else { - throw new Error('no image'); - } - }, [clearAttachments, channel.id, onSend, waitForAttachmentUploads]); - - const { bottom } = useSafeAreaInsets(); - - return ( - - - - ); -} - -export function SheetDrawingInput({ - onFinished, - ...props -}: ComponentProps & { - onFinished: () => void; -}) { - return ( - - - - - - ); -} diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index a839795de9..9b7ab6db2e 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -158,8 +158,6 @@ function labelForDraftInput(draftInputId: DraftInputId): string { return 'Gallery'; case DraftInputId.notebook: return 'Notebook'; - case DraftInputId.picto: - return 'Drawing'; case DraftInputId.yo: return 'Yo'; } @@ -172,8 +170,6 @@ function labelForContentRenderer(r: PostContentRendererId): string { return 'Gallery'; case PostContentRendererId.notebook: return 'Notebook'; - case PostContentRendererId.picto: - return 'Drawing'; } } function labelForCollectionLayout(l: CollectionRendererId): string { @@ -204,7 +200,6 @@ const CustomChannelConfigurationForm = forwardRef<{ DraftInputId.chat, DraftInputId.gallery, DraftInputId.notebook, - DraftInputId.picto, DraftInputId.yo, ].map((id) => ({ title: labelForDraftInput(id), @@ -214,7 +209,6 @@ const CustomChannelConfigurationForm = forwardRef<{ PostContentRendererId.chat, PostContentRendererId.gallery, PostContentRendererId.notebook, - PostContentRendererId.picto, ].map((id) => ({ title: labelForContentRenderer(id), value: id, diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index 191172b8f2..7d08e9e0d6 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -3,9 +3,7 @@ import * as db from '@tloncorp/shared/dist/db'; import { Story } from '@tloncorp/shared/dist/urbit'; import { ReactElement, createContext, useContext, useMemo } from 'react'; -import { PictoMessage } from '../components/Channel/PictoMessage'; import { ChatMessage } from '../components/ChatMessage'; -import { StandaloneDrawingInput } from '../components/DrawingInput'; import { GalleryPost } from '../components/GalleryPost'; import { NotebookPost } from '../components/NotebookPost'; import { @@ -66,13 +64,11 @@ const BUILTIN_CONTENT_RENDERERS: { [id: string]: RenderItemType } = { [PostContentRendererId.chat]: ChatMessage, [PostContentRendererId.gallery]: GalleryPost, [PostContentRendererId.notebook]: NotebookPost, - [PostContentRendererId.picto]: PictoMessage, }; const BUILTIN_DRAFT_INPUTS: { [id: string]: DraftInputRendererComponent } = { [DraftInputId.chat]: ChatInput, [DraftInputId.gallery]: GalleryInput, [DraftInputId.notebook]: NotebookInput, - [DraftInputId.picto]: StandaloneDrawingInput, [DraftInputId.yo]: ({ draftInputContext }) => ( =18.0' - react-native: '>=0.64' - react-native-reanimated: '>=2.0.0' - peerDependenciesMeta: - react-native: - optional: true - react-native-reanimated: - optional: true - '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -6725,9 +6706,6 @@ packages: '@vitest/utils@1.5.0': resolution: {integrity: sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==} - '@webgpu/types@0.1.21': - resolution: {integrity: sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow==} - '@welldone-software/why-did-you-render@7.0.1': resolution: {integrity: sha512-Qe/8Xxa2G+LMdI6VoazescPzjjkHYduCDa8aHOJR50e9Bgs8ihkfMBY+ev7B4oc3N59Zm547Sgjf8h5y0FOyoA==} peerDependencies: @@ -7314,9 +7292,6 @@ packages: caniuse-lite@1.0.30001650: resolution: {integrity: sha512-fgEc7hP/LB7iicdXHUI9VsBsMZmUmlVJeQP2qqQW+3lkqVhbmjEU8zp+h5stWeilX+G7uXuIUIIlWlDw9jdt8g==} - canvaskit-wasm@0.39.1: - resolution: {integrity: sha512-Gy3lCmhUdKq+8bvDrs9t8+qf7RvcjuQn+we7vTVVyqgOVO1UVfHpsnBxkTZw+R4ApEJ3D5fKySl9TU11hmjl/A==} - chai@4.4.1: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} @@ -11671,12 +11646,6 @@ packages: react-native-svg: optional: true - react-reconciler@0.27.0: - resolution: {integrity: sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==} - engines: {node: '>=0.10.0'} - peerDependencies: - react: ^18.0.0 - react-redux@7.2.8: resolution: {integrity: sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==} peerDependencies: @@ -12073,9 +12042,6 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.21.0: - resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} - scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} @@ -18821,7 +18787,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': + '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native/js-polyfills': 0.73.1 '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -18830,7 +18796,10 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' + - bufferutil + - encoding - supports-color + - utf-8-validate '@react-native/normalize-color@2.1.0': {} @@ -19009,15 +18978,6 @@ snapshots: recyclerlistview: 4.2.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) tslib: 2.4.0 - '@shopify/react-native-skia@1.4.2(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': - dependencies: - canvaskit-wasm: 0.39.1 - react: 18.2.0 - react-reconciler: 0.27.0(react@18.2.0) - optionalDependencies: - react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) - react-native-reanimated: 3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -21305,8 +21265,6 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - '@webgpu/types@0.1.21': {} - '@welldone-software/why-did-you-render@7.0.1(react@18.2.0)': dependencies: lodash: 4.17.21 @@ -22061,10 +22019,6 @@ snapshots: caniuse-lite@1.0.30001650: {} - canvaskit-wasm@0.39.1: - dependencies: - '@webgpu/types': 0.1.21 - chai@4.4.1: dependencies: assertion-error: 1.1.0 @@ -27529,12 +27483,6 @@ snapshots: optionalDependencies: react-native-svg: 15.0.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-reconciler@0.27.0(react@18.2.0): - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.21.0 - react-redux@7.2.8(react-dom@18.2.0(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.23.8 @@ -27984,10 +27932,6 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.21.0: - dependencies: - loose-envify: 1.4.0 - scheduler@0.23.0: dependencies: loose-envify: 1.4.0 From 38e51aab98d6a2db48fc4a73f8878da070734f79 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 12:58:17 -0700 Subject: [PATCH 152/259] Remove button / yo input --- .../shared/src/api/channelContentConfig.ts | 1 - .../ManageChannels/CreateChannelSheet.tsx | 3 -- .../components/draftInputs/ButtonInput.tsx | 41 ------------------- packages/ui/src/contexts/componentsKits.tsx | 8 ---- 4 files changed, 53 deletions(-) delete mode 100644 packages/ui/src/components/draftInputs/ButtonInput.tsx diff --git a/packages/shared/src/api/channelContentConfig.ts b/packages/shared/src/api/channelContentConfig.ts index 0e93e7b93b..35f5b89fcb 100644 --- a/packages/shared/src/api/channelContentConfig.ts +++ b/packages/shared/src/api/channelContentConfig.ts @@ -8,7 +8,6 @@ export enum DraftInputId { notebook = 'tlon.r0.input.notebook', chat = 'tlon.r0.input.chat', gallery = 'tlon.r0.input.gallery', - yo = 'tlon.r0.input.yo', } export enum PostContentRendererId { diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 9b7ab6db2e..a30d595b8d 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -158,8 +158,6 @@ function labelForDraftInput(draftInputId: DraftInputId): string { return 'Gallery'; case DraftInputId.notebook: return 'Notebook'; - case DraftInputId.yo: - return 'Yo'; } } function labelForContentRenderer(r: PostContentRendererId): string { @@ -200,7 +198,6 @@ const CustomChannelConfigurationForm = forwardRef<{ DraftInputId.chat, DraftInputId.gallery, DraftInputId.notebook, - DraftInputId.yo, ].map((id) => ({ title: labelForDraftInput(id), value: id, diff --git a/packages/ui/src/components/draftInputs/ButtonInput.tsx b/packages/ui/src/components/draftInputs/ButtonInput.tsx deleted file mode 100644 index 64b061600e..0000000000 --- a/packages/ui/src/components/draftInputs/ButtonInput.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { SafeAreaView } from 'react-native-safe-area-context'; -import { Button, View } from 'tamagui'; - -import { DraftInputContext } from './shared'; - -export function ButtonInput({ - draftInputContext, - messageText, - labelText, -}: { - draftInputContext: DraftInputContext; - messageText: string; - labelText: string; -}) { - return ( - - - - ); -} diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index 7d08e9e0d6..2d3714d85f 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -12,7 +12,6 @@ import { GalleryInput, NotebookInput, } from '../components/draftInputs'; -import { ButtonInput } from '../components/draftInputs/ButtonInput'; type RenderItemFunction = (props: { post: db.Post; @@ -69,13 +68,6 @@ const BUILTIN_DRAFT_INPUTS: { [id: string]: DraftInputRendererComponent } = { [DraftInputId.chat]: ChatInput, [DraftInputId.gallery]: GalleryInput, [DraftInputId.notebook]: NotebookInput, - [DraftInputId.yo]: ({ draftInputContext }) => ( - - ), }; export function ComponentsKitContextProvider({ From f9fccc6127405f27400f6cb855fdbd9260639cc4 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 13:09:08 -0700 Subject: [PATCH 153/259] Reduce pnpm-lock.yaml thrashing --- pnpm-lock.yaml | 1115 ++++-------------------------------------------- 1 file changed, 88 insertions(+), 1027 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74c7296028..478ed1bd5d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,7 +92,7 @@ importers: version: 8.0.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(postcss@8.4.35)(typescript@5.4.5) vitest: specifier: ^1.2.2 - version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) + version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) apps/tlon-mobile: dependencies: @@ -257,7 +257,7 @@ importers: version: 4.17.21 posthog-react-native: specifier: ^2.7.1 - version: 2.11.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(expo-application@5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-device@5.9.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-file-system@16.0.9(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-localization@14.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(react-native-device-info@10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))) + version: 2.11.3(jwrxiw3lzqzjxcpw4mvkvmmdfa) react: specifier: ^18.2.0 version: 18.2.0 @@ -342,7 +342,7 @@ importers: version: 29.7.0 '@react-native/metro-config': specifier: ^0.73.5 - version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13) + version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) '@tamagui/babel-plugin': specifier: ~1.112.12 version: 1.112.12(@swc/helpers@0.5.13)(encoding@0.1.13)(react@18.2.0) @@ -426,7 +426,7 @@ importers: version: 3.4.1 vitest: specifier: ^1.0.4 - version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) + version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) apps/tlon-web: dependencies: @@ -798,7 +798,7 @@ importers: version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) + version: 4.2.0(rollup@2.79.1)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) workbox-precaching: specifier: ^6.5.4 version: 6.6.0 @@ -889,10 +889,10 @@ importers: version: 2.0.1 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) + version: 1.1.0(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) '@welldone-software/why-did-you-render': specifier: ^7.0.1 version: 7.0.1(react@18.2.0) @@ -934,7 +934,7 @@ importers: version: 6.1.1 react-cosmos-plugin-vite: specifier: 6.1.1 - version: 6.1.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) + version: 6.1.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -943,7 +943,7 @@ importers: version: 4.0.0 rollup-plugin-visualizer: specifier: ^5.6.0 - version: 5.12.0(rollup@4.13.0) + version: 5.12.0(rollup@2.79.1) tailwindcss: specifier: ^3.2.7 version: 3.4.1 @@ -958,13 +958,13 @@ importers: version: 1.1.4(typescript@5.4.5) vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + version: 5.1.6(@types/node@20.10.8)(terser@5.19.1) vite-plugin-pwa: specifier: ^0.17.5 - version: 0.17.5(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) + version: 0.17.5(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) vitest: specifier: ^0.34.1 - version: 0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) + version: 0.34.6(jsdom@23.2.0)(terser@5.19.1) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -1348,7 +1348,7 @@ importers: version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) + version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) workbox-precaching: specifier: ^6.5.4 version: 6.6.0 @@ -1442,10 +1442,10 @@ importers: version: 2.0.1 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) + version: 1.1.0(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) '@welldone-software/why-did-you-render': specifier: ^7.0.1 version: 7.0.1(react@18.2.0) @@ -1490,7 +1490,7 @@ importers: version: 6.1.1 react-cosmos-plugin-vite: specifier: 6.1.1 - version: 6.1.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) + version: 6.1.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -1514,13 +1514,13 @@ importers: version: 1.1.4(typescript@5.4.5) vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + version: 5.1.6(@types/node@20.14.10)(terser@5.19.1) vite-plugin-pwa: specifier: ^0.17.5 - version: 0.17.5(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) + version: 0.17.5(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) vitest: specifier: ^0.34.1 - version: 0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) + version: 0.34.6(jsdom@23.2.0)(terser@5.19.1) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -1566,7 +1566,7 @@ importers: dependencies: '@10play/tentap-editor': specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1591,7 +1591,7 @@ importers: version: 6.21.0(eslint@8.56.0)(typescript@5.4.5) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) eslint: specifier: ^8.50.0 version: 8.56.0 @@ -1603,13 +1603,13 @@ importers: version: 5.4.5 vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + version: 5.1.6(@types/node@20.14.10)(terser@5.19.1) vite-plugin-singlefile: specifier: ^2.0.1 - version: 2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) + version: 2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) vitest: specifier: ^1.0.4 - version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) + version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) packages/shared: dependencies: @@ -1680,7 +1680,7 @@ importers: version: 5.4.5 vitest: specifier: ^1.4.0 - version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) + version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) packages/ui: dependencies: @@ -13669,43 +13669,6 @@ packages: snapshots: - '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': - dependencies: - '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-bold': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-bullet-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-code': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-code-block': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) - '@tiptap/extension-document': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-heading': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-history': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-horizontal-rule': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-italic': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-link': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-list-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-ordered-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-placeholder': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-strike': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-task-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-task-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/pm': 2.6.6 - '@tiptap/react': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) - lodash: 4.17.21 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) - react-native-webview: 13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - transitivePeerDependencies: - - '@tiptap/core' - '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) @@ -14599,19 +14562,6 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14625,13 +14575,6 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.24.7 - regexpu-core: 5.3.2 - semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14639,17 +14582,6 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.4 - transitivePeerDependencies: - - supports-color - '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14661,17 +14593,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.4 - transitivePeerDependencies: - - supports-color - '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14718,16 +14639,6 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - '@babel/traverse': 7.25.6 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14746,13 +14657,6 @@ snapshots: '@babel/helper-plugin-utils@7.24.8': {} - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14760,13 +14664,6 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 - '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14849,23 +14746,11 @@ snapshots: dependencies: '@babel/types': 7.25.6 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14873,26 +14758,12 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.25.2) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14901,12 +14772,6 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14920,12 +14785,6 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14938,39 +14797,18 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7)': - dependencies: - '@babel/compat-data': 7.25.2 - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -14980,25 +14818,12 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15006,19 +14831,10 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15029,21 +14845,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15054,81 +14860,41 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15139,136 +14905,67 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15277,15 +14974,6 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15295,45 +14983,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7)': + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - - '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': - dependencies: - '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.24.8 - - '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15341,18 +15006,6 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) - '@babel/helper-split-export-declaration': 7.22.6 - globals: 11.12.0 - '@babel/plugin-transform-classes@7.23.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15365,117 +15018,58 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 - '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/template': 7.25.0 - '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 - '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.25.2 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15483,58 +15077,28 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15543,15 +15107,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-simple-access': 7.22.5 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15561,16 +15116,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-validator-identifier': 7.22.20 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15581,14 +15126,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15597,61 +15134,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) - '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15661,37 +15166,18 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) - '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.25.2) - '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15699,36 +15185,17 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) - '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15737,21 +15204,11 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) - '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15793,17 +15250,6 @@ snapshots: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) '@babel/types': 7.25.6 - '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.24.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) - '@babel/types': 7.25.6 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15821,40 +15267,17 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - regenerator-transform: 0.15.2 - '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-plugin-utils': 7.24.8 - babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) - babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.7) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15867,66 +15290,32 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-spread@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15935,138 +15324,29 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.25.2) - '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/preset-env@7.23.7(@babel/core@7.23.7)': - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.23.7 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.23.7) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.23.7) - '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) - '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) - babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) - babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) - core-js-compat: 3.35.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/preset-env@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -16160,13 +15440,6 @@ snapshots: '@babel/helper-validator-option': 7.24.8 '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.25.2) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7)': - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/types': 7.25.6 - esutils: 2.0.3 - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -18543,13 +17816,6 @@ snapshots: '@react-native/assets-registry@0.73.1': {} - '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -18557,54 +17823,6 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/babel-preset@0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.23.7) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) - '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-react-jsx': 7.25.2(@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) - '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.23.7) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) - '@babel/template': 7.25.0 - '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.23.7) - react-refresh: 0.14.0 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - '@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -18653,19 +17871,6 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@babel/parser': 7.25.3 - '@babel/preset-env': 7.23.7(@babel/core@7.23.7) - flow-parser: 0.206.0 - glob: 7.2.3 - invariant: 2.2.4 - jscodeshift: 0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - mkdirp: 0.5.6 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/parser': 7.25.3 @@ -18700,27 +17905,6 @@ snapshots: - supports-color - utf-8-validate - '@react-native/community-cli-plugin@0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)': - dependencies: - '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) - '@react-native-community/cli-tools': 12.3.7(encoding@0.1.13) - '@react-native/dev-middleware': 0.73.8(encoding@0.1.13) - '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - chalk: 4.1.2 - execa: 5.1.1 - metro: 0.80.5(encoding@0.1.13) - metro-config: 0.80.5(encoding@0.1.13) - metro-core: 0.80.5 - node-fetch: 2.6.12(encoding@0.1.13) - readline: 1.3.0 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - bufferutil - - encoding - - supports-color - - utf-8-validate - '@react-native/community-cli-plugin@0.73.18(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) @@ -18767,16 +17951,6 @@ snapshots: '@react-native/js-polyfills@0.73.1': {} - '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': - dependencies: - '@babel/core': 7.23.7 - '@react-native/babel-preset': 0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - hermes-parser: 0.15.0 - nullthrows: 1.1.1 - transitivePeerDependencies: - - '@babel/preset-env' - - supports-color - '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -18787,7 +17961,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': + '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/js-polyfills': 0.73.1 '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -18796,10 +17970,7 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' - - bufferutil - - encoding - supports-color - - utf-8-validate '@react-native/normalize-color@2.1.0': {} @@ -18807,12 +17978,6 @@ snapshots: '@react-native/normalize-colors@0.74.84': {} - '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) - '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))': dependencies: invariant: 2.2.4 @@ -18915,6 +18080,14 @@ snapshots: picomatch: 2.3.1 rollup: 2.79.1 + '@rollup/pluginutils@5.1.0(rollup@2.79.1)': + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 2.79.1 + '@rollup/pluginutils@5.1.0(rollup@4.13.0)': dependencies: '@types/estree': 1.0.5 @@ -21149,33 +20322,33 @@ snapshots: graphql: 15.8.0 wonka: 4.0.15 - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))': dependencies: - vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))': dependencies: - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) - '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))': + '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))': 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.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))': + '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))': 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.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) transitivePeerDependencies: - supports-color @@ -21641,15 +20814,6 @@ snapshots: cosmiconfig: 7.1.0 resolve: 1.22.4 - babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.7): - dependencies: - '@babel/compat-data': 7.25.2 - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.25.2): dependencies: '@babel/compat-data': 7.25.2 @@ -21659,14 +20823,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) - core-js-compat: 3.35.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -21675,14 +20831,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.7): - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) - core-js-compat: 3.35.1 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -21691,13 +20839,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.7): - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -21709,12 +20850,6 @@ snapshots: babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.23.7): - dependencies: - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) - transitivePeerDependencies: - - '@babel/core' - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2): dependencies: '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) @@ -25245,31 +24380,6 @@ snapshots: jsc-safe-url@0.2.4: {} - jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)): - dependencies: - '@babel/core': 7.25.2 - '@babel/parser': 7.25.6 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.25.2) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.25.2) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.25.2) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.25.2) - '@babel/preset-env': 7.23.7(@babel/core@7.23.7) - '@babel/preset-flow': 7.23.3(@babel/core@7.25.2) - '@babel/preset-typescript': 7.23.3(@babel/core@7.25.2) - '@babel/register': 7.23.7(@babel/core@7.25.2) - babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) - chalk: 4.1.2 - flow-parser: 0.206.0 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - neo-async: 2.6.2 - node-dir: 0.1.17 - recast: 0.21.5 - temp: 0.8.4 - write-file-atomic: 2.4.3 - transitivePeerDependencies: - - supports-color - jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.25.2)): dependencies: '@babel/core': 7.25.2 @@ -26616,8 +25726,8 @@ snapshots: dependencies: fflate: 0.4.8 - ? posthog-react-native@2.11.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(expo-application@5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-device@5.9.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-file-system@16.0.9(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-localization@14.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(react-native-device-info@10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))) - : optionalDependencies: + posthog-react-native@2.11.3(jwrxiw3lzqzjxcpw4mvkvmmdfa): + optionalDependencies: '@react-native-async-storage/async-storage': 1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)) '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) expo-application: 5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)) @@ -26960,17 +26070,17 @@ snapshots: react-cosmos-core: 6.1.1 react-cosmos-renderer: 6.1.1 - react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)): + react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)): dependencies: react-cosmos-core: 6.1.1 react-cosmos-dom: 6.1.1 - vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) - react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): + react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): dependencies: react-cosmos-core: 6.1.1 react-cosmos-dom: 6.1.1 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) react-cosmos-renderer@6.1.1: dependencies: @@ -27303,13 +26413,6 @@ snapshots: transitivePeerDependencies: - encoding - react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): - dependencies: - escape-string-regexp: 2.0.0 - invariant: 2.2.4 - react: 18.2.0 - react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) - react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: escape-string-regexp: 2.0.0 @@ -27371,55 +26474,6 @@ snapshots: - supports-color - utf-8-validate - react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0): - dependencies: - '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 12.3.7(encoding@0.1.13) - '@react-native-community/cli-platform-android': 12.3.7(encoding@0.1.13) - '@react-native-community/cli-platform-ios': 12.3.7(encoding@0.1.13) - '@react-native/assets-registry': 0.73.1 - '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) - '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13) - '@react-native/gradle-plugin': 0.73.4 - '@react-native/js-polyfills': 0.73.1 - '@react-native/normalize-colors': 0.73.2 - '@react-native/virtualized-lists': 0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0)) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - base64-js: 1.5.1 - chalk: 4.1.2 - deprecated-react-native-prop-types: 5.0.0 - event-target-shim: 5.0.1 - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - jest-environment-node: 29.7.0 - jsc-android: 250231.0.0 - memoize-one: 5.2.1 - metro-runtime: 0.80.5 - metro-source-map: 0.80.5 - mkdirp: 0.5.6 - nullthrows: 1.1.1 - pretty-format: 26.6.2 - promise: 8.3.0 - react: 18.2.0 - react-devtools-core: 4.28.5 - react-refresh: 0.14.0 - react-shallow-renderer: 16.15.0(react@18.2.0) - regenerator-runtime: 0.13.11 - scheduler: 0.24.0-canary-efb381bbf-20230505 - stacktrace-parser: 0.1.10 - whatwg-fetch: 3.6.20 - ws: 6.2.2 - yargs: 17.7.2 - transitivePeerDependencies: - - '@babel/core' - - '@babel/preset-env' - - bufferutil - - encoding - - supports-color - - utf-8-validate - react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0): dependencies: '@jest/create-cache-key-function': 29.7.0 @@ -27837,6 +26891,15 @@ snapshots: serialize-javascript: 4.0.0 terser: 5.19.1 + rollup-plugin-visualizer@5.12.0(rollup@2.79.1): + dependencies: + open: 8.4.2 + picomatch: 2.3.1 + source-map: 0.7.4 + yargs: 17.7.2 + optionalDependencies: + rollup: 2.79.1 + rollup-plugin-visualizer@5.12.0(rollup@4.13.0): dependencies: open: 8.4.2 @@ -29138,14 +28201,14 @@ snapshots: react-dom: 18.2.0(react@18.2.0) redux: 4.2.0 - vite-node@0.34.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1): + vite-node@0.34.6(@types/node@20.10.8)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 mlly: 1.5.0 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -29156,13 +28219,13 @@ snapshots: - supports-color - terser - vite-node@1.2.2(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): + vite-node@1.2.2(@types/node@20.14.10)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -29173,13 +28236,13 @@ snapshots: - supports-color - terser - vite-node@1.5.0(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): + vite-node@1.5.0(@types/node@20.14.10)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -29190,57 +28253,57 @@ snapshots: - supports-color - terser - vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): + vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) workbox-build: 7.0.0(@types/babel__core@7.20.5) workbox-window: 7.0.0 transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): + vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) workbox-build: 7.0.0(@types/babel__core@7.20.5) workbox-window: 7.0.0 transitivePeerDependencies: - supports-color - vite-plugin-singlefile@2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): + vite-plugin-singlefile@2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): dependencies: micromatch: 4.0.5 rollup: 4.13.0 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) - vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)): + vite-plugin-svgr@4.2.0(rollup@2.79.1)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)): dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.13.0) + '@rollup/pluginutils': 5.1.0(rollup@2.79.1) '@svgr/core': 8.1.0(typescript@5.4.5) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): + vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.13.0) '@svgr/core': 8.1.0(typescript@5.4.5) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1): + vite@5.1.6(@types/node@20.10.8)(terser@5.19.1): dependencies: esbuild: 0.19.12 postcss: 8.4.35 @@ -29248,10 +28311,9 @@ snapshots: optionalDependencies: '@types/node': 20.10.8 fsevents: 2.3.3 - lightningcss: 1.19.0 terser: 5.19.1 - vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): + vite@5.1.6(@types/node@20.14.10)(terser@5.19.1): dependencies: esbuild: 0.19.12 postcss: 8.4.35 @@ -29259,10 +28321,9 @@ snapshots: optionalDependencies: '@types/node': 20.14.10 fsevents: 2.3.3 - lightningcss: 1.19.0 terser: 5.19.1 - vitest@0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): + vitest@0.34.6(jsdom@23.2.0)(terser@5.19.1): dependencies: '@types/chai': 4.3.11 '@types/chai-subset': 1.3.5 @@ -29285,8 +28346,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.7.0 - vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) - vite-node: 0.34.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite-node: 0.34.6(@types/node@20.10.8)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: jsdom: 23.2.0 @@ -29299,7 +28360,7 @@ snapshots: - supports-color - terser - vitest@1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): + vitest@1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1): dependencies: '@vitest/expect': 1.2.2 '@vitest/runner': 1.2.2 @@ -29319,8 +28380,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.2 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) - vite-node: 1.2.2(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite-node: 1.2.2(@types/node@20.14.10)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.10 @@ -29334,7 +28395,7 @@ snapshots: - supports-color - terser - vitest@1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): + vitest@1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1): dependencies: '@vitest/expect': 1.5.0 '@vitest/runner': 1.5.0 @@ -29353,8 +28414,8 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.4 - vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) - vite-node: 1.5.0(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite-node: 1.5.0(@types/node@20.14.10)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.10 From d0fd38384ef8c2324f378d0355ba930f3ded6f25 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 18 Oct 2024 15:55:23 -0500 Subject: [PATCH 154/259] debug: replacing errorreporter --- .../src/components/AuthenticatedApp.tsx | 11 +- packages/app/ErrorBoundary.tsx | 11 +- .../app/features/settings/AppInfoScreen.tsx | 21 +- .../features/settings/UserBugReportScreen.tsx | 13 +- packages/app/lib/debug.ts | 193 +--------------- packages/app/utils/posthog.ts | 4 +- packages/shared/src/debug.ts | 218 ++++++++++++++---- packages/shared/src/store/errorReporting.ts | 136 ----------- packages/shared/src/store/index.ts | 1 - packages/shared/src/store/sync.ts | 62 +++-- 10 files changed, 234 insertions(+), 436 deletions(-) delete mode 100644 packages/shared/src/store/errorReporting.ts diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index a31c3b2746..1059b841ed 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -1,4 +1,3 @@ -import crashlytics from '@react-native-firebase/crashlytics'; import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { useAppStatusChange } from '@tloncorp/app/hooks/useAppStatusChange'; @@ -10,8 +9,7 @@ import { cancelFetch, configureClient } from '@tloncorp/app/lib/api'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; -import { initializeCrashReporter, sync } from '@tloncorp/shared'; -import * as store from '@tloncorp/shared/dist/store'; +import { sync, useDebugStore } from '@tloncorp/shared'; import { ZStack } from '@tloncorp/ui'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; @@ -46,12 +44,7 @@ function AuthenticatedApp({ onChannelStatusChange: sync.handleChannelStatusChange, }); - initializeCrashReporter(crashlytics(), PlatformState); - - // TODO: remove, for use in Beta testing only - if (currentUserId) { - store.setErrorTrackingUserId(currentUserId); - } + useDebugStore.getState().initializePlatform(PlatformState); if (signupContext.didSignup) { handlePostSignup(); diff --git a/packages/app/ErrorBoundary.tsx b/packages/app/ErrorBoundary.tsx index 2ca27d39a0..b607a4b76c 100644 --- a/packages/app/ErrorBoundary.tsx +++ b/packages/app/ErrorBoundary.tsx @@ -1,5 +1,5 @@ import crashlytics from '@react-native-firebase/crashlytics'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; import { SizableText, View } from '@tloncorp/ui'; import { Component, ErrorInfo, ReactNode } from 'react'; @@ -13,6 +13,8 @@ interface ErrorBoundaryState { error: Error | null; } +const logger = createDevLogger('error-boundary', false); + class ErrorBoundary extends Component { constructor(props: ErrorBoundaryProps) { super(props); @@ -26,11 +28,8 @@ class ErrorBoundary extends Component { componentDidCatch(error: Error, errorInfo: ErrorInfo) { try { // If was thrown from within AuthenticatedApp, use enhanced error reporting - const reporter = new store.ErrorReporter( - 'Error boundary caught an error' - ); - reporter.log(JSON.stringify(errorInfo)); - reporter.report(error); + logger.crumb(JSON.stringify(errorInfo)); + logger.trackError(error.message, error); } catch (e) { // Otherwise fallback what we have at hand crashlytics().recordError(error); diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index 7e8af5a3d5..2f05927762 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -1,4 +1,5 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { useDebugStore } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/dist/store'; import { AppSetting, @@ -15,13 +16,13 @@ import { import { preSig } from '@urbit/aura'; import * as Application from 'expo-application'; import * as Updates from 'expo-updates'; -import { useMemo } from 'react'; +import { useEffect, useMemo } from 'react'; import { useCallback } from 'react'; -import { Platform, Switch } from 'react-native'; +import { Alert, Platform, Switch } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; import { NOTIFY_PROVIDER, NOTIFY_SERVICE } from '../../constants'; -import { toggleDebug, uploadLogs, useDebugStore } from '../../lib/debug'; +import { toggleDebug } from '../../lib/debug'; import { getEasUpdateDisplay } from '../../lib/platformHelpers'; import { RootStackParamList } from '../../navigation/types'; @@ -31,13 +32,25 @@ type Props = NativeStackScreenProps; export function AppInfoScreen(props: Props) { const { data: appInfo } = store.useAppInfo(); - const { enabled, logs, logsUrl } = useDebugStore(); + const { enabled, logs, logsUrl, uploadLogs } = useDebugStore(); const easUpdateDisplay = useMemo(() => getEasUpdateDisplay(Updates), []); const onPressPreviewFeatures = useCallback(() => { props.navigation.navigate('FeatureFlags'); }, [props.navigation]); + useEffect(() => { + Alert.alert( + 'Debug mode enabled', + 'Debug mode is now enabled. You may experience some degraded performance, because logs will be captured as you use the app. To get the best capture, you should kill the app and open it again.', + [ + { + text: 'OK', + }, + ] + ); + }, [enabled]); + return ( ; +const logger = createDevLogger('bug-report', false); + export function UserBugReportScreen({ navigation }: Props) { const [keyboardVisible, setKeyboardVisible] = useState(false); const isFocused = useIsFocused(); @@ -56,14 +58,11 @@ export function UserBugReportScreen({ navigation }: Props) { const sendBugReport = useCallback( (submission: { additionalNotes: string }) => { console.log(`got additional notes`, submission.additionalNotes); - const reporter = new ErrorReporter( - 'User manually submitted a bug report' - ); if (submission.additionalNotes) { - reporter.log(`User attached notes:`); - reporter.log(submission.additionalNotes); + logger.crumb(`User attached notes:`); + logger.crumb(submission.additionalNotes); } - reporter.report(null); + logger.trackError('User manually submitted a bug report'); setState('sent'); setTimeout(() => { if (isFocusedRef.current) { diff --git a/packages/app/lib/debug.ts b/packages/app/lib/debug.ts index 49068b6f3e..e2bade1beb 100644 --- a/packages/app/lib/debug.ts +++ b/packages/app/lib/debug.ts @@ -1,48 +1,8 @@ -import { - createDevLogger, - initializeLogger, - toggleAllLogs, -} from '@tloncorp/shared/dist'; -import { performUpload } from '@tloncorp/shared/dist/store'; -import { format } from 'date-fns'; -import * as FileSystem from 'expo-file-system'; -import { Alert, Platform } from 'react-native'; -import create from 'zustand'; +import { useDebugStore } from '@tloncorp/shared'; import storage from './storage'; const DEBUG_STORAGE_KEY = 'debug'; -const DEBUG_LOG_STORAGE_KEY = 'debug-log'; -const devLogger = createDevLogger('debug-tools', false); - -interface Log { - timestamp: number; - message: string; -} - -interface DebugStore { - enabled: boolean; - logs: Log[]; - logsUrl: string | null; - appendLog: (log: Log) => void; - toggle: (enabled: boolean) => void; -} - -export const useDebugStore = create((set, get) => ({ - enabled: false, - logs: [], - logsUrl: null, - appendLog: (log: Log) => { - set((state) => ({ - logs: [...state.logs, log], - })); - }, - toggle: (enabled) => { - set(() => ({ - enabled, - })); - }, -})); storage .load({ @@ -50,161 +10,14 @@ storage }) .then((enabled) => { useDebugStore.getState().toggle(enabled); - toggleAllLogs(enabled); - }); - -// we clear logs on every app start -// storage.save({ key: DEBUG_LOG_STORAGE_KEY, data: [] }); - -const write = (...args: unknown[]) => { - const message = args - .map((arg) => { - if (!arg) { - return JSON.stringify(arg); - } - if (typeof arg === 'string') { - return arg; - } - - if (typeof arg === 'object' && 'toString' in arg) { - return arg.toString(); - } - - return JSON.stringify(arg); - }) - .join(' '); - - useDebugStore.getState().appendLog({ - timestamp: Date.now(), - message, }); - // storage.load({ key: DEBUG_LOG_STORAGE_KEY }).then((logs) => { - // logs.push({ - // timestamp: Date.now(), - // message, - // }); - // storage.save({ - // key: DEBUG_LOG_STORAGE_KEY, - // data: logs, - // }); - // }); -}; - -const logger = { - log: (...args: unknown[]) => { - if (useDebugStore.getState().enabled) { - write(args); - } - - if (!__DEV__) { - return; - } - - console.log(...args); - }, - warn: (...args: unknown[]) => { - if (useDebugStore.getState().enabled) { - write(args); - } - - if (!__DEV__) { - return; - } - - console.warn(...args); - }, - debug: (...args: unknown[]) => { - if (useDebugStore.getState().enabled) { - write(args); - } - - if (!__DEV__) { - return; - } - - console.debug(...args); - }, - error: (...args: unknown[]) => { - if (useDebugStore.getState().enabled) { - write(args); - } - - if (!__DEV__) { - return; - } - - console.error(...args); - }, -} as Console; - -export const initializeDebug = () => { - initializeLogger(logger); -}; export const toggleDebug = async (enabled: boolean) => { + console.log(`Debug mode ${enabled ? 'enabled' : 'disabled'}`); useDebugStore.getState().toggle(enabled); + await storage.save({ key: DEBUG_STORAGE_KEY, data: enabled, }); - - toggleAllLogs(enabled); - - if (enabled) { - console.log('Debug mode enabled'); - - Alert.alert( - 'Debug mode enabled', - 'Debug mode is now enabled. You may experience some degraded performance, because logs will be captured as you use the app. To get the best capture, you should kill the app and open it again.', - [ - { - text: 'OK', - }, - ] - ); - } else { - console.log('Debug mode disabled'); - } }; - -export async function uploadLogs() { - const filename = `tlon-debug-log-${format(new Date(), 'M-d-yy-HH-mm')}`; - const contents = ( - await storage.load({ key: DEBUG_LOG_STORAGE_KEY }) - ).join('\n'); - if (Platform.OS === 'ios') { - if (!FileSystem.documentDirectory) { - logger.log(); - return; - } - const uri = FileSystem.documentDirectory + filename + '.txt'; - // await FileSystem. - await FileSystem.writeAsStringAsync(uri, contents, { - encoding: FileSystem.EncodingType.UTF8, - }); - - const url = await performUpload({ uri }, false); - useDebugStore.setState({ logsUrl: url }); - } else if (Platform.OS === 'android') { - const permissions = - await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync(); - if (!permissions.granted) { - return; - } - - if (!FileSystem.documentDirectory) { - return; - } - - const uri = await FileSystem.StorageAccessFramework.createFileAsync( - FileSystem.documentDirectory, - filename, - 'text/plain' - ); - - await FileSystem.StorageAccessFramework.writeAsStringAsync(uri, contents); - - const url = await performUpload({ uri }, false); - useDebugStore.setState({ logsUrl: url }); - } -} diff --git a/packages/app/utils/posthog.ts b/packages/app/utils/posthog.ts index 81213d46b5..387be31287 100644 --- a/packages/app/utils/posthog.ts +++ b/packages/app/utils/posthog.ts @@ -1,5 +1,5 @@ import crashlytics from '@react-native-firebase/crashlytics'; -import { initializeErrorLogger } from '@tloncorp/shared/dist'; +import { useDebugStore } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/dist/db'; import PostHog from 'posthog-react-native'; @@ -25,7 +25,7 @@ export const posthogAsync = posthogAsync?.then((client) => { posthog = client; crashlytics().setAttribute('analyticsId', client.getDistinctId()); - initializeErrorLogger(client); + useDebugStore.getState().initializeErrorLogger(client); }); const capture = (event: string, properties?: { [key: string]: any }) => { diff --git a/packages/shared/src/debug.ts b/packages/shared/src/debug.ts index 499c325811..ed82f84813 100644 --- a/packages/shared/src/debug.ts +++ b/packages/shared/src/debug.ts @@ -1,11 +1,11 @@ import { useEffect, useRef } from 'react'; +import create from 'zustand'; +import * as db from './db'; import { useLiveRef } from './logic/utilHooks'; import { useCurrentSession } from './store/session'; -const customLoggers = new Set(); -let logger: Console | null = null; -let forceEnabled = false; +const BREADCRUMB_LIMIT = 100; interface Breadcrumb { tag: string; @@ -13,50 +13,136 @@ interface Breadcrumb { sensitive?: string | null; } +interface DebugPlatformState { + network: string; + battery: string; + easUpdate: string; +} + +type PlatformState = { + getDebugInfo: () => Promise; +}; + +interface Log { + timestamp: number; + message: string; +} + export type Logger = Console & { crumb: (...args: unknown[]) => void; sensitiveCrumb: (...args: unknown[]) => void; trackError: (message: string, data?: Record) => void; }; -const debugBreadcrumbs: Breadcrumb[] = []; -const BREADCRUMB_LIMIT = 100; - -function addBreadcrumb(crumb: Breadcrumb) { - debugBreadcrumbs.push(crumb); - if (debugBreadcrumbs.length >= BREADCRUMB_LIMIT) { - debugBreadcrumbs.shift(); - } -} - -export function getCurrentBreadcrumbs() { - const includeSensitiveContext = true; // TODO: handle accordingly - return debugBreadcrumbs.map((crumb) => { - return `[${crumb.tag}] ${crumb.message ?? ''}${includeSensitiveContext && crumb.sensitive ? crumb.sensitive : ''}`; - }); -} - -export function addCustomEnabledLoggers(loggers: string[]) { - loggers.forEach((logger) => customLoggers.add(logger)); +interface ErrorLoggerStub { + capture: (event: string, data: Record) => void; } -export function initializeLogger(loggerInput: Console) { - logger = loggerInput; +interface DebugStore { + enabled: boolean; + debugBreadcrumbs: Breadcrumb[]; + customLoggers: Set; + errorLogger: ErrorLoggerStub | null; + logs: Log[]; + logsUrl: string | null; + platform: PlatformState | null; + toggle: (enabled: boolean) => void; + appendLog: (log: Log) => void; + uploadLogs: () => Promise; + addBreadcrumb: (crumb: Breadcrumb) => void; + getBreadcrumbs: () => string[]; + addCustomEnabledLoggers: (loggers: string[]) => void; + initializePlatform: (platform: PlatformState) => void; + initializeErrorLogger: (errorLoggerInput: ErrorLoggerStub) => void; } -export function toggleAllLogs(on: boolean) { - forceEnabled = on; -} +export const useDebugStore = create((set, get) => ({ + enabled: false, + customLoggers: new Set(), + errorLogger: null, + debugBreadcrumbs: [], + logs: [], + logsUrl: null, + platform: null, + toggle: (enabled) => { + set(() => ({ + enabled, + })); + }, + appendLog: (log: Log) => { + set((state) => ({ + logs: [...state.logs, log], + })); + }, + uploadLogs: async () => { + const { errorLogger, platform, debugBreadcrumbs } = get(); + const debugInfo = await platform?.getDebugInfo(); + + errorLogger?.capture('debug_logs', { + logs: get().logs, + breadcrumbs: debugBreadcrumbs, + debugInfo, + }); + }, + addBreadcrumb: (crumb: Breadcrumb) => { + set((state) => { + const debugBreadcrumbs = state.debugBreadcrumbs.slice(); + debugBreadcrumbs.push(crumb); + + if (debugBreadcrumbs.length >= BREADCRUMB_LIMIT) { + debugBreadcrumbs.shift(); + } + + return state; + }); + }, + getBreadcrumbs: () => { + const { debugBreadcrumbs } = get(); + const includeSensitiveContext = true; // TODO: handle accordingly + return debugBreadcrumbs.map((crumb) => { + return `[${crumb.tag}] ${crumb.message ?? ''}${includeSensitiveContext && crumb.sensitive ? crumb.sensitive : ''}`; + }); + }, + addCustomEnabledLoggers: (loggers) => { + set((state) => { + loggers.forEach((logger) => state.customLoggers.add(logger)); + return state; + }); + }, + initializePlatform: (platform) => { + set(() => ({ + platform, + })); + }, + initializeErrorLogger: (errorLoggerInput) => { + set(() => ({ + errorLogger: errorLoggerInput, + })); + }, +})); -interface ErrorLoggerStub { - capture: (event: string, data: Record) => void; +export function addCustomEnabledLoggers(loggers: string[]) { + return useDebugStore.getState().addCustomEnabledLoggers(loggers); } -let errorLoggerInstance: ErrorLoggerStub | null = null; -export function initializeErrorLogger(errorLoggerInput: ErrorLoggerStub) { - if (errorLoggerInput) { - errorLoggerInstance = errorLoggerInput; +async function getDebugInfo() { + let appInfo = null; + let platformState = null; + const { platform } = useDebugStore.getState(); + try { + appInfo = await db.getAppInfoSettings(); + platformState = await platform?.getDebugInfo(); + } catch (e) { + console.error('Failed to get app info or platform state', e); } + + return { + groupsSource: appInfo?.groupsSyncNode, + groupsHash: appInfo?.groupsHash, + network: platformState?.network, + battery: platformState?.battery, + easUpdate: platformState?.easUpdate, + }; } export function createDevLogger(tag: string, enabled: boolean) { @@ -64,6 +150,12 @@ export function createDevLogger(tag: string, enabled: boolean) { get(target: Console, prop: string | symbol, receiver) { return (...args: unknown[]) => { let resolvedProp = prop; + const { + enabled: debugEnabled, + errorLogger, + customLoggers, + addBreadcrumb, + } = useDebugStore.getState(); if (prop === 'crumb') { addBreadcrumb({ @@ -92,23 +184,36 @@ export function createDevLogger(tag: string, enabled: boolean) { if (prop === 'trackError') { const customProps = args[1] && typeof args[1] === 'object' ? args[1] : {}; - errorLoggerInstance?.capture('app_error', { - ...customProps, - message: - typeof args[0] === 'string' - ? `[${tag}] ${args[0]}` - : 'no message', - breadcrumbs: getCurrentBreadcrumbs(), - }); + const report = (debugInfo: any = undefined) => + errorLogger?.capture('app_error', { + ...customProps, + debugInfo, + message: + typeof args[0] === 'string' + ? `[${tag}] ${args[0]}` + : 'no message', + breadcrumbs: useDebugStore.getState().getBreadcrumbs(), + }); + getDebugInfo() + .then(report) + .catch(() => report()); resolvedProp = 'error'; } - if ( - (forceEnabled || enabled || customLoggers.has(tag)) && - process.env.NODE_ENV !== 'production' - ) { - const val = Reflect.get(logger || target, resolvedProp, receiver); - const prefix = `${[sessionTimeLabel(), deltaLabel()].filter((v) => !!v).join(':')} [${tag}]`; + if (!(debugEnabled || enabled || customLoggers.has(tag))) { + return; + } + + const prefix = `${[sessionTimeLabel(), deltaLabel()].filter((v) => !!v).join(':')} [${tag}]`; + if (debugEnabled) { + useDebugStore.getState().appendLog({ + timestamp: Date.now(), + message: `${prefix} ${stringifyArgs(...args)}`, + }); + } + + if (__DEV__) { + const val = Reflect.get(target, resolvedProp, receiver); val(prefix, ...args); } }; @@ -269,3 +374,22 @@ export function useObjectChangeLogging( } }); } + +function stringifyArgs(...args: unknown[]): string { + return args + .map((arg) => { + if (!arg) { + return JSON.stringify(arg); + } + if (typeof arg === 'string') { + return arg; + } + + if (typeof arg === 'object' && 'toString' in arg) { + return arg.toString(); + } + + return JSON.stringify(arg); + }) + .join(' '); +} diff --git a/packages/shared/src/store/errorReporting.ts b/packages/shared/src/store/errorReporting.ts deleted file mode 100644 index af9bc033a1..0000000000 --- a/packages/shared/src/store/errorReporting.ts +++ /dev/null @@ -1,136 +0,0 @@ -// import { Platform } from 'react-native'; -import * as db from '../db'; -import { getCurrentBreadcrumbs } from '../debug'; - -// RN specific modules are having issues, so we inject them as a dependencies instead. TBD how to handle on web. -type CrashReporter = { - log: (message: string) => void; - recordError: (error: Error) => void; - setUserId: (userId: string) => void; -}; - -interface DebugPlatformState { - network: string; - battery: string; - easUpdate: string; -} - -type PlatformState = { - getDebugInfo: () => Promise; -}; - -let crashReporterInstance: CrashReporter | null = null; -let platformStateInstance: PlatformState | null = null; - -export function initializeCrashReporter( - client: T, - platformState: PlatformState -) { - crashReporterInstance = client; - platformStateInstance = platformState; -} -export const CrashReporter = new Proxy( - {}, - { - get: function (target, prop, receiver) { - if (!crashReporterInstance) { - throw new Error('Crash reporter not set!'); - } - return Reflect.get(crashReporterInstance, prop, receiver); - }, - } -) as CrashReporter; - -export const PlatformState = new Proxy( - {}, - { - get: function (target, prop, receiver) { - if (!platformStateInstance) { - throw new Error('Platform state not set!'); - } - return Reflect.get(platformStateInstance, prop, receiver); - }, - } -) as PlatformState; - -// try to associate @p with any errors we send -export function setErrorTrackingUserId(userId: string) { - if (!__DEV__) { - try { - CrashReporter.setUserId(userId); - } catch (e) { - console.error('Failed to set error tracking user id', e); - } - } -} - -export class ErrorReporter { - private name: string; - private baseLogger?: Console; - private logs: string[] = []; - private error: Error | null = null; - - // name identifies the reporter in logs, baseLogger used to echo output in development - constructor(name: string, baseLogger?: Console) { - this.name = name; - this.baseLogger = baseLogger; - this.error = null; - this.logs = []; - } - - public log(message: string) { - this.logs.push(`(${this.name}): ${message}`); - this.baseLogger?.log(`(${this.name}): ${message}`); - } - - private getErrorToSubmit(): Error { - if (this.error) { - return this.error; - } - return new Error(this.name); - } - - // data only sent to crashlytics once this method is called - public async report(error: Error | null) { - this.error = error; - const errorToSubmit = this.getErrorToSubmit(); - const crumbs = getCurrentBreadcrumbs(); - - let appInfo = null; - let platformState = null; - try { - appInfo = await db.getAppInfoSettings(); - platformState = await PlatformState.getDebugInfo(); - } catch (e) { - console.error('Failed to get app info or platform state', e); - } - - if (!__DEV__) { - if (appInfo) { - CrashReporter.log(`%groups source: ${appInfo.groupsSyncNode}`); - CrashReporter.log(`%groups hash: ${appInfo.groupsHash}`); - if (platformState) { - CrashReporter.log(`network: ${platformState.network}`); - CrashReporter.log(`battery: ${platformState.battery}`); - CrashReporter.log(`OTA update: ${platformState.easUpdate}`); - } - } - - if (crumbs.length) { - CrashReporter.log('Debug Breadcrumbs:'); - crumbs.forEach((crumb) => CrashReporter.log(crumb)); - } - - if (this.logs.length) { - CrashReporter.log(`Reporter logs:`); - this.logs.forEach((log) => CrashReporter.log(log)); - } - - CrashReporter.recordError(errorToSubmit); - } else { - console.warn(`New error report: ${errorToSubmit.message}`); - console.log('Debug Breadcrumbs:'); - crumbs.forEach((crumb) => console.log(crumb)); - } - } -} diff --git a/packages/shared/src/store/index.ts b/packages/shared/src/store/index.ts index 0ef4960fd2..97cead666e 100644 --- a/packages/shared/src/store/index.ts +++ b/packages/shared/src/store/index.ts @@ -14,5 +14,4 @@ export * from './activityActions'; export * from './useActivityFetchers'; export * from './session'; export * from './contactActions'; -export * from './errorReporting'; export * from './lure'; diff --git a/packages/shared/src/store/sync.ts b/packages/shared/src/store/sync.ts index 3cf644ff3d..075af995a3 100644 --- a/packages/shared/src/store/sync.ts +++ b/packages/shared/src/store/sync.ts @@ -12,7 +12,6 @@ import { INFINITE_ACTIVITY_QUERY_KEY, resetActivityFetchers, } from '../store/useActivityFetchers'; -import { ErrorReporter } from './errorReporting'; import { useLureState } from './lure'; import { updateIsSyncing, updateSession } from './session'; import { SyncCtx, SyncPriority, syncQueue } from './syncQueue'; @@ -43,7 +42,6 @@ export function updateChannelCursor(channelId: string, cursor: string) { const joinedGroupsAndChannels = new Set(); export const syncInitData = async ( - reporter?: ErrorReporter, syncCtx?: SyncCtx, queryCtx?: QueryCtx, yieldWriter?: boolean @@ -51,50 +49,50 @@ export const syncInitData = async ( const initData = await syncQueue.add('init', syncCtx, () => api.getInitData() ); - reporter?.log('got init data from api'); + logger.crumb('got init data from api'); initializeJoinedSet(initData.unreads); useLureState.getState().start(); const writer = async () => { await db .insertGroups({ groups: initData.groups }, queryCtx) - .then(() => reporter?.log('inserted groups')); + .then(() => logger.crumb('inserted groups')); await db .insertUnjoinedGroups(initData.unjoinedGroups, queryCtx) - .then(() => reporter?.log('inserted unjoined groups')); + .then(() => logger.crumb('inserted unjoined groups')); await db .insertChannels(initData.channels, queryCtx) - .then(() => reporter?.log('inserted channels')); + .then(() => logger.crumb('inserted channels')); await persistUnreads({ unreads: initData.unreads, ctx: queryCtx, includesAllUnreads: true, - }).then(() => reporter?.log('persisted unreads')); + }).then(() => logger.crumb('persisted unreads')); await db .insertPinnedItems(initData.pins, queryCtx) - .then(() => reporter?.log('inserted pinned items')); + .then(() => logger.crumb('inserted pinned items')); await db .resetHiddenPosts(initData.hiddenPostIds, queryCtx) - .then(() => reporter?.log('handled hidden posts')); + .then(() => logger.crumb('handled hidden posts')); await db .insertBlockedContacts({ blockedIds: initData.blockedUsers }, queryCtx) - .then(() => reporter?.log('inserted blocked users')); + .then(() => logger.crumb('inserted blocked users')); await db .insertChannelPerms(initData.channelPerms, queryCtx) - .then(() => reporter?.log('inserted channel perms')); + .then(() => logger.crumb('inserted channel perms')); await db .setLeftGroups({ joinedGroupIds: initData.joinedGroups }, queryCtx) - .then(() => reporter?.log('set left groups')); + .then(() => logger.crumb('set left groups')); await db .setLeftGroupChannels( { joinedChannelIds: initData.joinedChannels }, queryCtx ) - .then(() => reporter?.log('set left channels')); + .then(() => logger.crumb('set left channels')); }; if (yieldWriter) { @@ -154,7 +152,6 @@ export const syncBlockedUsers = async (ctx?: SyncCtx) => { }; export const syncLatestPosts = async ( - reporter?: ErrorReporter, ctx?: SyncCtx, queryCtx?: QueryCtx, yieldWriter?: boolean @@ -162,7 +159,7 @@ export const syncLatestPosts = async ( const result = await syncQueue.add('latestPosts', ctx, () => api.getLatestPosts({}) ); - reporter?.log('got latest posts from api'); + logger.crumb('got latest posts from api'); const allPosts = result.map((p) => p.latestPost); const writer = async (): Promise => { allPosts.forEach((p) => updateChannelCursor(p.channelId, p.id)); @@ -1040,8 +1037,7 @@ export const handleChannelStatusChange = async (status: ChannelStatus) => { export const syncStart = async (alreadySubscribed?: boolean) => { updateIsSyncing(true); - const reporter = new ErrorReporter('sync start', logger); - reporter.log(`sync start running${alreadySubscribed ? ' (recovery)' : ''}`); + logger.crumb(`sync start running${alreadySubscribed ? ' (recovery)' : ''}`); batchEffects('sync start (high)', async (ctx) => { // this allows us to run the api calls first in parallel but handle @@ -1050,13 +1046,11 @@ export const syncStart = async (alreadySubscribed?: boolean) => { // first kickoff the fetching const syncInitPromise = syncInitData( - reporter, { priority: SyncPriority.High, retry: true }, ctx, yieldWriter ); const syncLatestPostsPromise = syncLatestPosts( - reporter, { priority: SyncPriority.High, retry: true, @@ -1068,21 +1062,21 @@ export const syncStart = async (alreadySubscribed?: boolean) => { ? Promise.resolve() : setupHighPrioritySubscriptions({ priority: SyncPriority.High - 1, - }).then(() => reporter.log('subscribed high priority')); + }).then(() => logger.crumb('subscribed high priority')); // then enforce the ordering of writes to avoid race conditions const initWriter = await syncInitPromise; await initWriter(); - reporter.log('finished writing init data'); + logger.crumb('finished writing init data'); const latestPostsWriter = await syncLatestPostsPromise; await latestPostsWriter(); - reporter.log('finished writing latest posts'); + logger.crumb('finished writing latest posts'); await subsPromise; - reporter.log('finished initializing high priority subs'); + logger.crumb('finished initializing high priority subs'); - reporter.log(`finished high priority init sync`); + logger.crumb(`finished high priority init sync`); updateSession({ startTime: Date.now() }); }); @@ -1091,36 +1085,36 @@ export const syncStart = async (alreadySubscribed?: boolean) => { ? Promise.resolve() : setupLowPrioritySubscriptions({ priority: SyncPriority.Medium, - }).then(() => reporter.log('subscribed low priority')), + }).then(() => logger.crumb('subscribed low priority')), resetActivity({ priority: SyncPriority.Medium + 1, retry: true }).then(() => - reporter.log(`finished resetting activity`) + logger.crumb(`finished resetting activity`) ), syncContacts({ priority: SyncPriority.Medium + 1, retry: true }).then(() => - reporter.log(`finished syncing contacts`) + logger.crumb(`finished syncing contacts`) ), syncSettings({ priority: SyncPriority.Medium }).then(() => - reporter.log(`finished syncing settings`) + logger.crumb(`finished syncing settings`) ), syncVolumeSettings({ priority: SyncPriority.Low }).then(() => - reporter.log(`finished syncing volume settings`) + logger.crumb(`finished syncing volume settings`) ), syncStorageSettings({ priority: SyncPriority.Low }).then(() => - reporter.log(`finished initializing storage`) + logger.crumb(`finished initializing storage`) ), syncPushNotificationsSetting({ priority: SyncPriority.Low }).then(() => - reporter.log(`finished syncing push notifications setting`) + logger.crumb(`finished syncing push notifications setting`) ), syncAppInfo({ priority: SyncPriority.Low }).then(() => { - reporter.log(`finished syncing app info`); + logger.crumb(`finished syncing app info`); }), ]; await Promise.all(lowPriorityPromises) .then(() => { - reporter.log(`finished low priority sync`); + logger.crumb(`finished low priority sync`); }) .catch((e) => { - reporter.report(e); + logger.trackError(e); }); updateIsSyncing(false); From 17fad88c17cedaa93c229a045878df9ed084f622 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 14:10:02 -0700 Subject: [PATCH 155/259] Fix test --- packages/shared/src/db/modelBuilders.ts | 2 +- packages/shared/src/store/sync.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/db/modelBuilders.ts b/packages/shared/src/db/modelBuilders.ts index d4ea3eaac6..954781876e 100644 --- a/packages/shared/src/db/modelBuilders.ts +++ b/packages/shared/src/db/modelBuilders.ts @@ -282,7 +282,7 @@ export function buildChannel( coverImage: null, coverImageColor: null, currentUserIsMember: null, - description: '', + description: null, firstUnreadPostId: null, groupId: null, iconImage: null, diff --git a/packages/shared/src/store/sync.test.ts b/packages/shared/src/store/sync.test.ts index 72be024d1d..75f00d8aa1 100644 --- a/packages/shared/src/store/sync.test.ts +++ b/packages/shared/src/store/sync.test.ts @@ -175,7 +175,8 @@ test('syncs dms', async () => { contactId: null, iconImageColor: '#f0ebbd', title: 'Pensacola 2024-04', - description: '', + // nb: we coerce empty description strings to null + description: null, members: db .buildChatMembers({ chatId: '0v4.00000.qd4p2.it253.qs53q.s53qs', From eb9571d2cacd32b9e9d5f15bde33e56171dc6949 Mon Sep 17 00:00:00 2001 From: David Lee Date: Fri, 18 Oct 2024 14:25:46 -0700 Subject: [PATCH 156/259] Add a test for parsing description --- packages/shared/src/store/sync.test.ts | 37 +++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/store/sync.test.ts b/packages/shared/src/store/sync.test.ts index 75f00d8aa1..71e51cd263 100644 --- a/packages/shared/src/store/sync.test.ts +++ b/packages/shared/src/store/sync.test.ts @@ -1,7 +1,14 @@ import * as $ from 'drizzle-orm'; +import { pick } from 'lodash'; import { expect, test, vi } from 'vitest'; -import { toClientGroup } from '../api'; +import { StructuredChannelDescriptionPayload, toClientGroup } from '../api'; +import '../api/channelContentConfig'; +import { + CollectionRendererId, + DraftInputId, + PostContentRendererId, +} from '../api/channelContentConfig'; import * as db from '../db'; import rawNewestPostData from '../test/channelNewestPost.json'; import rawChannelPostWithRepliesData from '../test/channelPostWithReplies.json'; @@ -299,3 +306,31 @@ test('syncs thread posts', async () => { Object.keys(channelPostWithRepliesData.seal.replies).length + 1 ); }); + +test('syncs groups, decoding structured description payloads', async () => { + const groupId = '~fabled-faster/new-york'; + const groupWithScdp = pick(groupsData, groupId); + const channelId = 'chat/~tormut-bolpub/nyc-housing-7361'; + const channel = groupWithScdp['~fabled-faster/new-york'].channels[channelId]; + const descriptionText = 'cheers'; + const channelContentConfiguration = { + draftInput: DraftInputId.chat, + defaultPostContentRenderer: PostContentRendererId.notebook, + defaultPostCollectionRenderer: CollectionRendererId.gallery, + }; + channel.meta.description = StructuredChannelDescriptionPayload.encode({ + description: descriptionText, + channelContentConfiguration, + })!; + setScryOutput(groupsData); + await syncGroups(); + const pins = Object.keys(groupsData).slice(0, 3); + setScryOutput(pins); + await syncPinnedItems(); + const channelFromDb = await db.getChannel({ id: channelId }); + expect(channelFromDb).toBeTruthy(); + expect(channelFromDb!.description).toEqual(descriptionText); + expect(channelFromDb!.contentConfiguration).toMatchObject( + channelContentConfiguration + ); +}); From 23bb40bface7d99f3c391186e84b90581292e4d2 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Mon, 21 Oct 2024 08:07:17 -0500 Subject: [PATCH 157/259] android: fix issue with notifications service --- .../notifications/TalkNotificationManager.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/tlon-mobile/android/app/src/main/java/io/tlon/landscape/notifications/TalkNotificationManager.java b/apps/tlon-mobile/android/app/src/main/java/io/tlon/landscape/notifications/TalkNotificationManager.java index 347d4ffad9..0f0fe3f73d 100644 --- a/apps/tlon-mobile/android/app/src/main/java/io/tlon/landscape/notifications/TalkNotificationManager.java +++ b/apps/tlon-mobile/android/app/src/main/java/io/tlon/landscape/notifications/TalkNotificationManager.java @@ -13,6 +13,7 @@ import com.android.volley.TimeoutError; import com.android.volley.VolleyError; +import android.util.Log; import org.json.JSONException; import org.json.JSONObject; @@ -49,13 +50,18 @@ public static void createNotificationChannel(Context context) { } public static void handleNotification(Context context, String uid) { + Log.d("TalkNotificationManager", "handleNotification: " + uid); + // Disabled for now, was causing issues with notifications not showing up + // while the app wasn't in the foreground (or even when it was killed) // Skip showing notifications when app is in foreground - if (AppLifecycleManager.isInForeground) { - return; - } + // if (AppLifecycleManager.isInForeground) { + // Log.d("TalkNotificationManager", "App is in foreground, skipping notification"); + // return; + // } final TalkApi api = new TalkApi(context); final int id = UvParser.getIntCompatibleFromUv(uid); + Log.d("TalkNotificationManager", "fetching yarn: " + uid + " " + id); api.fetchYarn(uid, new TalkObjectCallback() { @Override public void onComplete(JSONObject response) { @@ -67,16 +73,21 @@ public void onComplete(JSONObject response) { return; } + Log.d("TalkNotificationManager", "handleNotification, yarn: " + yarn.toString()); + // Skip if not a valid push notification if (!yarn.isValidNotification) { + Log.d("TalkNotificationManager", "Invalid notification, skipping"); return; } + Log.d("TalkNotificationManager", "fetching contact: " + yarn.senderId); api.fetchContact(yarn.senderId, new TalkObjectCallback() { @Override public void onComplete(JSONObject response) { final Contact contact = new Contact(yarn.senderId, response); final String channelId = yarn.channelId.orElse(""); + Log.d("TalkNotificationManager", "handleNotification, contact: " + contact.toString()); createNotificationTitle(api, yarn, contact, title -> { Bundle data = new Bundle(); data.putString("wer", yarn.wer); @@ -185,6 +196,7 @@ public void onError(VolleyError error) { } private static void sendNotification(Context context, int id, Person person, String title, String text, Boolean isGroupConversation, Bundle data) { + Log.d("TalkNotificationManager", "sendNotification: " + id + " " + title + " " + text + " " + isGroupConversation); Intent tapIntent = new Intent(context, MainActivity.class); tapIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); tapIntent.replaceExtras(data); From 92d8cfc0a4f4f3b1603ebed7fcc05da42ff6d9c1 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Mon, 21 Oct 2024 13:58:31 -0500 Subject: [PATCH 158/259] input: disable autofocus to fix backspace issue --- .../ui/src/components/BigInput.native.tsx | 4 +-- .../components/MessageInput/index.native.tsx | 25 +++++++++++++++---- packages/ui/src/components/PostScreenView.tsx | 9 ++++--- .../src/components/draftInputs/ChatInput.tsx | 3 ++- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/ui/src/components/BigInput.native.tsx b/packages/ui/src/components/BigInput.native.tsx index c285f0660a..f0e983e833 100644 --- a/packages/ui/src/components/BigInput.native.tsx +++ b/packages/ui/src/components/BigInput.native.tsx @@ -1,4 +1,3 @@ -import { EditorBridge } from '@10play/tentap-editor'; import * as db from '@tloncorp/shared/dist/db'; import { useMemo, useRef, useState } from 'react'; import { Dimensions, KeyboardAvoidingView, Platform } from 'react-native'; @@ -154,7 +153,8 @@ export function BigInput({ placeholder={placeholder} bigInput channelType={channelType} - shouldAutoFocus + // TODO: figure out why autofocus breaks backspace + // shouldAutoFocus draftType={channelType === 'gallery' ? 'text' : undefined} ref={editorRef} /> diff --git a/packages/ui/src/components/MessageInput/index.native.tsx b/packages/ui/src/components/MessageInput/index.native.tsx index 6cef5349a0..dadec1e05f 100644 --- a/packages/ui/src/components/MessageInput/index.native.tsx +++ b/packages/ui/src/components/MessageInput/index.native.tsx @@ -230,6 +230,10 @@ export const MessageInput = forwardRef( try { getDraft(draftType).then((draft) => { if (!editingPost && draft) { + messageInputLogger.log( + 'Not editing and we have draft content', + draft + ); const inlines = tiptap.JSONToInlines(draft); const newInlines = inlines .map((inline) => { @@ -244,15 +248,19 @@ export const MessageInput = forwardRef( .filter((inline) => inline !== null) as Inline[]; const newStory = constructStory(newInlines); const tiptapContent = tiptap.diaryMixedToJSON(newStory); - messageInputLogger.log('Setting draft content', tiptapContent); + messageInputLogger.log( + 'Setting content with draft', + tiptapContent + ); // @ts-expect-error setContent does accept JSONContent editor.setContent(tiptapContent); setEditorIsEmpty(false); - messageInputLogger.log('set has set initial content'); + messageInputLogger.log( + 'set has set initial content, not editing' + ); setHasSetInitialContent(true); } - messageInputLogger.log('Editing post?', editingPost); if (editingPost && editingPost.content) { messageInputLogger.log('Editing post', editingPost); const { @@ -298,13 +306,13 @@ export const MessageInput = forwardRef( ) as Story ); messageInputLogger.log( - 'Setting edit post content', + 'Setting content with edit post content', tiptapContent ); // @ts-expect-error setContent does accept JSONContent editor.setContent(tiptapContent); setEditorIsEmpty(false); - messageInputLogger.log('set has set initial content'); + messageInputLogger.log('set has set initial content, editing'); setHasSetInitialContent(true); } @@ -351,6 +359,7 @@ export const MessageInput = forwardRef( !editorState.isFocused && !hasAutoFocused ) { + messageInputLogger.log('Auto focusing editor', editorState); editor.focus(); messageInputLogger.log('Auto focused editor'); setHasAutoFocused(true); @@ -391,6 +400,7 @@ export const MessageInput = forwardRef( attachments.length === 0; if (isEmpty !== editorIsEmpty) { + messageInputLogger.log('Editor is empty?', isEmpty); setEditorIsEmpty(isEmpty); setContainerHeight(initialHeight); } @@ -771,6 +781,7 @@ export const MessageInput = forwardRef( const handleMessage = useCallback( async (event: WebViewMessageEvent) => { const { data } = event.nativeEvent; + messageInputLogger.log('[webview] Message from editor', data); if (data === 'enter') { handleAddNewLine(); return; @@ -868,7 +879,9 @@ export const MessageInput = forwardRef( ); useEffect(() => { + messageInputLogger.log('Setting up keyboard listeners'); if (bigInput) { + messageInputLogger.log('Setting up keyboard listeners for big input'); Keyboard.addListener('keyboardDidShow', () => { // we should always have the keyboard height here but just in case const keyboardHeight = Keyboard.metrics()?.height || 300; @@ -881,6 +894,7 @@ export const MessageInput = forwardRef( } if (!bigInput) { + messageInputLogger.log('Setting up keyboard listeners for basic input'); Keyboard.addListener('keyboardDidShow', () => { const keyboardHeight = Keyboard.metrics()?.height || 300; setMaxInputHeight(maxInputHeightBasic - keyboardHeight); @@ -895,6 +909,7 @@ export const MessageInput = forwardRef( // we need to check if the app within the webview actually loaded useEffect(() => { if (editorCrashed) { + messageInputLogger.warn('Editor crashed', editorCrashed); // if it hasn't loaded yet, we need to try loading the content again reloadWebview(`Editor crashed: ${editorCrashed}`); } diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 40a69796b6..e429611d82 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -221,10 +221,11 @@ export function PostScreenView({ editPost={editPost} channelType="chat" getDraft={getDraft} - shouldAutoFocus={ - (channel.type === 'chat' && parentPost?.replyCount === 0) || - !!editingPost - } + // TODO: figure out why autofocus breaks backspace + // shouldAutoFocus={ + // (channel.type === 'chat' && parentPost?.replyCount === 0) || + // !!editingPost + // } ref={editorRef} /> )} diff --git a/packages/ui/src/components/draftInputs/ChatInput.tsx b/packages/ui/src/components/draftInputs/ChatInput.tsx index 7ce1dc2fea..edbe7b2b29 100644 --- a/packages/ui/src/components/draftInputs/ChatInput.tsx +++ b/packages/ui/src/components/draftInputs/ChatInput.tsx @@ -39,7 +39,8 @@ export function ChatInput({ setEditingPost={setEditingPost} editPost={editPost} channelType={channel.type} - shouldAutoFocus={!!editingPost} + // TODO: figure out why autoFocus breaks backspace + // shouldAutoFocus={!!editingPost} showInlineAttachments showAttachmentButton /> From 8b9554df8552f07f822555a0e66819dab48b87db Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 21 Oct 2024 14:16:36 -0500 Subject: [PATCH 159/259] debug: better upload flow, directly to email --- apps/tlon-mobile/index.js | 16 +- .../src/components/AuthenticatedApp.tsx | 5 +- .../app/features/settings/AppInfoScreen.tsx | 77 +- packages/app/features/top/ChatListScreen.tsx | 18 +- packages/app/package.json | 5 +- packages/shared/package.json | 3 +- packages/shared/src/debug.ts | 87 +- pnpm-lock.yaml | 982 +++++++++++++++++- 8 files changed, 1142 insertions(+), 51 deletions(-) diff --git a/apps/tlon-mobile/index.js b/apps/tlon-mobile/index.js index f1977428f7..b49fc5ed68 100644 --- a/apps/tlon-mobile/index.js +++ b/apps/tlon-mobile/index.js @@ -1,21 +1,22 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; +import PlatformState from '@tloncorp/app'; import { ENABLED_LOGGERS } from '@tloncorp/app/constants'; -import { initializeDebug } from '@tloncorp/app/lib/debug'; // Setup custom dev menu items import '@tloncorp/app/lib/devMenuItems'; import { setupDb } from '@tloncorp/app/lib/nativeDb'; import { addCustomEnabledLoggers } from '@tloncorp/shared'; +import { useDebugStore } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/dist/db'; import { setStorage } from '@tloncorp/ui'; import { registerRootComponent } from 'expo'; import 'expo-dev-client'; +import { useEffect } from 'react'; import 'react-native-get-random-values'; import { TailwindProvider } from 'tailwind-rn'; import App from './src/App'; import utilities from './tailwind.json'; -initializeDebug(); - // Modifies fetch to support server sent events which // are required for Urbit client subscriptions setupDb(); @@ -23,6 +24,15 @@ addCustomEnabledLoggers(ENABLED_LOGGERS); setStorage(AsyncStorage); function Main(props) { + useEffect(() => { + async function init() { + const appInfo = await db.getAppInfoSettings(); + useDebugStore.getState().initializeDebugInfo(PlatformState, appInfo); + } + + init(); + }, []); + return ( diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index 1059b841ed..a3a7b5fe27 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -6,10 +6,9 @@ import { useNavigationLogging } from '@tloncorp/app/hooks/useNavigationLogger'; import { useNetworkLogger } from '@tloncorp/app/hooks/useNetworkLogger'; import { usePostSignup } from '@tloncorp/app/hooks/usePostSignup'; import { cancelFetch, configureClient } from '@tloncorp/app/lib/api'; -import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; -import { sync, useDebugStore } from '@tloncorp/shared'; +import { sync } from '@tloncorp/shared'; import { ZStack } from '@tloncorp/ui'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; @@ -44,8 +43,6 @@ function AuthenticatedApp({ onChannelStatusChange: sync.handleChannelStatusChange, }); - useDebugStore.getState().initializePlatform(PlatformState); - if (signupContext.didSignup) { handlePostSignup(); } diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index 2f05927762..f939cd1566 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -1,5 +1,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useDebugStore } from '@tloncorp/shared'; +import { getCurrentUserId } from '@tloncorp/shared/dist/api'; import * as store from '@tloncorp/shared/dist/store'; import { AppSetting, @@ -16,9 +17,10 @@ import { import { preSig } from '@urbit/aura'; import * as Application from 'expo-application'; import * as Updates from 'expo-updates'; -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useCallback } from 'react'; import { Alert, Platform, Switch } from 'react-native'; +import { getEmailClients, openComposer } from 'react-native-email-link'; import { ScrollView } from 'react-native-gesture-handler'; import { NOTIFY_PROVIDER, NOTIFY_SERVICE } from '../../constants'; @@ -30,16 +32,51 @@ const BUILD_VERSION = `${Platform.OS === 'ios' ? 'iOS' : 'Android'} ${Applicatio type Props = NativeStackScreenProps; +function makeDebugEmail(appInfo: any, platformInfo: any) { + return ` +---------------------------------------------- +Insert description of problem here. +---------------------------------------------- + +Tlon ID: ${getCurrentUserId()} + +Platform Information: +${JSON.stringify(platformInfo)} + +App Information: +${JSON.stringify(appInfo)} +`; +} + export function AppInfoScreen(props: Props) { const { data: appInfo } = store.useAppInfo(); - const { enabled, logs, logsUrl, uploadLogs } = useDebugStore(); + const { enabled, logs, logId, uploadLogs } = useDebugStore(); const easUpdateDisplay = useMemo(() => getEasUpdateDisplay(Updates), []); + const [hasClients, setHasClients] = useState(true); + + useEffect(() => { + async function checkClients() { + try { + const clients = await getEmailClients(); + setHasClients(clients.length > 0); + } catch (e) { + setHasClients(false); + } + } + + checkClients(); + }, []); const onPressPreviewFeatures = useCallback(() => { props.navigation.navigate('FeatureFlags'); }, [props.navigation]); - useEffect(() => { + const toggleDebugFlag = useCallback((enabled: boolean) => { + toggleDebug(enabled); + if (!enabled) { + return; + } + Alert.alert( 'Debug mode enabled', 'Debug mode is now enabled. You may experience some degraded performance, because logs will be captured as you use the app. To get the best capture, you should kill the app and open it again.', @@ -49,7 +86,24 @@ export function AppInfoScreen(props: Props) { }, ] ); - }, [enabled]); + }, []); + + const onUploadLogs = useCallback(async () => { + const id = uploadLogs(); + + const { platform, appInfo } = useDebugStore.getState(); + const platformInfo = await platform?.getDebugInfo(); + + if (!hasClients) { + return; + } + + openComposer({ + to: 'support@tlon.io', + subject: `${getCurrentUserId()} uploaded logs ${id}`, + body: makeDebugEmail(appInfo, platformInfo), + }); + }, [hasClients]); return ( @@ -103,22 +157,23 @@ export function AppInfoScreen(props: Props) { {enabled && logs.length > 0 && ( - - {logsUrl} )} + {enabled && logId && !hasClients && ( + + Please email support@tlon.io with this log ID: + {logId} + + )} diff --git a/packages/app/features/top/ChatListScreen.tsx b/packages/app/features/top/ChatListScreen.tsx index f74e27935b..57023bfc8f 100644 --- a/packages/app/features/top/ChatListScreen.tsx +++ b/packages/app/features/top/ChatListScreen.tsx @@ -211,14 +211,16 @@ export default function ChatListScreen(props: Props) { } }, []); - const { pinned: pinnedChats, unpinned } = resolvedChats; - const allChats = [...pinnedChats, ...unpinned]; - const isTlonEmployee = !!allChats.find( - (obj) => obj.groupId === TLON_EMPLOYEE_GROUP - ); - if (isTlonEmployee && TLON_EMPLOYEE_GROUP !== '') { - identifyTlonEmployee(); - } + const isTlonEmployee = useMemo(() => { + const allChats = [...resolvedChats.pinned, ...resolvedChats.unpinned]; + return !!allChats.find((obj) => obj.groupId === TLON_EMPLOYEE_GROUP); + }, [resolvedChats]); + + useEffect(() => { + if (isTlonEmployee && TLON_EMPLOYEE_GROUP !== '') { + identifyTlonEmployee(); + } + }, [isTlonEmployee]); const handleSectionChange = useCallback( (title: string) => { diff --git a/packages/app/package.json b/packages/app/package.json index 8ccc9b365c..0fd3063743 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -7,8 +7,9 @@ "test": "vitest --watch false" }, "dependencies": { - "@tloncorp/ui": "workspace:*", "@tloncorp/shared": "workspace:*", + "@tloncorp/ui": "workspace:*", + "react-native-email-link": "^1.16.1", "sqlocal": "^0.11.1" }, "devDependencies": { @@ -17,8 +18,8 @@ }, "peerDependencies": { "@react-native-firebase/perf": "19.2.2", - "react-native-device-info": "^10.8.0", "lodash": "^4.17.21", + "react-native-device-info": "^10.8.0", "zustand": "^3.7.2" } } diff --git a/packages/shared/package.json b/packages/shared/package.json index d5ab5aa0fb..120c04a342 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -30,8 +30,9 @@ "@urbit/aura": "^1.0.0", "any-ascii": "^0.3.1", "big-integer": "^1.6.52", + "exponential-backoff": "^3.1.1", "sorted-btree": "^1.8.1", - "exponential-backoff": "^3.1.1" + "uuid": "^9.0.0" }, "devDependencies": { "@types/better-sqlite3": "^7.6.9", diff --git a/packages/shared/src/debug.ts b/packages/shared/src/debug.ts index ed82f84813..258936eff3 100644 --- a/packages/shared/src/debug.ts +++ b/packages/shared/src/debug.ts @@ -1,10 +1,11 @@ import { useEffect, useRef } from 'react'; +import { v4 as uuidv4 } from 'uuid'; import create from 'zustand'; -import * as db from './db'; import { useLiveRef } from './logic/utilHooks'; import { useCurrentSession } from './store/session'; +const MAX_POSTHOG_EVENT_SIZE = 1000; const BREADCRUMB_LIMIT = 100; interface Breadcrumb { @@ -19,6 +20,12 @@ interface DebugPlatformState { easUpdate: string; } +interface AppInfo { + groupsVersion: string; + groupsHash: string; + groupsSyncNode: string; +} + type PlatformState = { getDebugInfo: () => Promise; }; @@ -44,15 +51,19 @@ interface DebugStore { customLoggers: Set; errorLogger: ErrorLoggerStub | null; logs: Log[]; - logsUrl: string | null; + logId: string | null; + appInfo: AppInfo | null; platform: PlatformState | null; toggle: (enabled: boolean) => void; appendLog: (log: Log) => void; - uploadLogs: () => Promise; + uploadLogs: () => Promise; addBreadcrumb: (crumb: Breadcrumb) => void; getBreadcrumbs: () => string[]; addCustomEnabledLoggers: (loggers: string[]) => void; - initializePlatform: (platform: PlatformState) => void; + initializeDebugInfo: ( + platform: PlatformState, + appInfo: AppInfo | null + ) => void; initializeErrorLogger: (errorLoggerInput: ErrorLoggerStub) => void; } @@ -62,8 +73,9 @@ export const useDebugStore = create((set, get) => ({ errorLogger: null, debugBreadcrumbs: [], logs: [], - logsUrl: null, + logId: null, platform: null, + appInfo: null, toggle: (enabled) => { set(() => ({ enabled, @@ -75,14 +87,35 @@ export const useDebugStore = create((set, get) => ({ })); }, uploadLogs: async () => { - const { errorLogger, platform, debugBreadcrumbs } = get(); - const debugInfo = await platform?.getDebugInfo(); + const { logs, errorLogger, platform, appInfo, debugBreadcrumbs } = get(); + const platformInfo = await platform?.getDebugInfo(); + const debugInfo = { + ...appInfo, + ...platformInfo, + }; + const infoSize = roughMeasure(debugInfo); + const crumbSize = roughMeasure(debugBreadcrumbs); + const mappedLogs = logs.map((log) => log.message); + const runSize = MAX_POSTHOG_EVENT_SIZE - crumbSize - infoSize; + const runs = splitLogs(mappedLogs, runSize); + const logId = uuidv4(); + + for (let i = 0; i < runs.length; i++) { + errorLogger?.capture('debug_logs', { + logId, + page: `Page ${i + 1} of ${runs.length}`, + logs: runs[i], + breadcrumbs: debugBreadcrumbs, + debugInfo, + }); + } - errorLogger?.capture('debug_logs', { - logs: get().logs, - breadcrumbs: debugBreadcrumbs, - debugInfo, - }); + set(() => ({ + logs: [], + logId, + })); + + return logId; }, addBreadcrumb: (crumb: Breadcrumb) => { set((state) => { @@ -109,7 +142,7 @@ export const useDebugStore = create((set, get) => ({ return state; }); }, - initializePlatform: (platform) => { + initializeDebugInfo: (platform, appInfo) => { set(() => ({ platform, })); @@ -126,11 +159,9 @@ export function addCustomEnabledLoggers(loggers: string[]) { } async function getDebugInfo() { - let appInfo = null; let platformState = null; - const { platform } = useDebugStore.getState(); + const { platform, appInfo } = useDebugStore.getState(); try { - appInfo = await db.getAppInfoSettings(); platformState = await platform?.getDebugInfo(); } catch (e) { console.error('Failed to get app info or platform state', e); @@ -393,3 +424,27 @@ function stringifyArgs(...args: unknown[]): string { }) .join(' '); } + +function roughMeasure(obj: any): number { + return JSON.stringify(obj).length; +} + +function splitLogs(logs: string[], maxSize: number): string[][] { + const splits = []; + let currentSize = 0; + let currentSplit: string[] = []; + + for (const log of logs) { + const logSize = log.length; + if (currentSize + logSize > maxSize) { + splits.push(currentSplit); + currentSplit = [log]; + currentSize = logSize; + } + + currentSplit.push(log); + currentSize += logSize; + } + + return splits; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3db8c4cee5..7e708e2d22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1542,6 +1542,9 @@ importers: react-native-device-info: specifier: ^10.8.0 version: 10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)) + react-native-email-link: + specifier: ^1.16.1 + version: 1.16.1(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) sqlocal: specifier: ^0.11.1 version: 0.11.1(drizzle-orm@0.30.9(patch_hash=cegrec33e6f7d6ltk7vff5r7w4)(@op-engineering/op-sqlite@5.0.5(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(@opentelemetry/api@1.8.0)(@types/better-sqlite3@7.6.9)(@types/react@18.2.55)(better-sqlite3@9.4.5)(react@18.2.0)) @@ -1560,7 +1563,7 @@ importers: dependencies: '@10play/tentap-editor': specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1646,6 +1649,9 @@ importers: sorted-btree: specifier: ^1.8.1 version: 1.8.1 + uuid: + specifier: ^9.0.0 + version: 9.0.0 zustand: specifier: ^3.7.2 version: 3.7.2(react@18.2.0) @@ -8325,11 +8331,13 @@ packages: eslint@8.56.0: resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm-resolve@1.0.11: @@ -11497,6 +11505,12 @@ packages: peerDependencies: react-native: '*' + react-native-email-link@1.16.1: + resolution: {integrity: sha512-uTolJXOa6HKPEiRAQuLKN/OhVwUA4xS++yPV6YiCtRBWxl2q3FUlrJt1G6plfMAEU4qNhmwZnH3tCJ9WNYIDhg==} + peerDependencies: + react: '>=16.8.0' + react-native: '>=0.40.0' + react-native-fetch-api@3.0.0: resolution: {integrity: sha512-g2rtqPjdroaboDKTsJCTlcmtw54E25OjyaunUP0anOZn4Fuo2IKs8BVfe02zVggA/UysbmfSnRJIqtNkAgggNA==} @@ -13655,6 +13669,43 @@ packages: snapshots: + '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bold': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bullet-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code-block': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) + '@tiptap/extension-document': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-heading': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-history': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-horizontal-rule': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-italic': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-link': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-list-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-ordered-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-placeholder': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-strike': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-task-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-task-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/pm': 2.6.6 + '@tiptap/react': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) + lodash: 4.17.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview: 13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + transitivePeerDependencies: + - '@tiptap/core' + '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) @@ -14548,6 +14599,19 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14561,6 +14625,13 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14568,6 +14639,17 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14579,6 +14661,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14625,6 +14718,16 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14643,6 +14746,13 @@ snapshots: '@babel/helper-plugin-utils@7.24.8': {} + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14650,6 +14760,13 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14732,11 +14849,23 @@ snapshots: dependencies: '@babel/types': 7.25.6 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14744,12 +14873,26 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.25.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14758,6 +14901,12 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14771,6 +14920,12 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14783,18 +14938,39 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -14804,12 +14980,25 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14817,10 +15006,19 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14831,11 +15029,21 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14846,41 +15054,81 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14891,67 +15139,136 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14960,18 +15277,37 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.23.7 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': @@ -14979,12 +15315,25 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14992,6 +15341,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15004,58 +15365,117 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/template': 7.25.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15063,28 +15483,58 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15093,6 +15543,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-simple-access': 7.22.5 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15102,6 +15561,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-identifier': 7.22.20 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15112,6 +15581,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15120,29 +15597,61 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15152,18 +15661,37 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.25.2) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15171,17 +15699,36 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15190,11 +15737,21 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15236,6 +15793,17 @@ snapshots: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) '@babel/types': 7.25.6 + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15253,17 +15821,40 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + regenerator-transform: 0.15.2 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15276,32 +15867,66 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15310,29 +15935,138 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/preset-env@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + core-js-compat: 3.35.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/preset-env@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15426,6 +16160,13 @@ snapshots: '@babel/helper-validator-option': 7.24.8 '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.25.2) + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.25.6 + esutils: 2.0.3 + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -17802,6 +18543,13 @@ snapshots: '@react-native/assets-registry@0.73.1': {} + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -17809,6 +18557,54 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-react-jsx': 7.25.2(@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) + '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/template': 7.25.0 + '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.23.7) + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17857,6 +18653,19 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/parser': 7.25.3 + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + flow-parser: 0.206.0 + glob: 7.2.3 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/parser': 7.25.3 @@ -17891,6 +18700,27 @@ snapshots: - supports-color - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-tools': 12.3.7(encoding@0.1.13) + '@react-native/dev-middleware': 0.73.8(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + chalk: 4.1.2 + execa: 5.1.1 + metro: 0.80.5(encoding@0.1.13) + metro-config: 0.80.5(encoding@0.1.13) + metro-core: 0.80.5 + node-fetch: 2.6.12(encoding@0.1.13) + readline: 1.3.0 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) @@ -17937,6 +18767,16 @@ snapshots: '@react-native/js-polyfills@0.73.1': {} + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@react-native/babel-preset': 0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + hermes-parser: 0.15.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17967,6 +18807,12 @@ snapshots: '@react-native/normalize-colors@0.74.84': {} + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))': dependencies: invariant: 2.2.4 @@ -20800,7 +21646,16 @@ snapshots: dependencies: '@babel/runtime': 7.25.6 cosmiconfig: 7.1.0 - resolve: 1.22.4 + resolve: 1.22.8 + + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.7): + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.25.2): dependencies: @@ -20811,6 +21666,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20819,6 +21682,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20827,6 +21698,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20838,6 +21716,12 @@ snapshots: babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.23.7): + dependencies: + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + transitivePeerDependencies: + - '@babel/core' + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2): dependencies: '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) @@ -24366,6 +25250,31 @@ snapshots: jsc-safe-url@0.2.4: {} + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)): + dependencies: + '@babel/core': 7.25.2 + '@babel/parser': 7.25.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.25.2) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.25.2) + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + '@babel/preset-flow': 7.23.3(@babel/core@7.25.2) + '@babel/preset-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/register': 7.23.7(@babel/core@7.25.2) + babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) + chalk: 4.1.2 + flow-parser: 0.206.0 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.21.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.25.2)): dependencies: '@babel/core': 7.25.2 @@ -26211,6 +27120,11 @@ snapshots: dependencies: react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) + react-native-email-link@1.16.1(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): + dependencies: + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) + react-native-fetch-api@3.0.0: dependencies: p-defer: 3.0.0 @@ -26399,6 +27313,13 @@ snapshots: transitivePeerDependencies: - encoding + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): + dependencies: + escape-string-regexp: 2.0.0 + invariant: 2.2.4 + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: escape-string-regexp: 2.0.0 @@ -26460,6 +27381,55 @@ snapshots: - supports-color - utf-8-validate + react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-android': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 12.3.7(encoding@0.1.13) + '@react-native/assets-registry': 0.73.1 + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13) + '@react-native/gradle-plugin': 0.73.4 + '@react-native/js-polyfills': 0.73.1 + '@react-native/normalize-colors': 0.73.2 + '@react-native/virtualized-lists': 0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0)) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + deprecated-react-native-prop-types: 5.0.0 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.5 + metro-source-map: 0.80.5 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 4.28.5 + react-refresh: 0.14.0 + react-shallow-renderer: 16.15.0(react@18.2.0) + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0): dependencies: '@jest/create-cache-key-function': 29.7.0 From 4ec7383372ea72e7b94cb5b43a19f866c79c6e5b Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 21 Oct 2024 15:07:03 -0500 Subject: [PATCH 160/259] urbit: adding posthog error tracking to poke and sub failures --- packages/shared/src/api/urbit.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/api/urbit.ts b/packages/shared/src/api/urbit.ts index c2bfb7d75f..d210eed10a 100644 --- a/packages/shared/src/api/urbit.ts +++ b/packages/shared/src/api/urbit.ts @@ -197,7 +197,9 @@ export async function subscribe( config.onQuitOrReset?.(); }, err: (error, id) => { - logger.error(`subscribe error on ${printEndpoint(endpoint)}:`, error); + logger.trackError(`subscribe error on ${printEndpoint(endpoint)}`, { + stack: error, + }); if (err) { logger.log( @@ -241,7 +243,16 @@ export async function subscribeOnce( try { return config.client.subscribeOnce(endpoint.app, endpoint.path, timeout); } catch (err) { - logger.error('bad subscribeOnce', printEndpoint(endpoint), err); + if (err !== 'timeout' && err !== 'quit') { + logger.trackError(`bad subscribeOnce ${printEndpoint(endpoint)}`, { + stack: err, + }); + } else if (err === 'timeout') { + logger.error('subscribeOnce timed out', printEndpoint(endpoint)); + } else { + logger.error('subscribeOnce quit', printEndpoint(endpoint)); + } + if (!(err instanceof AuthError)) { throw err; } @@ -286,7 +297,10 @@ export async function poke({ app, mark, json }: PokeParams) { }); }; const retry = async (err: any) => { - logger.log('bad poke', app, mark, json, err); + logger.trackError(`bad poke to ${app} with mark ${mark}`, { + stack: err, + body: json, + }); if (!(err instanceof AuthError)) { throw err; } From 1bddbb39a5c4acd9d20c608c6a9df586b9a9bc9f Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 21 Oct 2024 15:39:19 -0500 Subject: [PATCH 161/259] app: remove crashyltics init --- apps/tlon-mobile/src/App.main.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 5dc76b7cde..ae6972d264 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -23,7 +23,6 @@ import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { FeatureFlagConnectedInstrumentationProvider } from '@tloncorp/app/utils/perf'; import { posthogAsync } from '@tloncorp/app/utils/posthog'; -import { initializeCrashReporter } from '@tloncorp/shared/dist'; import { QueryClientProvider, queryClient } from '@tloncorp/shared/dist/api'; import { LoadingSpinner, @@ -42,8 +41,6 @@ import { SafeAreaProvider } from 'react-native-safe-area-context'; import { OnboardingStack } from './OnboardingStack'; import AuthenticatedApp from './components/AuthenticatedApp'; -initializeCrashReporter(crashlytics(), PlatformState); - // Android notification tap handler passes initial params here const App = () => { const isDarkMode = useIsDarkMode(); From affe5b432b8ad73a722d8144f3fec76d0dc54a8e Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 21 Oct 2024 15:50:17 -0500 Subject: [PATCH 162/259] debug: fix max event size --- packages/shared/src/debug.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/debug.ts b/packages/shared/src/debug.ts index a9245281ea..f58d3a0ad5 100644 --- a/packages/shared/src/debug.ts +++ b/packages/shared/src/debug.ts @@ -5,7 +5,7 @@ import create from 'zustand'; import { useLiveRef } from './logic/utilHooks'; import { useCurrentSession } from './store/session'; -const MAX_POSTHOG_EVENT_SIZE = 1000; +const MAX_POSTHOG_EVENT_SIZE = 1_000_000; const BREADCRUMB_LIMIT = 100; interface Breadcrumb { From 9ac3bc1c0d7a5b2f689e75c50a9866cac33c6ad2 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Mon, 21 Oct 2024 16:06:39 -0500 Subject: [PATCH 163/259] input: update 10tap, fixes backspace on autofocus, re-enable autofocus --- apps/tlon-mobile/ios/Podfile.lock | 4 +- apps/tlon-mobile/package.json | 2 +- package.json | 2 +- packages/editor/package.json | 2 +- packages/ui/package.json | 2 +- .../ui/src/components/BigInput.native.tsx | 3 +- packages/ui/src/components/PostScreenView.tsx | 9 +- .../src/components/draftInputs/ChatInput.tsx | 3 +- pnpm-lock.yaml | 1375 +++++++++++++---- 9 files changed, 1073 insertions(+), 329 deletions(-) diff --git a/apps/tlon-mobile/ios/Podfile.lock b/apps/tlon-mobile/ios/Podfile.lock index 57a709f540..716c600b86 100644 --- a/apps/tlon-mobile/ios/Podfile.lock +++ b/apps/tlon-mobile/ios/Podfile.lock @@ -1388,7 +1388,7 @@ PODS: - sqlite3 (3.42.0): - sqlite3/common (= 3.42.0) - sqlite3/common (3.42.0) - - tentap (0.5.11): + - tentap (0.5.21): - glog - RCT-Folly (= 2022.05.16.00) - React-Core @@ -1878,7 +1878,7 @@ SPEC CHECKSUMS: SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 sqlite3: f163dbbb7aa3339ad8fc622782c2d9d7b72f7e9c - tentap: 4871503ab3d587fe80fe13f6fe712fde98b57525 + tentap: 2cf2e387dd284bf867010eb7d0f91618fb35b673 UMAppLoader: 5df85360d65cabaef544be5424ac64672e648482 Yoga: fb61b2337c7688c81a137e5560b3cbb515289f91 diff --git a/apps/tlon-mobile/package.json b/apps/tlon-mobile/package.json index 9a8e3707a2..c744dbdadf 100644 --- a/apps/tlon-mobile/package.json +++ b/apps/tlon-mobile/package.json @@ -37,7 +37,7 @@ ] }, "dependencies": { - "@10play/tentap-editor": "~0.5.11", + "@10play/tentap-editor": "~0.5.21", "@aws-sdk/client-s3": "^3.190.0", "@aws-sdk/s3-request-presigner": "^3.190.0", "@dev-plugins/async-storage": "^0.0.3", diff --git a/package.json b/package.json index 741e2241db..1b1ffd30b4 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "allowNonAppliedPatches": true, "overrides": { "typescript": "5.4.5", - "@10play/tentap-editor": "0.5.11", + "@10play/tentap-editor": "0.5.21", "@tiptap/suggestion": "2.6.0", "@tiptap/extension-mention": "2.6.0", "@tiptap/extension-hard-break": "2.6.0", diff --git a/packages/editor/package.json b/packages/editor/package.json index 7487c0e5c9..9505e30ad9 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -38,6 +38,6 @@ }, "peerDependencies": { "react": "^18.2.0", - "@10play/tentap-editor": "~0.5.11" + "@10play/tentap-editor": "~0.5.21" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index d04420478e..8330d1f820 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -52,7 +52,7 @@ "urbit-ob": "^5.0.1" }, "peerDependencies": { - "@10play/tentap-editor": "~0.5.11", + "@10play/tentap-editor": "~0.5.21", "@urbit/sigil-js": "^2.2.0", "expo-image": "*", "react": "*", diff --git a/packages/ui/src/components/BigInput.native.tsx b/packages/ui/src/components/BigInput.native.tsx index f0e983e833..ef87afbaf1 100644 --- a/packages/ui/src/components/BigInput.native.tsx +++ b/packages/ui/src/components/BigInput.native.tsx @@ -153,8 +153,7 @@ export function BigInput({ placeholder={placeholder} bigInput channelType={channelType} - // TODO: figure out why autofocus breaks backspace - // shouldAutoFocus + shouldAutoFocus draftType={channelType === 'gallery' ? 'text' : undefined} ref={editorRef} /> diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index e429611d82..40a69796b6 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -221,11 +221,10 @@ export function PostScreenView({ editPost={editPost} channelType="chat" getDraft={getDraft} - // TODO: figure out why autofocus breaks backspace - // shouldAutoFocus={ - // (channel.type === 'chat' && parentPost?.replyCount === 0) || - // !!editingPost - // } + shouldAutoFocus={ + (channel.type === 'chat' && parentPost?.replyCount === 0) || + !!editingPost + } ref={editorRef} /> )} diff --git a/packages/ui/src/components/draftInputs/ChatInput.tsx b/packages/ui/src/components/draftInputs/ChatInput.tsx index edbe7b2b29..7ce1dc2fea 100644 --- a/packages/ui/src/components/draftInputs/ChatInput.tsx +++ b/packages/ui/src/components/draftInputs/ChatInput.tsx @@ -39,8 +39,7 @@ export function ChatInput({ setEditingPost={setEditingPost} editPost={editPost} channelType={channel.type} - // TODO: figure out why autoFocus breaks backspace - // shouldAutoFocus={!!editingPost} + shouldAutoFocus={!!editingPost} showInlineAttachments showAttachmentButton /> diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 478ed1bd5d..792e212993 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: overrides: typescript: 5.4.5 - '@10play/tentap-editor': 0.5.11 + '@10play/tentap-editor': 0.5.21 '@tiptap/suggestion': 2.6.0 '@tiptap/extension-mention': 2.6.0 '@tiptap/extension-hard-break': 2.6.0 @@ -92,13 +92,13 @@ importers: version: 8.0.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(postcss@8.4.35)(typescript@5.4.5) vitest: specifier: ^1.2.2 - version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) apps/tlon-mobile: dependencies: '@10play/tentap-editor': - specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + specifier: 0.5.21 + version: 0.5.21(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@aws-sdk/client-s3': specifier: ^3.190.0 version: 3.190.0 @@ -257,7 +257,7 @@ importers: version: 4.17.21 posthog-react-native: specifier: ^2.7.1 - version: 2.11.3(jwrxiw3lzqzjxcpw4mvkvmmdfa) + version: 2.11.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(expo-application@5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-device@5.9.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-file-system@16.0.9(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-localization@14.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(react-native-device-info@10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))) react: specifier: ^18.2.0 version: 18.2.0 @@ -342,7 +342,7 @@ importers: version: 29.7.0 '@react-native/metro-config': specifier: ^0.73.5 - version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) + version: 0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13) '@tamagui/babel-plugin': specifier: ~1.112.12 version: 1.112.12(@swc/helpers@0.5.13)(encoding@0.1.13)(react@18.2.0) @@ -426,7 +426,7 @@ importers: version: 3.4.1 vitest: specifier: ^1.0.4 - version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) apps/tlon-web: dependencies: @@ -798,7 +798,7 @@ importers: version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@2.79.1)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) workbox-precaching: specifier: ^6.5.4 version: 6.6.0 @@ -889,10 +889,10 @@ importers: version: 2.0.1 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 1.1.0(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) '@welldone-software/why-did-you-render': specifier: ^7.0.1 version: 7.0.1(react@18.2.0) @@ -934,7 +934,7 @@ importers: version: 6.1.1 react-cosmos-plugin-vite: specifier: 6.1.1 - version: 6.1.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)) + version: 6.1.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -943,7 +943,7 @@ importers: version: 4.0.0 rollup-plugin-visualizer: specifier: ^5.6.0 - version: 5.12.0(rollup@2.79.1) + version: 5.12.0(rollup@4.13.0) tailwindcss: specifier: ^3.2.7 version: 3.4.1 @@ -958,13 +958,13 @@ importers: version: 1.1.4(typescript@5.4.5) vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + version: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) vite-plugin-pwa: specifier: ^0.17.5 - version: 0.17.5(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) + version: 0.17.5(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) vitest: specifier: ^0.34.1 - version: 0.34.6(jsdom@23.2.0)(terser@5.19.1) + version: 0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -1348,7 +1348,7 @@ importers: version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 - version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) workbox-precaching: specifier: ^6.5.4 version: 6.6.0 @@ -1442,10 +1442,10 @@ importers: version: 2.0.1 '@vitejs/plugin-basic-ssl': specifier: ^1.1.0 - version: 1.1.0(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 1.1.0(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) '@welldone-software/why-did-you-render': specifier: ^7.0.1 version: 7.0.1(react@18.2.0) @@ -1490,7 +1490,7 @@ importers: version: 6.1.1 react-cosmos-plugin-vite: specifier: 6.1.1 - version: 6.1.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 6.1.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) react-test-renderer: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -1514,13 +1514,13 @@ importers: version: 1.1.4(typescript@5.4.5) vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + version: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) vite-plugin-pwa: specifier: ^0.17.5 - version: 0.17.5(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) + version: 0.17.5(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0) vitest: specifier: ^0.34.1 - version: 0.34.6(jsdom@23.2.0)(terser@5.19.1) + version: 0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) workbox-window: specifier: ^7.0.0 version: 7.0.0 @@ -1565,8 +1565,8 @@ importers: packages/editor: dependencies: '@10play/tentap-editor': - specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + specifier: 0.5.21 + version: 0.5.21(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1591,7 +1591,7 @@ importers: version: 6.21.0(eslint@8.56.0)(typescript@5.4.5) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) eslint: specifier: ^8.50.0 version: 8.56.0 @@ -1603,13 +1603,13 @@ importers: version: 5.4.5 vite: specifier: ^5.1.6 - version: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + version: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) vite-plugin-singlefile: specifier: ^2.0.1 - version: 2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)) + version: 2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) vitest: specifier: ^1.0.4 - version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) packages/shared: dependencies: @@ -1680,13 +1680,13 @@ importers: version: 5.4.5 vitest: specifier: ^1.4.0 - version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1) + version: 1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1) packages/ui: dependencies: '@10play/tentap-editor': - specifier: 0.5.11 - version: 0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + specifier: 0.5.21 + version: 0.5.21(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@emoji-mart/data': specifier: ^1.1.2 version: 1.1.2 @@ -1784,8 +1784,8 @@ importers: packages: - '@10play/tentap-editor@0.5.11': - resolution: {integrity: sha512-F+MBGQYS9vW2MscmSIwbfb3KPhbulWq7AxIfiYEno6aoj4/kBDAQtwwynQD77C5fjy5NyT4HhJg4t438w8+5CA==} + '@10play/tentap-editor@0.5.21': + resolution: {integrity: sha512-ZGA90XLzDenUMhi6NW0/GTbiCPSHGSylLGBGvZBTT1+nIOmxLStEvO8LWYaBpKoTHMovnb+TknQD2nlf548OiA==} engines: {node: '>= 18.0.0'} peerDependencies: react: '*' @@ -3146,9 +3146,11 @@ packages: '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.6.5': resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} @@ -5958,65 +5960,33 @@ packages: peerDependencies: '@tiptap/pm': 2.6.6 - '@tiptap/extension-blockquote@2.3.0': - resolution: {integrity: sha512-Cztt77t7f+f0fuPy+FWUL8rKTIpcdsVT0z0zYQFFafvGaom0ZALQSOdTR/q+Kle9I4DaCMO3/Q0mwax/D4k4+A==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-blockquote@2.6.6': resolution: {integrity: sha512-hAdsNlMfzzxld154hJqPqtWqO5i4/7HoDfuxmyqBxdMJ+e2UMaIGBGwoLRXG0V9UoRwJusjqlpyD7pIorxNlgA==} peerDependencies: '@tiptap/core': ^2.6.6 - '@tiptap/extension-bold@2.3.0': - resolution: {integrity: sha512-SzkbJibHXFNU7TRaAebTtwbXUEhGZ8+MhlBn12aQ4QhdjNtFpQwKXQPyYeDyZGcyiOFgtFTb+WIfCGm8ZX0Fpw==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-bold@2.6.6': resolution: {integrity: sha512-CD6gBhdQtCoqYSmx8oAV8gvKtVOGZSyyvuNYo7by9eZ56DqLYnd7kbUj0RH7o9Ymf/iJTOUJ6XcvrsWwo4lubg==} peerDependencies: '@tiptap/core': ^2.6.6 - '@tiptap/extension-bubble-menu@2.3.0': - resolution: {integrity: sha512-dqyfQ8idTlhapvt0fxCGvkyjw92pBEwPqmkJ01h3EE8wTh53j0ytOHyMSf1KBuzardxpd8Yya3zlrAcR0Z3DlQ==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-bubble-menu@2.6.6': resolution: {integrity: sha512-IkfmlZq67aaegym5sBddBc/xXWCArxn5WJEl1oxKEayjQhybKSaqI7tk0lOx/x7fa5Ml1WlGpCFh+KKXbQTG0g==} peerDependencies: '@tiptap/core': ^2.6.6 '@tiptap/pm': 2.6.6 - '@tiptap/extension-bullet-list@2.3.0': - resolution: {integrity: sha512-4nU4vJ5FjRDLqHm085vYAkuo68UK84Wl6CDSjm7sPVcu0FvQX02Okqt65azoSYQeS1SSSd5qq9YZuGWcYdp4Cw==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-bullet-list@2.6.6': resolution: {integrity: sha512-WEKxbVSYuvmX2wkHWP8HXk5nzA7stYwtdaubwWH/R17kGI3IGScJuMQ9sEN82uzJU8bfgL9yCbH2bY8Fj/Q4Ow==} peerDependencies: '@tiptap/core': ^2.6.6 - '@tiptap/extension-code-block@2.3.0': - resolution: {integrity: sha512-+Ne6PRBwQt70Pp8aW2PewaEy4bHrNYn4N+y8MObsFtqLutXBz4nXnsXWiNYFQZwzlUY+CHG4XS73mx8oMOFfDw==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-code-block@2.6.6': resolution: {integrity: sha512-1YLp/zHMHSkE2xzht8nPR6T4sQJJ3ket798czxWuQEbetFv/l0U/mpiPpYSLObj6oTAoqYZ0kWXZj5eQSpPB8Q==} peerDependencies: '@tiptap/core': ^2.6.6 '@tiptap/pm': 2.6.6 - '@tiptap/extension-code@2.3.0': - resolution: {integrity: sha512-O2FZmosiIRoVbW82fZy8xW4h4gb2xAzxWzHEcsHPlwCbE3vYvcBMmbkQ5p+33eRtuRQInzl3Q/cwupv9ctIepQ==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-code@2.6.6': resolution: {integrity: sha512-JrEFKsZiLvfvOFhOnnrpA0TzCuJjDeysfbMeuKUZNV4+DhYOL28d39H1++rEtJAX0LcbBU60oC5/PrlU9SpvRQ==} peerDependencies: @@ -6028,11 +5998,6 @@ packages: '@tiptap/core': ^2.0.0 '@tiptap/extension-text-style': ^2.0.0 - '@tiptap/extension-document@2.3.0': - resolution: {integrity: sha512-WC55SMrtlsNOnHXpzbXDzJOp7eKmZV0rXooKmvCDqoiLO/DKpyQXyF+0UHfcRPmUAi2GWFPaer7+p1H9xzcjXg==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-document@2.6.6': resolution: {integrity: sha512-6qlH5VWzLHHRVeeciRC6C4ZHpMsAGPNG16EF53z0GeMSaaFD/zU3B239QlmqXmLsAl8bpf8Bn93N0t2ABUvScw==} peerDependencies: @@ -6061,11 +6026,6 @@ packages: peerDependencies: '@tiptap/core': ^2.6.0 - '@tiptap/extension-heading@2.3.0': - resolution: {integrity: sha512-YcZoUYfqb0nohoPgem4f8mjn5OqDomFrbJiC9VRHUOCIuEu+aJEYwp8mmdkLnS3f+LRCZ6G76cJJ50lkzSAZRw==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-heading@2.6.6': resolution: {integrity: sha512-bgx9vptVFi5yFkIw1OI53J7+xJ71Or3SOe/Q8eSpZv53DlaKpL/TzKw8Z54t1PrI2rJ6H9vrLtkvixJvBZH1Ug==} peerDependencies: @@ -6076,24 +6036,12 @@ packages: peerDependencies: '@tiptap/core': ^2.0.0 - '@tiptap/extension-history@2.3.0': - resolution: {integrity: sha512-EF5Oq9fe/VBzU1Lsow2ubOlx1e1r4OQT1WUPGsRnL7pr94GH1Skpk7/hs9COJ9K6kP3Ebt42XjP0JEQodR58YA==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-history@2.6.6': resolution: {integrity: sha512-tPTzAmPGqMX5Bd5H8lzRpmsaMvB9DvI5Dy2za/VQuFtxgXmDiFVgHRkRXIuluSkPTuANu84XBOQ0cBijqY8x4w==} peerDependencies: '@tiptap/core': ^2.6.6 '@tiptap/pm': 2.6.6 - '@tiptap/extension-horizontal-rule@2.3.0': - resolution: {integrity: sha512-4DB8GU3uuDzzyqUmONIb3CHXcQ6Nuy4mHHkFSmUyEjg1i5eMQU5H7S6mNvZbltcJB2ImgCSwSMlj1kVN3MLIPg==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-horizontal-rule@2.6.6': resolution: {integrity: sha512-cFEfv7euDpuLSe8exY8buwxkreKBAZY9Hn3EetKhPcLQo+ut5Y24chZTxFyf9b+Y0wz3UhOhLTZSz7fTobLqBA==} peerDependencies: @@ -6105,33 +6053,17 @@ packages: peerDependencies: '@tiptap/core': ^2.0.0 - '@tiptap/extension-italic@2.3.0': - resolution: {integrity: sha512-jdFjLjdt5JtPlGMpoS6TEq5rznjbAYVlPwcw5VkYENVIYIGIR1ylIw2JwK1nUEsQ+OgYwVxHLejcUXWG1dCi2g==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-italic@2.6.6': resolution: {integrity: sha512-t7ZPsXqa8nJZZ/6D0rQyZ/KsvzLaSihC6hBTjUQ77CeDGV9PhDWjIcBW4OrvwraJDBd12ETBeQ2CkULJOgH+lQ==} peerDependencies: '@tiptap/core': ^2.6.6 - '@tiptap/extension-link@2.3.0': - resolution: {integrity: sha512-CnJAlV0ZOdEhKmDfYKuHJVG8g79iCFQ85cX/CROTWyuMfXz9uhj2rLpZ6nfidVbonqxAhQp7NAIr2y+Fj5/53A==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-link@2.6.6': resolution: {integrity: sha512-NJSR5Yf/dI3do0+Mr6e6nkbxRQcqbL7NOPxo5Xw8VaKs2Oe8PX+c7hyqN3GZgn6uEbZdbVi1xjAniUokouwpFg==} peerDependencies: '@tiptap/core': ^2.6.6 '@tiptap/pm': 2.6.6 - '@tiptap/extension-list-item@2.3.0': - resolution: {integrity: sha512-mHU+IuRa56OT6YCtxf5Z7OSUrbWdKhGCEX7RTrteDVs5oMB6W3oF9j88M5qQmZ1WDcxvQhAOoXctnMt6eX9zcA==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-list-item@2.6.6': resolution: {integrity: sha512-k+oEzZu2cgVKqPqOP1HzASOKLpTEV9m7mRVPAbuaaX8mSyvIgD6f+JUx9PvgYv//D918wk98LMoRBFX53tDJ4w==} peerDependencies: @@ -6144,11 +6076,6 @@ packages: '@tiptap/pm': 2.6.6 '@tiptap/suggestion': 2.6.0 - '@tiptap/extension-ordered-list@2.3.0': - resolution: {integrity: sha512-gkf0tltXjlUj0cqyfDV2r7xy9YPKtcVSWwlCPun6OOi0KzKFiAMqQpA9hy2W6gJ+KCp8+KNRMClZOfH4TnnBfg==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-ordered-list@2.6.6': resolution: {integrity: sha512-AJwyfLXIi7iUGnK5twJbwdVVpQyh7fU6OK75h1AwDztzsOcoPcxtffDlZvUOd4ZtwuyhkzYqVkeI0f+abTWZTw==} peerDependencies: @@ -6159,45 +6086,23 @@ packages: peerDependencies: '@tiptap/core': ^2.6.6 - '@tiptap/extension-placeholder@2.3.0': - resolution: {integrity: sha512-1BOyxVLzyUYf6yOOeJ8CfpP6DSCS4L6HjBZqj6WP1z1NyBV8RAfhf3UuLNcimfSWAETXFR3g0ZbaxxWffI1cEg==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-placeholder@2.6.6': resolution: {integrity: sha512-J0ZMvF93NsRrt+R7IQ3GhxNq32vq+88g25oV/YFJiwvC48HMu1tQB6kG1I3LJpu5b8lN+LnfANNqDOEhiBfjaA==} peerDependencies: '@tiptap/core': ^2.6.6 '@tiptap/pm': 2.6.6 - '@tiptap/extension-strike@2.3.0': - resolution: {integrity: sha512-gOW4ALeH8gkJiUGGXVy/AOd5lAPTX0bzoOW1+sCLcTA7t8dluBW7M2ngNYxTEtlKqyv7aLfrgsYSiqucmmfSLw==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-strike@2.6.6': resolution: {integrity: sha512-Ze8KhGk+wzSJSJRl5fbhTI6AvPu2LmcHYeO3pMEH8u4gV5WTXfmKJVStEIAzkoqvwEQVWzXvy8nDgsFQHiojPg==} peerDependencies: '@tiptap/core': ^2.6.6 - '@tiptap/extension-task-item@2.3.0': - resolution: {integrity: sha512-WvQJiQSskI1dZLPgNH4hmYPW0HFyR/EHwogzVnY7XCn2/5isV0ewyaVuSfqTXvfEA/R5uCi95opwz61NFBc2nQ==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - '@tiptap/extension-task-item@2.6.6': resolution: {integrity: sha512-fvzy8/TN5sm3A2HSokJzHj5ZvcOAsRdqPS6fPOpmf5dQZ+EIAJrlfyxqb9B6055pNXBbuXcMEXdeU44zCU0YRg==} peerDependencies: '@tiptap/core': ^2.6.6 '@tiptap/pm': 2.6.6 - '@tiptap/extension-task-list@2.3.0': - resolution: {integrity: sha512-TBgqf4s3DpUV97w7AAj1WZDnZ3rZQ8B645d9bBayo4VfRzHCLefv5cVP/Ye9GA23T4FZoHNR+yIPrM7SfhkmPA==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/extension-task-list@2.6.6': resolution: {integrity: sha512-0N4xCCJZu0PcKoCRDywQngNNW6qlB26hyVJGDGgW53p/2zk5gdlzAA6/NxElO3iSAXKFm0QOWAg/x8E+ggDu4w==} peerDependencies: @@ -6221,14 +6126,6 @@ packages: '@tiptap/pm@2.6.6': resolution: {integrity: sha512-56FGLPn3fwwUlIbLs+BO21bYfyqP9fKyZQbQyY0zWwA/AG2kOwoXaRn7FOVbjP6CylyWpFJnpRRmgn694QKHEg==} - '@tiptap/react@2.3.0': - resolution: {integrity: sha512-ThgFJQTWYKRClTV2Zg0wBRqfy0EGz3U4NOey7jwncUjSjx5+o9nXbfQAYWDKQFfWyE+wnrBTYfddEP9pHNX5cQ==} - peerDependencies: - '@tiptap/core': ^2.0.0 - '@tiptap/pm': 2.6.6 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - '@tiptap/react@2.6.6': resolution: {integrity: sha512-AUmdb/J1O/vCO2b8LL68ctcZr9a3931BwX4fUUZ1kCrCA5lTj2xz0rjeAtpxEdzLnR+Z7q96vB7vf7bPYOUAew==} peerDependencies: @@ -11374,6 +11271,7 @@ packages: react-beautiful-dnd@13.1.1: resolution: {integrity: sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==} + deprecated: 'react-beautiful-dnd is now deprecated. Context and options: https://github.com/atlassian/react-beautiful-dnd/issues/2672' peerDependencies: react: ^16.8.5 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0 @@ -13669,34 +13567,71 @@ packages: snapshots: - '@10play/tentap-editor@0.5.11(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + '@10play/tentap-editor@0.5.21(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + '@tiptap/extension-blockquote': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bold': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bullet-list': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code-block': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) + '@tiptap/extension-document': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-heading': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-history': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-horizontal-rule': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-italic': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-link': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-list-item': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-ordered-list': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-placeholder': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-strike': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-task-item': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-task-list': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/pm': 2.6.6 + '@tiptap/react': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) + lodash: 4.17.21 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview: 13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + transitivePeerDependencies: + - '@tiptap/core' + + '@10play/tentap-editor@0.5.21(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: - '@tiptap/extension-blockquote': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-bold': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-bullet-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-code': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-code-block': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-blockquote': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bold': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-bullet-list': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-code-block': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) '@tiptap/extension-color': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/extension-text-style@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))) - '@tiptap/extension-document': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-document': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) '@tiptap/extension-dropcursor': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) '@tiptap/extension-hard-break': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-heading': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-heading': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) '@tiptap/extension-highlight': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-history': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-horizontal-rule': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-history': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-horizontal-rule': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) '@tiptap/extension-image': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-italic': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-link': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-list-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-ordered-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-placeholder': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-strike': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-task-item': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-task-list': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-italic': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-link': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-list-item': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-ordered-list': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-placeholder': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-strike': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) + '@tiptap/extension-task-item': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) + '@tiptap/extension-task-list': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) '@tiptap/extension-underline': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) '@tiptap/pm': 2.6.6 - '@tiptap/react': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@tiptap/react': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@tiptap/starter-kit': 2.3.0(@tiptap/pm@2.6.6) lodash: 4.17.21 react: 18.2.0 @@ -14562,6 +14497,19 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + '@babel/helper-create-class-features-plugin@7.23.10(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14575,6 +14523,13 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14582,6 +14537,17 @@ snapshots: regexpu-core: 5.3.2 semver: 6.3.1 + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.4.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14593,6 +14559,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14639,6 +14616,16 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14657,6 +14644,13 @@ snapshots: '@babel/helper-plugin-utils@7.24.8': {} + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14664,6 +14658,13 @@ snapshots: '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14746,11 +14747,23 @@ snapshots: dependencies: '@babel/types': 7.25.6 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14758,12 +14771,26 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.25.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14772,6 +14799,12 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14785,6 +14818,12 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14797,18 +14836,39 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.25.2 @@ -14818,12 +14878,25 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14831,10 +14904,19 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14845,11 +14927,21 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14860,42 +14952,82 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.23.7)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.23.7)': dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': + '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 @@ -14905,67 +15037,136 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14974,6 +15175,15 @@ snapshots: '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.2) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -14983,22 +15193,45 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15006,6 +15239,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-split-export-declaration': 7.22.6 + globals: 11.12.0 + '@babel/plugin-transform-classes@7.23.8(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15018,58 +15263,117 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/template': 7.25.0 + '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/template': 7.25.0 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-for-of@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15077,28 +15381,58 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15107,6 +15441,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-simple-access': 7.22.5 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15116,6 +15459,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-identifier': 7.22.20 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15126,6 +15479,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15134,29 +15495,61 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15166,18 +15559,37 @@ snapshots: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-replace-supers': 7.22.20(@babel/core@7.25.2) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15185,17 +15597,36 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15204,11 +15635,21 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15250,6 +15691,17 @@ snapshots: '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) '@babel/types': 7.25.6 + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15267,17 +15719,40 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + regenerator-transform: 0.15.2 + '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 regenerator-transform: 0.15.2 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-runtime@7.23.9(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15290,32 +15765,66 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-spread@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript@7.23.6(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -15324,29 +15833,138 @@ snapshots: '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 + '@babel/preset-env@7.23.7(@babel/core@7.23.7)': + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/core': 7.23.7 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.23.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.23.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.23.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.23.7) + babel-plugin-polyfill-corejs2: 0.4.8(@babel/core@7.23.7) + babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.7) + babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.7) + core-js-compat: 3.35.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/preset-env@7.23.7(@babel/core@7.25.2)': dependencies: '@babel/compat-data': 7.23.5 @@ -15440,6 +16058,13 @@ snapshots: '@babel/helper-validator-option': 7.24.8 '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.25.2) + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.23.7)': + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.25.6 + esutils: 2.0.3 + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -17816,6 +18441,13 @@ snapshots: '@react-native/assets-registry@0.73.1': {} + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-plugin-codegen@0.73.4(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -17823,6 +18455,54 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.23.7) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.23.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) + '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.23.7) + '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.23.7) + '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.23.7) + '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-react-jsx': 7.25.2(@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) + '@babel/plugin-transform-runtime': 7.23.9(@babel/core@7.23.7) + '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) + '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.23.7) + '@babel/template': 7.25.0 + '@react-native/babel-plugin-codegen': 0.73.4(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.23.7) + react-refresh: 0.14.0 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17871,6 +18551,19 @@ snapshots: - '@babel/preset-env' - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/parser': 7.25.3 + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + flow-parser: 0.206.0 + glob: 7.2.3 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + '@react-native/codegen@0.73.3(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/parser': 7.25.3 @@ -17905,6 +18598,27 @@ snapshots: - supports-color - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-tools': 12.3.7(encoding@0.1.13) + '@react-native/dev-middleware': 0.73.8(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + chalk: 4.1.2 + execa: 5.1.1 + metro: 0.80.5(encoding@0.1.13) + metro-config: 0.80.5(encoding@0.1.13) + metro-core: 0.80.5 + node-fetch: 2.6.12(encoding@0.1.13) + readline: 1.3.0 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + '@react-native/community-cli-plugin@0.73.18(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native-community/cli-server-api': 12.3.7(encoding@0.1.13) @@ -17951,6 +18665,16 @@ snapshots: '@react-native/js-polyfills@0.73.1': {} + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))': + dependencies: + '@babel/core': 7.23.7 + '@react-native/babel-preset': 0.73.21(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + hermes-parser: 0.15.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + '@react-native/metro-babel-transformer@0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': dependencies: '@babel/core': 7.25.2 @@ -17961,7 +18685,7 @@ snapshots: - '@babel/preset-env' - supports-color - '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))': + '@react-native/metro-config@0.73.5(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)': dependencies: '@react-native/js-polyfills': 0.73.1 '@react-native/metro-babel-transformer': 0.73.15(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)) @@ -17970,7 +18694,10 @@ snapshots: transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' + - bufferutil + - encoding - supports-color + - utf-8-validate '@react-native/normalize-color@2.1.0': {} @@ -17978,6 +18705,12 @@ snapshots: '@react-native/normalize-colors@0.74.84': {} + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + '@react-native/virtualized-lists@0.73.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))': dependencies: invariant: 2.2.4 @@ -18080,14 +18813,6 @@ snapshots: picomatch: 2.3.1 rollup: 2.79.1 - '@rollup/pluginutils@5.1.0(rollup@2.79.1)': - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - optionalDependencies: - rollup: 2.79.1 - '@rollup/pluginutils@5.1.0(rollup@4.13.0)': dependencies: '@types/estree': 1.0.5 @@ -19537,56 +20262,29 @@ snapshots: dependencies: '@tiptap/pm': 2.6.6 - '@tiptap/extension-blockquote@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-blockquote@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-bold@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-bold@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-bubble-menu@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - tippy.js: 6.3.7 - '@tiptap/extension-bubble-menu@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/pm': 2.6.6 tippy.js: 6.3.7 - '@tiptap/extension-bullet-list@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-bullet-list@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-code-block@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - '@tiptap/extension-code-block@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/pm': 2.6.6 - '@tiptap/extension-code@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-code@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19596,10 +20294,6 @@ snapshots: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/extension-text-style': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6)) - '@tiptap/extension-document@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-document@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19624,10 +20318,6 @@ snapshots: dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-heading@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-heading@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19636,21 +20326,11 @@ snapshots: dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-history@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - '@tiptap/extension-history@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/pm': 2.6.6 - '@tiptap/extension-horizontal-rule@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - '@tiptap/extension-horizontal-rule@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19660,30 +20340,16 @@ snapshots: dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-italic@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-italic@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-link@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - linkifyjs: 4.1.1 - '@tiptap/extension-link@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/pm': 2.6.6 linkifyjs: 4.1.1 - '@tiptap/extension-list-item@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-list-item@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19694,10 +20360,6 @@ snapshots: '@tiptap/pm': 2.6.6 '@tiptap/suggestion': 2.6.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-ordered-list@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-ordered-list@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19706,38 +20368,20 @@ snapshots: dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-placeholder@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - '@tiptap/extension-placeholder@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/pm': 2.6.6 - '@tiptap/extension-strike@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-strike@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-task-item@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - '@tiptap/extension-task-item@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) '@tiptap/pm': 2.6.6 - '@tiptap/extension-task-list@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-task-list@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -19775,15 +20419,6 @@ snapshots: prosemirror-transform: 1.10.0 prosemirror-view: 1.33.4 - '@tiptap/react@2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': - dependencies: - '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) - '@tiptap/extension-bubble-menu': 2.3.0(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/extension-floating-menu': 2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6) - '@tiptap/pm': 2.6.6 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - '@tiptap/react@2.6.6(@tiptap/core@2.6.6(@tiptap/pm@2.6.6))(@tiptap/pm@2.6.6)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@tiptap/core': 2.6.6(@tiptap/pm@2.6.6) @@ -20322,33 +20957,33 @@ snapshots: graphql: 15.8.0 wonka: 4.0.15 - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))': dependencies: - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) - '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))': + '@vitejs/plugin-basic-ssl@1.1.0(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))': dependencies: - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) - '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))': + '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))': 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.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))': + '@vitejs/plugin-react@4.2.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))': 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.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - supports-color @@ -20814,6 +21449,15 @@ snapshots: cosmiconfig: 7.1.0 resolve: 1.22.4 + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.23.7): + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.8(@babel/core@7.25.2): dependencies: '@babel/compat-data': 7.25.2 @@ -20823,6 +21467,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20831,6 +21483,14 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + core-js-compat: 3.35.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20839,6 +21499,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.23.7): + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.23.7) + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -20850,6 +21517,12 @@ snapshots: babel-plugin-syntax-trailing-function-commas@7.0.0-beta.0: {} + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.23.7): + dependencies: + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.23.7) + transitivePeerDependencies: + - '@babel/core' + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.25.2): dependencies: '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.25.2) @@ -24380,6 +25053,31 @@ snapshots: jsc-safe-url@0.2.4: {} + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.23.7)): + dependencies: + '@babel/core': 7.25.2 + '@babel/parser': 7.25.6 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.25.2) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.25.2) + '@babel/preset-env': 7.23.7(@babel/core@7.23.7) + '@babel/preset-flow': 7.23.3(@babel/core@7.25.2) + '@babel/preset-typescript': 7.23.3(@babel/core@7.25.2) + '@babel/register': 7.23.7(@babel/core@7.25.2) + babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) + chalk: 4.1.2 + flow-parser: 0.206.0 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.21.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + jscodeshift@0.14.0(@babel/preset-env@7.23.7(@babel/core@7.25.2)): dependencies: '@babel/core': 7.25.2 @@ -25726,8 +26424,8 @@ snapshots: dependencies: fflate: 0.4.8 - posthog-react-native@2.11.3(jwrxiw3lzqzjxcpw4mvkvmmdfa): - optionalDependencies: + ? posthog-react-native@2.11.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(expo-application@5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-device@5.9.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-file-system@16.0.9(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(expo-localization@14.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)))(react-native-device-info@10.12.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))) + : optionalDependencies: '@react-native-async-storage/async-storage': 1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)) '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) expo-application: 5.8.3(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)) @@ -26070,17 +26768,17 @@ snapshots: react-cosmos-core: 6.1.1 react-cosmos-renderer: 6.1.1 - react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)): + react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: react-cosmos-core: 6.1.1 react-cosmos-dom: 6.1.1 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) - react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): + react-cosmos-plugin-vite@6.1.1(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: react-cosmos-core: 6.1.1 react-cosmos-dom: 6.1.1 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) react-cosmos-renderer@6.1.1: dependencies: @@ -26413,6 +27111,13 @@ snapshots: transitivePeerDependencies: - encoding + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): + dependencies: + escape-string-regexp: 2.0.0 + invariant: 2.2.4 + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0) + react-native-webview@13.6.4(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: escape-string-regexp: 2.0.0 @@ -26474,6 +27179,55 @@ snapshots: - supports-color - utf-8-validate + react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-android': 12.3.7(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 12.3.7(encoding@0.1.13) + '@react-native/assets-registry': 0.73.1 + '@react-native/codegen': 0.73.3(@babel/preset-env@7.23.7(@babel/core@7.23.7)) + '@react-native/community-cli-plugin': 0.73.18(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13) + '@react-native/gradle-plugin': 0.73.4 + '@react-native/js-polyfills': 0.73.1 + '@react-native/normalize-colors': 0.73.2 + '@react-native/virtualized-lists': 0.73.4(react-native@0.73.9(@babel/core@7.23.7)(@babel/preset-env@7.23.7(@babel/core@7.23.7))(encoding@0.1.13)(react@18.2.0)) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + deprecated-react-native-prop-types: 5.0.0 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.5 + metro-source-map: 0.80.5 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 4.28.5 + react-refresh: 0.14.0 + react-shallow-renderer: 16.15.0(react@18.2.0) + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@babel/core' + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0): dependencies: '@jest/create-cache-key-function': 29.7.0 @@ -26891,15 +27645,6 @@ snapshots: serialize-javascript: 4.0.0 terser: 5.19.1 - rollup-plugin-visualizer@5.12.0(rollup@2.79.1): - dependencies: - open: 8.4.2 - picomatch: 2.3.1 - source-map: 0.7.4 - yargs: 17.7.2 - optionalDependencies: - rollup: 2.79.1 - rollup-plugin-visualizer@5.12.0(rollup@4.13.0): dependencies: open: 8.4.2 @@ -28201,14 +28946,14 @@ snapshots: react-dom: 18.2.0(react@18.2.0) redux: 4.2.0 - vite-node@0.34.6(@types/node@20.10.8)(terser@5.19.1): + vite-node@0.34.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 mlly: 1.5.0 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -28219,13 +28964,13 @@ snapshots: - supports-color - terser - vite-node@1.2.2(@types/node@20.14.10)(terser@5.19.1): + vite-node@1.2.2(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -28236,13 +28981,13 @@ snapshots: - supports-color - terser - vite-node@1.5.0(@types/node@20.14.10)(terser@5.19.1): + vite-node@1.5.0(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): dependencies: cac: 6.7.14 debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - '@types/node' - less @@ -28253,57 +28998,57 @@ snapshots: - supports-color - terser - vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): + vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) workbox-build: 7.0.0(@types/babel__core@7.20.5) workbox-window: 7.0.0 transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): + vite-plugin-pwa@0.17.5(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1))(workbox-build@7.0.0(@types/babel__core@7.20.5))(workbox-window@7.0.0): dependencies: debug: 4.3.4 fast-glob: 3.3.2 pretty-bytes: 6.1.1 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) workbox-build: 7.0.0(@types/babel__core@7.20.5) workbox-window: 7.0.0 transitivePeerDependencies: - supports-color - vite-plugin-singlefile@2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): + vite-plugin-singlefile@2.0.1(rollup@4.13.0)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: micromatch: 4.0.5 rollup: 4.13.0 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) - vite-plugin-svgr@4.2.0(rollup@2.79.1)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(terser@5.19.1)): + vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: - '@rollup/pluginutils': 5.1.0(rollup@2.79.1) + '@rollup/pluginutils': 5.1.0(rollup@4.13.0) '@svgr/core': 8.1.0(typescript@5.4.5) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(terser@5.19.1)): + vite-plugin-svgr@4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.13.0) '@svgr/core': 8.1.0(typescript@5.4.5) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5)) - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite@5.1.6(@types/node@20.10.8)(terser@5.19.1): + vite@5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1): dependencies: esbuild: 0.19.12 postcss: 8.4.35 @@ -28311,9 +29056,10 @@ snapshots: optionalDependencies: '@types/node': 20.10.8 fsevents: 2.3.3 + lightningcss: 1.19.0 terser: 5.19.1 - vite@5.1.6(@types/node@20.14.10)(terser@5.19.1): + vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1): dependencies: esbuild: 0.19.12 postcss: 8.4.35 @@ -28321,9 +29067,10 @@ snapshots: optionalDependencies: '@types/node': 20.14.10 fsevents: 2.3.3 + lightningcss: 1.19.0 terser: 5.19.1 - vitest@0.34.6(jsdom@23.2.0)(terser@5.19.1): + vitest@0.34.6(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): dependencies: '@types/chai': 4.3.11 '@types/chai-subset': 1.3.5 @@ -28346,8 +29093,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.7.0 - vite: 5.1.6(@types/node@20.10.8)(terser@5.19.1) - vite-node: 0.34.6(@types/node@20.10.8)(terser@5.19.1) + vite: 5.1.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) + vite-node: 0.34.6(@types/node@20.10.8)(lightningcss@1.19.0)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: jsdom: 23.2.0 @@ -28360,7 +29107,7 @@ snapshots: - supports-color - terser - vitest@1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1): + vitest@1.2.2(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): dependencies: '@vitest/expect': 1.2.2 '@vitest/runner': 1.2.2 @@ -28380,8 +29127,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.2 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) - vite-node: 1.2.2(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite-node: 1.2.2(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.10 @@ -28395,7 +29142,7 @@ snapshots: - supports-color - terser - vitest@1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(terser@5.19.1): + vitest@1.5.0(@types/node@20.14.10)(jsdom@23.2.0)(lightningcss@1.19.0)(terser@5.19.1): dependencies: '@vitest/expect': 1.5.0 '@vitest/runner': 1.5.0 @@ -28414,8 +29161,8 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.4 - vite: 5.1.6(@types/node@20.14.10)(terser@5.19.1) - vite-node: 1.5.0(@types/node@20.14.10)(terser@5.19.1) + vite: 5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) + vite-node: 1.5.0(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1) why-is-node-running: 2.2.2 optionalDependencies: '@types/node': 20.14.10 From df1a3f9af1af2b61e7ada02cd468bbdd66bd1878 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 22 Oct 2024 08:22:20 -0500 Subject: [PATCH 164/259] new web: fix build issue --- packages/app/hooks/useConfigureUrbitClient.ts | 12 +++--------- packages/app/platform/polyfills.native.ts | 13 +++++++++++++ packages/app/platform/polyfills.ts | 6 ++++++ 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 packages/app/platform/polyfills.native.ts create mode 100644 packages/app/platform/polyfills.ts diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 0a1de8177a..41797ec4c7 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -2,21 +2,15 @@ import { createDevLogger, sync } from '@tloncorp/shared/dist'; import { ClientParams } from '@tloncorp/shared/dist/api'; import { configureClient } from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; -//@ts-expect-error no typedefs -import { fetch as streamingFetch } from 'react-native-fetch-api'; -//@ts-expect-error no typedefs -import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; -//@ts-expect-error no typedefs -import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; import { ENABLED_LOGGERS } from '../constants'; import { useShip } from '../contexts/ship'; import { getShipAccessCode } from '../lib/hostingApi'; import { resetDb } from '../lib/nativeDb'; +import { initializePolyfills, platformFetch } from '../platform/polyfills'; import { useHandleLogout } from './useHandleLogout'; -polyfillReadableStream(); -polyfillEncoding(); +initializePolyfills(); let abortController = new AbortController(); @@ -49,7 +43,7 @@ const apiFetch: typeof fetch = (input, { ...init } = {}) => { // to stream the request. reactNative: { textStreaming: true }, }; - return streamingFetch(input, newInit); + return platformFetch(input, newInit); }; export function useConfigureUrbitClient() { diff --git a/packages/app/platform/polyfills.native.ts b/packages/app/platform/polyfills.native.ts new file mode 100644 index 0000000000..3940da3547 --- /dev/null +++ b/packages/app/platform/polyfills.native.ts @@ -0,0 +1,13 @@ +//@ts-expect-error no typedefs +import { fetch as streamingFetch } from 'react-native-fetch-api'; +//@ts-expect-error no typedefs +import { polyfill as polyfillEncoding } from 'react-native-polyfill-globals/src/encoding'; +//@ts-expect-error no typedefs +import { polyfill as polyfillReadableStream } from 'react-native-polyfill-globals/src/readable-stream'; + +export const initializePolyfills = () => { + polyfillReadableStream(); + polyfillEncoding(); +} + +export const platformFetch = streamingFetch; diff --git a/packages/app/platform/polyfills.ts b/packages/app/platform/polyfills.ts new file mode 100644 index 0000000000..f57c8aa030 --- /dev/null +++ b/packages/app/platform/polyfills.ts @@ -0,0 +1,6 @@ + +export const initializePolyfills = () => { + // no-op +} + +export const platformFetch = window.fetch; From 3a8a0a74d8998a106763074f623d9830cfaa8406 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 22 Oct 2024 14:47:20 +0000 Subject: [PATCH 165/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 69f85fcb3b..53049d403c 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v4.tb96j.2436j.2paik.8b0lq.kc7m8.glob' 0v4.tb96j.2436j.2paik.8b0lq.kc7m8] + glob-http+['https://bootstrap.urbit.org/glob-0v4.l0ohn.clu7u.59ejp.p6lmk.jr5to.glob' 0v4.l0ohn.clu7u.59ejp.p6lmk.jr5to] base+'groups' version+[6 4 2] website+'https://tlon.io' From f97c6f34d688c1c2bc273dd75d4061b7394a2b57 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 11:56:52 -0400 Subject: [PATCH 166/259] wip stash --- apps/tlon-mobile/src/App.main.tsx | 23 ++-- apps/tlon-mobile/src/OnboardingStack.tsx | 3 + .../src/hooks/useReviveSavedOnboarding.ts | 128 ++++++++++++++++++ .../screens/Onboarding/CheckVerifyScreen.tsx | 5 +- .../Onboarding/RequestPhoneVerifyScreen.tsx | 4 + .../screens/Onboarding/SignUpEmailScreen.tsx | 15 +- .../Onboarding/SignUpPasswordScreen.tsx | 1 + .../src/screens/Onboarding/WelcomeScreen.tsx | 1 + packages/app/contexts/signup.tsx | 98 ++++++++------ packages/app/hooks/useHandleLogout.ts | 5 +- packages/app/lib/hostingApi.ts | 8 +- packages/shared/src/db/domainTypes.ts | 54 ++++++++ packages/shared/src/db/index.ts | 1 + packages/shared/src/db/keyValue.ts | 88 ++++++++++++ packages/shared/src/logic/analytics.ts | 1 + 15 files changed, 369 insertions(+), 66 deletions(-) create mode 100644 apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts create mode 100644 packages/shared/src/db/domainTypes.ts diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 5dc76b7cde..bc78de2ee2 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -47,7 +47,6 @@ initializeCrashReporter(crashlytics(), PlatformState); // Android notification tap handler passes initial params here const App = () => { const isDarkMode = useIsDarkMode(); - const { isLoading, isAuthenticated } = useShip(); const [connected, setConnected] = useState(true); const signupContext = useSignupContext(); @@ -73,7 +72,7 @@ const App = () => { - ) : isAuthenticated && !signupContext.didBeginSignup ? ( + ) : isAuthenticated && !signupContext.email ? ( ) : ( @@ -130,11 +129,11 @@ export default function ConnectedApp() { enable: process.env.NODE_ENV !== 'test', }} > - - - - - + + + + + @@ -144,11 +143,11 @@ export default function ConnectedApp() { navigationContainerRef={navigationContainerRef} /> )} - - - - - + + + + + diff --git a/apps/tlon-mobile/src/OnboardingStack.tsx b/apps/tlon-mobile/src/OnboardingStack.tsx index 6d7ccead88..025d045f2a 100644 --- a/apps/tlon-mobile/src/OnboardingStack.tsx +++ b/apps/tlon-mobile/src/OnboardingStack.tsx @@ -1,6 +1,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { useScreenOptions } from '@tloncorp/app/hooks/useScreenOptions'; +import { useReviveSavedOnboarding } from './hooks/useReviveSavedOnboarding'; import { CheckVerifyScreen } from './screens/Onboarding/CheckVerifyScreen'; import { EULAScreen } from './screens/Onboarding/EULAScreen'; import { InventoryCheckScreen } from './screens/Onboarding/InventoryCheckScreen'; @@ -29,6 +30,8 @@ export function OnboardingStack() { headerShown: false, }; + useReviveSavedOnboarding(); + return ( >(); + const { hostingApi } = useOnboardingContext(); + const { isAuthenticated } = useShip(); + const signupContext = useSignupContext(); + + const getOnboardingRouteStack = useCallback( + async (savedSignup: SignupParams) => { + if (!savedSignup.email || !savedSignup.password) { + logger.log('no stored email or password'); + return null; + } + + const stack: { name: keyof OnboardingStackParamList; params?: any }[] = [ + { name: 'Welcome' }, + { name: 'SignUpEmail' }, + { + name: 'SignUpPassword', + params: { + email: savedSignup.email, + }, + }, + ]; + + logger.log('getting hosting user', { + email: savedSignup.email, + password: savedSignup.password, + }); + const user = await hostingApi.logInHostingUser({ + email: savedSignup.email, + password: savedSignup.password, + }); + logger.log(`got hosting user`, user); + + if (user.requirePhoneNumberVerification) { + logger.log(`needs phone verify`); + stack.push({ name: 'RequestPhoneVerify', params: { user } }); + return stack; + } + + if (!user.verified) { + logger.log(`need email verify`); + stack.push({ name: 'CheckVerify', params: { user } }); + return stack; + } + + stack.push({ name: 'SetNickname', params: { user } }); + if (!savedSignup.nickname) { + logger.log('needs nickname'); + return stack; + } + + stack.push({ name: 'SetTelemetry', params: { user } }); + if (savedSignup.telemetry === undefined) { + logger.log('needs telemetry'); + return stack; + } + + logger.log('ready to reserve ship'); + stack.push({ name: 'ReserveShip', params: { user } }); + return stack; + }, + [hostingApi] + ); + + const execute = useCallback(async () => { + const savedSignup = await signupData.getValue(); + if (!savedSignup.email) { + logger.log('no saved onboarding session found'); + return; + } + + if (isAuthenticated) { + logger.log( + 'found saved session, but already authenticated. Running post signup logic' + ); + signupContext.handlePostSignup(); + return; + } + + if (inviteMeta) { + logger.log(`attempting to revive onboarding session`, savedSignup); + const routeStack = await getOnboardingRouteStack(savedSignup); + logger.log(`computed onboarding route stack`, routeStack); + + if (routeStack) { + logger.trackEvent(AnalyticsEvent.OnboardingSessionRevived, { + route: routeStack[routeStack.length - 1], + }); + navigation.reset({ + index: 1, + routes: routeStack, + }); + } + } + }, [ + getOnboardingRouteStack, + inviteMeta, + isAuthenticated, + navigation, + signupContext, + ]); + + useEffect(() => { + try { + execute(); + } catch (e) { + logger.trackError('Error reviving onboarding', { + errorMessage: e.message, + errorStack: e.stack, + }); + } + }, []); +} diff --git a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx index df511f6f0f..657eed457a 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx @@ -104,6 +104,7 @@ export const CheckVerifyScreen = ({ value={code} length={codeLength} onChange={handleCodeChanged} + isEmail={isEmail} error={error} /> void; error?: string; @@ -169,7 +172,7 @@ function CodeInput({ return ( { const { hostingApi } = useOnboardingContext(); const signupParams = useSignupParams(); + const signupContext = useSignupContext(); const lureMeta = useLureMetadata(); const { @@ -73,6 +75,10 @@ export const SignUpEmailScreen = ({ navigation, route: { params } }: Props) => { email, lure: signupParams.lureId, }); + + signupContext.setOnboardingValues({ + email, + }); navigation.navigate('SignUpPassword', { email, }); @@ -91,12 +97,17 @@ export const SignUpEmailScreen = ({ navigation, route: { params } }: Props) => { setIsSubmitting(false); }); + const goBack = useCallback(() => { + signupContext.clear(); + navigation.goBack(); + }, [navigation, signupContext]); + return ( navigation.goBack()} + backAction={goBack} isLoading={isSubmitting} rightControls={ diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx index becdc19d12..cc91d0d41a 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx @@ -100,6 +100,7 @@ export const SignUpPasswordScreen = ({ priorityToken: signupParams.priorityToken, }); signupContext.setDidSignup(true); + signupContext.setOnboardingValues({ password }); } catch (err) { console.error('Error signing up user:', err); if (err instanceof Error) { diff --git a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx index cdee8e26b4..ba9e399ffa 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx @@ -1,3 +1,4 @@ +import { useIsFocused } from '@react-navigation/native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; import { setDidShowBenefitsSheet } from '@tloncorp/shared/dist/db'; diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index 19d236d76d..fd0d7ab04a 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -1,5 +1,6 @@ import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; +import { SignupParams, signupData } from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import { createContext, @@ -16,22 +17,8 @@ import { connectNotifyProvider } from '../lib/notificationsApi'; const logger = createDevLogger('signup', true); -export interface SignupParams { - nickname?: string; - notificationToken?: string; - telemetry?: boolean; - didBeginSignup?: boolean; - didCompleteSignup?: boolean; - isOngoing?: boolean; - hostingUser: { id: string } | null; - reservedNodeId: string | null; - bootPhase: NodeBootPhase; - userWasReadyAt?: number; -} - type SignupValues = Omit; const defaultValues: SignupValues = { - nickname: undefined, hostingUser: null, reservedNodeId: null, }; @@ -43,6 +30,8 @@ interface SignupContext extends SignupParams { setTelemetry: (telemetry: boolean) => void; setDidSignup: (didSignup: boolean) => void; setDidCompleteSignup: (value: boolean) => void; + setOnboardingValues: (newValues: Partial) => void; + handlePostSignup: () => void; clear: () => void; } @@ -53,6 +42,8 @@ const defaultMethods = { setDidSignup: () => {}, setHostingUser: () => {}, setDidCompleteSignup: () => {}, + setOnboardingValues: () => {}, + handlePostSignup: () => {}, clear: () => {}, }; @@ -63,7 +54,12 @@ const SignupContext = createContext({ }); export const SignupProvider = ({ children }: { children: React.ReactNode }) => { - const [values, setValues] = useState(defaultValues); + // const [values, setValues] = useState(defaultValues); + const { + value: values, + setValue: setValues, + resetValue: resetValues, + } = signupData.useStorageItem(); const { bootPhase, bootReport } = useBootSequence(values); const isOngoing = useMemo(() => { @@ -73,6 +69,16 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { ); }, [values.didBeginSignup, values.didCompleteSignup, bootPhase]); + const setOnboardingValues = useCallback( + (newValues: Partial) => { + setValues((current) => ({ + ...current, + ...newValues, + })); + }, + [] + ); + const setDidSignup = useCallback((didBeginSignup: boolean) => { setValues((current) => ({ ...current, @@ -121,42 +127,46 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { const clear = useCallback(() => { logger.log('clearing signup context'); - setValues(defaultValues); + resetValues(); }, []); + const handlePostSignup = useCallback(() => { + try { + logger.log('running post-signup actions'); + const postSignupParams = { + nickname: values.nickname, + telemetry: values.telemetry, + notificationToken: values.notificationToken, + }; + runPostSignupActions(postSignupParams); + logger.trackEvent('hosted signup report', { + bootDuration: bootReport + ? bootReport.completedAt - bootReport.startedAt + : null, + userSatWaitingFor: values.userWasReadyAt + ? Date.now() - values.userWasReadyAt + : null, + timeUnit: 'ms', + }); + } catch (e) { + logger.trackError('post signup error', { + errorMessage: e.message, + errorStack: e.stack, + }); + } finally { + setTimeout(() => clear(), 2000); + } + }, [values, bootReport, clear]); + useEffect(() => { if ( values.didBeginSignup && values.didCompleteSignup && bootPhase === NodeBootPhase.READY ) { - try { - logger.log('running post-signup actions'); - const postSignupParams = { - nickname: values.nickname, - telemetry: values.telemetry, - notificationToken: values.notificationToken, - }; - handlePostSignup(postSignupParams); - logger.trackEvent('hosted signup report', { - bootDuration: bootReport - ? bootReport.completedAt - bootReport.startedAt - : null, - userSatWaitingFor: values.userWasReadyAt - ? Date.now() - values.userWasReadyAt - : null, - timeUnit: 'ms', - }); - } catch (e) { - logger.trackError('post signup error', { - errorMessage: e.message, - errorStack: e.stack, - }); - } finally { - setTimeout(() => clear(), 2000); - } + handlePostSignup(); } - }, [values, bootPhase, clear, bootReport]); + }, [values, bootPhase, clear, bootReport, handlePostSignup]); return ( { setTelemetry, setDidSignup, setDidCompleteSignup, + setOnboardingValues, + handlePostSignup, clear, }} > @@ -188,7 +200,7 @@ export function useSignupContext() { return context; } -async function handlePostSignup(params: { +async function runPostSignupActions(params: { nickname?: string; telemetry?: boolean; notificationToken?: string; diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index 267fd5fec4..24ab201e0e 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -5,6 +5,7 @@ import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; import { clearShipInfo, useShip } from '../contexts/ship'; +import { useSignupContext } from '../contexts/signup'; import { removeHostingAuthTracking, removeHostingToken, @@ -17,6 +18,7 @@ const logger = createDevLogger('logout', true); export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { const { clearShip } = useShip(); const { clearLure, clearDeepLink } = useBranch(); + const signupContext = useSignupContext(); const handleLogout = useCallback(async () => { api.queryClient.clear(); @@ -29,13 +31,14 @@ export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { clearLure(); clearDeepLink(); clearSplashDismissed(); + signupContext.clear(); if (!resetDb) { logger.trackError('could not reset db on logout'); return; } // delay DB reset to next tick to avoid race conditions setTimeout(() => resetDb()); - }, [clearDeepLink, clearLure, clearShip, resetDb]); + }, [clearDeepLink, clearLure, clearShip, resetDb, signupContext]); return handleLogout; } diff --git a/packages/app/lib/hostingApi.ts b/packages/app/lib/hostingApi.ts index a13ee67477..2cd614b1fa 100644 --- a/packages/app/lib/hostingApi.ts +++ b/packages/app/lib/hostingApi.ts @@ -2,13 +2,7 @@ import * as logic from '@tloncorp/shared/dist/logic'; import { Buffer } from 'buffer'; import { Platform } from 'react-native'; -import { - API_AUTH_PASSWORD, - API_AUTH_USERNAME, - API_URL, - DEFAULT_LURE, - DEFAULT_PRIORITY_TOKEN, -} from '../constants'; +import { API_AUTH_PASSWORD, API_AUTH_USERNAME, API_URL } from '../constants'; import type { BootPhase, HostedShipStatus, diff --git a/packages/shared/src/db/domainTypes.ts b/packages/shared/src/db/domainTypes.ts new file mode 100644 index 0000000000..1aceed2543 --- /dev/null +++ b/packages/shared/src/db/domainTypes.ts @@ -0,0 +1,54 @@ +/* + * Signup + */ +export interface SignupParams { + email?: string; + password?: string; + nickname?: string; + notificationToken?: string; + telemetry?: boolean; + didBeginSignup?: boolean; + didCompleteSignup?: boolean; + isOngoing?: boolean; + hostingUser: { id: string } | null; + reservedNodeId: string | null; + bootPhase: NodeBootPhase; + userWasReadyAt?: number; +} + +export enum NodeBootPhase { + IDLE = 1, + RESERVING = 2, + BOOTING = 3, + AUTHENTICATING = 4, + CONNECTING = 5, + CHECKING_FOR_INVITE = 6, + ACCEPTING_INVITES = 7, + READY = 200, + ERROR = 400, +} + +export const BootPhaseExplanations: Record = { + [NodeBootPhase.IDLE]: 'Waiting to start', + [NodeBootPhase.RESERVING]: 'Reserving your p2p node', + [NodeBootPhase.BOOTING]: 'Booting your p2p node', + [NodeBootPhase.AUTHENTICATING]: 'Authenticating with your node', + [NodeBootPhase.CONNECTING]: 'Establishing a connection to your node', + [NodeBootPhase.CHECKING_FOR_INVITE]: 'Confirming your invites were received', + [NodeBootPhase.ACCEPTING_INVITES]: + 'Initializing the conversations you were invited to', + [NodeBootPhase.READY]: 'Your node is ready', + [NodeBootPhase.ERROR]: 'Your node errored while initializing', +}; + +export const BootPhaseNames: Record = { + [NodeBootPhase.IDLE]: 'Idle', + [NodeBootPhase.RESERVING]: 'Reserving', + [NodeBootPhase.BOOTING]: 'Booting', + [NodeBootPhase.AUTHENTICATING]: 'Authenticating', + [NodeBootPhase.CONNECTING]: 'Connecting', + [NodeBootPhase.CHECKING_FOR_INVITE]: 'Checking for Invites', + [NodeBootPhase.ACCEPTING_INVITES]: 'Accepting Invites', + [NodeBootPhase.READY]: 'Ready', + [NodeBootPhase.ERROR]: 'Error', +}; diff --git a/packages/shared/src/db/index.ts b/packages/shared/src/db/index.ts index c39ced301c..059095474d 100644 --- a/packages/shared/src/db/index.ts +++ b/packages/shared/src/db/index.ts @@ -6,3 +6,4 @@ export * from './modelBuilders'; export * from './keyValue'; export { setClient } from './client'; export * from './changeListener'; +export * from './domainTypes'; diff --git a/packages/shared/src/db/keyValue.ts b/packages/shared/src/db/keyValue.ts index 91c635fd3d..cee78de864 100644 --- a/packages/shared/src/db/keyValue.ts +++ b/packages/shared/src/db/keyValue.ts @@ -1,4 +1,10 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; +import { + UseMutationResult, + UseQueryResult, + useMutation, + useQuery, +} from '@tanstack/react-query'; import { StorageConfiguration, @@ -8,6 +14,7 @@ import { } from '../api'; import { createDevLogger } from '../debug'; import * as ub from '../urbit'; +import { NodeBootPhase, SignupParams } from './domainTypes'; const logger = createDevLogger('keyValueStore', false); @@ -197,3 +204,84 @@ export async function getDidShowBenefitsSheet() { const didShow = await AsyncStorage.getItem('didShowBenefitsSheet'); return didShow === 'true' ? true : false; } + +// new pattern +type StorageItem = { + key: string; + defaultValue: T; + isSecure?: boolean; + serialize?: (value: T) => string; + deserialize?: (value: string) => T; +}; + +const createStorageItem = (config: StorageItem) => { + const { + key, + defaultValue, + serialize = JSON.stringify, + deserialize = JSON.parse, + } = config; + + const getValue = async (): Promise => { + const value = await AsyncStorage.getItem(key); + return value ? deserialize(value) : defaultValue; + }; + + const resetValue = async (): Promise => { + await AsyncStorage.setItem(key, serialize(defaultValue)); + queryClient.invalidateQueries({ queryKey: [key] }); + return defaultValue; + }; + + const setValue = async (valueInput: T | ((curr: T) => T)): Promise => { + let newValue: T; + if (valueInput instanceof Function) { + const currValue = await getValue(); + newValue = valueInput(currValue); + } else { + newValue = valueInput; + } + + await AsyncStorage.setItem(key, serialize(newValue)); + queryClient.invalidateQueries({ queryKey: [key] }); + }; + + function useValue() { + // TODo + } + + function useStorageItem() { + const { data: value } = useQuery({ queryKey: [key], queryFn: getValue }); + return { + value: value === undefined ? defaultValue : value, + setValue, + resetValue, + }; + } + + return { getValue, setValue, resetValue, useStorageItem }; +}; + +export const currentOnboardingRoute = createStorageItem({ + key: 'currentOnboardingRoute', + defaultValue: null, +}); +export const useCurrentOnboardingRoute = currentOnboardingRoute.useStorageItem; + +export const signupData = createStorageItem({ + key: 'signupData', + defaultValue: { + hostingUser: null, + reservedNodeId: null, + bootPhase: NodeBootPhase.IDLE, + }, +}); + +// in component +// const didShowBenefitsSheet = useDidShowBenefitsSheet(); +// OR +// const { value, setValue } = useDidShowBenefitsSheet(); + +// import {didShowBenefitsSheet } from '../store/kv'; + +// didshowBenefitsSheet.useValue() diff --git a/packages/shared/src/logic/analytics.ts b/packages/shared/src/logic/analytics.ts index ae01fb7bca..f86422a452 100644 --- a/packages/shared/src/logic/analytics.ts +++ b/packages/shared/src/logic/analytics.ts @@ -1,3 +1,4 @@ export enum AnalyticsEvent { InviteShared = 'Invite Link Shared', + OnboardingSessionRevived = 'Onboarding Session Revived', } From 17bd67b5819423a227e2e6cb9396970c51ec0965 Mon Sep 17 00:00:00 2001 From: David Lee Date: Tue, 22 Oct 2024 12:07:06 -0700 Subject: [PATCH 167/259] Hardcode detail view layout --- .../src/types/PostCollectionConfiguration.ts | 15 +++------------ packages/ui/src/components/Channel/Scroller.tsx | 9 +++------ packages/ui/src/components/Channel/index.tsx | 6 ++++++ packages/ui/src/components/DetailView.tsx | 4 ++-- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/packages/shared/src/types/PostCollectionConfiguration.ts b/packages/shared/src/types/PostCollectionConfiguration.ts index 8e6bf53d18..8054151368 100644 --- a/packages/shared/src/types/PostCollectionConfiguration.ts +++ b/packages/shared/src/types/PostCollectionConfiguration.ts @@ -13,16 +13,13 @@ export type PostCollectionLayoutType = // If the caller has a non-nullable `channel`, they can then get a // non-nullable return value - nice, right? export function layoutTypeFromChannel( - channel: db.Channel, - detailView?: boolean + channel: db.Channel ): PostCollectionLayoutType; export function layoutTypeFromChannel( - channel: db.Channel | null, - detailView?: boolean + channel: db.Channel | null ): PostCollectionLayoutType | null; export function layoutTypeFromChannel( - channel: db.Channel | null, - detailView?: boolean + channel: db.Channel | null ): PostCollectionLayoutType | null { switch (channel?.type) { case null: @@ -38,15 +35,9 @@ export function layoutTypeFromChannel( return 'compact-list-bottom-to-top'; case 'notebook': - if (detailView) { - return 'compact-list-bottom-to-top'; - } return 'comfy-list-top-to-bottom'; case 'gallery': - if (detailView) { - return 'compact-list-bottom-to-top'; - } return 'grid'; } } diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 96518ade72..06950a654d 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -1,4 +1,5 @@ import { + PostCollectionLayoutType, configurationFromChannel, layoutForType, layoutTypeFromChannel, @@ -94,7 +95,7 @@ const Scroller = forwardRef( renderEmptyComponent: renderEmptyComponentFn, posts, channel, - detailView, + collectionLayoutType, firstUnreadId, unreadCount, onStartReached, @@ -119,7 +120,7 @@ const Scroller = forwardRef( renderEmptyComponent?: () => ReactElement; posts: db.Post[] | null; channel: db.Channel; - detailView?: boolean; + collectionLayoutType: PostCollectionLayoutType; firstUnreadId?: string | null; unreadCount?: number | null; onStartReached?: () => void; @@ -142,10 +143,6 @@ const Scroller = forwardRef( }, ref ) => { - const collectionLayoutType = useMemo( - () => layoutTypeFromChannel(channel, detailView), - [channel] - ); const collectionLayout = useMemo( () => layoutForType(collectionLayoutType), [collectionLayoutType] diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 8fd84bbcef..7db328fd58 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -271,6 +271,11 @@ export function Channel({ } }, [goBack, draftInputPresentationMode, draftInputRef, setEditingPost]); + const collectionLayoutType = useMemo( + () => layoutTypeFromChannel(channel), + [channel] + ); + return ( @@ -328,6 +333,7 @@ export function Channel({ renderEmptyComponent={renderEmptyComponent} anchor={scrollerAnchor} posts={posts} + collectionLayoutType={collectionLayoutType} hasNewerPosts={hasNewerPosts} hasOlderPosts={hasOlderPosts} editingPost={editingPost} diff --git a/packages/ui/src/components/DetailView.tsx b/packages/ui/src/components/DetailView.tsx index 86b3d0329d..56114e46be 100644 --- a/packages/ui/src/components/DetailView.tsx +++ b/packages/ui/src/components/DetailView.tsx @@ -64,7 +64,7 @@ export const DetailView = ({ inverted renderItem={ChatMessage} channel={channel} - detailView + collectionLayoutType="compact-list-bottom-to-top" editingPost={editingPost} setEditingPost={setEditingPost} posts={resolvedPosts ?? null} @@ -98,7 +98,7 @@ export const DetailView = ({ setActiveMessage, setEditingPost, headerMode, - channel + channel, ]); return isChat ? ( From 84eb69bcbf571e59dc4364e0f74ff9b332e2f5e0 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 15:15:44 -0400 Subject: [PATCH 168/259] progress --- apps/tlon-mobile/app.config.ts | 3 + .../src/hooks/useReviveSavedOnboarding.ts | 6 +- .../screens/Onboarding/CheckVerifyScreen.tsx | 1 + .../screens/Onboarding/ReserveShipScreen.tsx | 7 +- .../screens/Onboarding/SetNicknameScreen.tsx | 7 +- .../screens/Onboarding/SetTelemetryScreen.tsx | 2 +- .../screens/Onboarding/SignUpEmailScreen.tsx | 16 +++- .../Onboarding/SignUpPasswordScreen.tsx | 11 ++- .../screens/Onboarding/TlonLoginScreen.tsx | 15 ++- packages/app/constants.ts | 7 ++ packages/app/contexts/signup.tsx | 93 +++---------------- packages/app/hooks/useBootSequence.ts | 19 ++-- packages/shared/src/db/domainTypes.ts | 4 +- packages/shared/src/db/keyValue.ts | 9 +- 14 files changed, 91 insertions(+), 109 deletions(-) diff --git a/apps/tlon-mobile/app.config.ts b/apps/tlon-mobile/app.config.ts index 5ab6d07cd8..e2ecd6872a 100644 --- a/apps/tlon-mobile/app.config.ts +++ b/apps/tlon-mobile/app.config.ts @@ -34,6 +34,9 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ defaultInviteLinkUrl: process.env.DEFAULT_INVITE_LINK_URL, defaultShipLoginUrl: process.env.DEFAULT_SHIP_LOGIN_URL, defaultShipLoginAccessCode: process.env.DEFAULT_SHIP_LOGIN_ACCESS_CODE, + defaultOnboardingPassword: process.env.ONBOARDING_DEFAULT_PASSWORD, + defaultOnboardingTlonEmail: process.env.ONBOARDING_DEFAULT_TLON_EMAIL, + defaultOnboardingNickname: process.env.ONBOARDING_DEFAULT_NICKNAME, recaptchaSiteKeyAndroid: process.env.RECAPTCHA_SITE_KEY_ANDROID, recaptchaSiteKeyIOS: process.env.RECAPTCHA_SITE_KEY_IOS, enabledLoggers: process.env.ENABLED_LOGGERS, diff --git a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts index e18f380fda..8d23f55418 100644 --- a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts +++ b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts @@ -93,9 +93,11 @@ export function useReviveSavedOnboarding() { } if (inviteMeta) { - logger.log(`attempting to revive onboarding session`, savedSignup); + logger.crumb(`attempting to revive onboarding session`, { + email: savedSignup.email, + }); const routeStack = await getOnboardingRouteStack(savedSignup); - logger.log(`computed onboarding route stack`, routeStack); + logger.crumb(`computed onboarding route stack`, routeStack); if (routeStack) { logger.trackEvent(AnalyticsEvent.OnboardingSessionRevived, { diff --git a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx index 657eed457a..5c6cea0f0c 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx @@ -52,6 +52,7 @@ export const CheckVerifyScreen = ({ }); signupContext.setHostingUser(user); + signupContext.kickOffBootSequence(); navigation.navigate('SetNickname', { user }); } catch (err) { console.error('Error submitting verification:', err); diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index 747b9daef8..6251bd62d9 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -32,10 +32,11 @@ export const ReserveShipScreen = ({ navigation }: Props) => { ); useEffect(() => { - if (!signupContext.didCompleteSignup) { - signupContext.setDidCompleteSignup(true); + if (!signupContext.didCompleteOnboarding) { + signupContext.setOnboardingValues({ didCompleteOnboarding: true }); } - }, [signupContext]); + signupContext.kickOffBootSequence(); + }, []); return ( diff --git a/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx index 8e789ce9ec..d608f65ba3 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx @@ -1,4 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { DEFAULT_ONBOARDING_NICKNAME } from '@tloncorp/app/constants'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { requestNotificationToken } from '@tloncorp/app/lib/notifications'; import { trackError } from '@tloncorp/app/utils/posthog'; @@ -44,7 +45,7 @@ export const SetNicknameScreen = ({ setValue, } = useForm({ defaultValues: { - nickname: '', + nickname: DEFAULT_ONBOARDING_NICKNAME ?? '', notificationToken: undefined, }, }); @@ -53,11 +54,11 @@ export const SetNicknameScreen = ({ const onSubmit = handleSubmit(({ nickname, notificationToken }) => { if (nickname) { - signupContext.setNickname(nickname); + signupContext.setOnboardingValues({ nickname }); } if (notificationToken) { - signupContext.setNotificationToken(notificationToken); + signupContext.setOnboardingValues({ notificationToken }); } navigation.navigate('SetTelemetry', { diff --git a/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx index 29a46b78c6..3426bcfcb3 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx @@ -28,7 +28,7 @@ export const SetTelemetryScreen = ({ const signupContext = useSignupContext(); const handleNext = useCallback(() => { - signupContext.setTelemetry(isEnabled); + signupContext.setOnboardingValues({ telemetry: isEnabled }); if (!isEnabled) { postHog?.optOut(); diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx index 0111d96e3c..821379aa65 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx @@ -1,5 +1,8 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { EMAIL_REGEX } from '@tloncorp/app/constants'; +import { + DEFAULT_ONBOARDING_TLON_EMAIL, + EMAIL_REGEX, +} from '@tloncorp/app/constants'; import { useLureMetadata, useSignupParams, @@ -31,6 +34,11 @@ type FormData = { email: string; }; +function genDefaultEmail() { + const entropy = String(Math.random()).slice(2, 12); + return `${DEFAULT_ONBOARDING_TLON_EMAIL}+test${entropy}@tlon.io`; +} + export const SignUpEmailScreen = ({ navigation, route: { params } }: Props) => { const [isSubmitting, setIsSubmitting] = useState(false); const { hostingApi } = useOnboardingContext(); @@ -45,7 +53,11 @@ export const SignUpEmailScreen = ({ navigation, route: { params } }: Props) => { formState: { errors, isValid }, setError, trigger, - } = useForm(); + } = useForm({ + defaultValues: { + email: DEFAULT_ONBOARDING_TLON_EMAIL ? genDefaultEmail() : '', + }, + }); const onSubmit = handleSubmit(async ({ email }) => { setIsSubmitting(true); diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx index cc91d0d41a..2d23390951 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx @@ -1,5 +1,8 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { RECAPTCHA_SITE_KEY } from '@tloncorp/app/constants'; +import { + DEFAULT_ONBOARDING_PASSWORD, + RECAPTCHA_SITE_KEY, +} from '@tloncorp/app/constants'; import { useSignupParams } from '@tloncorp/app/contexts/branch'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { setEulaAgreed } from '@tloncorp/app/utils/eula'; @@ -58,6 +61,8 @@ export const SignUpPasswordScreen = ({ } = useForm({ defaultValues: { eulaAgreed: false, + password: DEFAULT_ONBOARDING_PASSWORD ?? '', + confirmPassword: DEFAULT_ONBOARDING_PASSWORD ?? '', }, mode: 'onBlur', }); @@ -99,7 +104,6 @@ export const SignUpPasswordScreen = ({ lure: signupParams.lureId, priorityToken: signupParams.priorityToken, }); - signupContext.setDidSignup(true); signupContext.setOnboardingValues({ password }); } catch (err) { console.error('Error signing up user:', err); @@ -190,9 +194,8 @@ export const SignUpPasswordScreen = ({ }, [recaptchaError]); const goBackHandler = useCallback(() => { - signupContext.setDidSignup(false); navigation.goBack(); - }, [navigation, signupContext]); + }, [navigation]); return ( diff --git a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx index 314a110896..c09a776b34 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx @@ -5,6 +5,7 @@ import { EMAIL_REGEX, } from '@tloncorp/app/constants'; import { useShip } from '@tloncorp/app/contexts/ship'; +import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { getShipAccessCode, getShipsWithStatus, @@ -40,6 +41,7 @@ type FormData = { export const TlonLoginScreen = ({ navigation }: Props) => { const [isSubmitting, setIsSubmitting] = useState(false); const [remoteError, setRemoteError] = useState(); + const signupContext = useSignupContext(); const { control, setFocus, @@ -47,7 +49,6 @@ export const TlonLoginScreen = ({ navigation }: Props) => { formState: { errors, isValid }, getValues, trigger, - watch, } = useForm({ defaultValues: { email: DEFAULT_TLON_LOGIN_EMAIL, @@ -113,15 +114,27 @@ export const TlonLoginScreen = ({ navigation }: Props) => { ); } } else { + signupContext.setOnboardingValues({ + email: params.email, + password: params.password, + }); navigation.navigate('ReserveShip', { user }); } } else if (user.requirePhoneNumberVerification && !user.phoneNumber) { + signupContext.setOnboardingValues({ + email: params.email, + password: params.password, + }); navigation.navigate('RequestPhoneVerify', { user }); } else { if (user.requirePhoneNumberVerification) { await requestPhoneVerify(user.id, user.phoneNumber ?? ''); } + signupContext.setOnboardingValues({ + email: params.email, + password: params.password, + }); navigation.navigate('CheckVerify', { user, }); diff --git a/packages/app/constants.ts b/packages/app/constants.ts index 6edcd1b889..b4506e18fe 100644 --- a/packages/app/constants.ts +++ b/packages/app/constants.ts @@ -33,6 +33,13 @@ export const DEFAULT_INVITE_LINK_URL = extra.defaultInviteLinkUrl ?? ''; export const DEFAULT_SHIP_LOGIN_URL = extra.defaultShipLoginUrl ?? ''; export const DEFAULT_SHIP_LOGIN_ACCESS_CODE = extra.defaultShipLoginAccessCode ?? ''; +export const DEFAULT_ONBOARDING_PASSWORD = + extra.defaultOnboardingPassword ?? ''; +export const DEFAULT_ONBOARDING_TLON_EMAIL = + extra.defaultOnboardingTlonEmail ?? ''; +export const DEFAULT_ONBOARDING_NICKNAME = + extra.defaultOnboardingNickname ?? ''; + export const ENABLED_LOGGERS = extra.enabledLoggers?.split(',') ?? []; export const IGNORE_COSMOS = extra.ignoreCosmos === 'true'; export const TLON_EMPLOYEE_GROUP = extra.TlonEmployeeGroup ?? ''; diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index fd0d7ab04a..3f00ea5a2c 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -2,14 +2,7 @@ import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; import { SignupParams, signupData } from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; -import { - createContext, - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react'; +import { createContext, useCallback, useContext, useEffect } from 'react'; import { useBootSequence } from '../hooks/useBootSequence'; import { NodeBootPhase } from '../lib/bootHelpers'; @@ -25,25 +18,17 @@ const defaultValues: SignupValues = { interface SignupContext extends SignupParams { setHostingUser: (hostingUser: { id: string }) => void; - setNickname: (nickname: string | undefined) => void; - setNotificationToken: (notificationToken: string | undefined) => void; - setTelemetry: (telemetry: boolean) => void; - setDidSignup: (didSignup: boolean) => void; - setDidCompleteSignup: (value: boolean) => void; setOnboardingValues: (newValues: Partial) => void; + kickOffBootSequence: () => void; handlePostSignup: () => void; clear: () => void; } const defaultMethods = { - setNickname: () => {}, - setNotificationToken: () => {}, - setTelemetry: () => {}, - setDidSignup: () => {}, setHostingUser: () => {}, - setDidCompleteSignup: () => {}, setOnboardingValues: () => {}, handlePostSignup: () => {}, + kickOffBootSequence: () => {}, clear: () => {}, }; @@ -54,20 +39,13 @@ const SignupContext = createContext({ }); export const SignupProvider = ({ children }: { children: React.ReactNode }) => { - // const [values, setValues] = useState(defaultValues); const { value: values, setValue: setValues, resetValue: resetValues, } = signupData.useStorageItem(); - const { bootPhase, bootReport } = useBootSequence(values); - - const isOngoing = useMemo(() => { - return ( - values.didBeginSignup && - (!values.didCompleteSignup || bootPhase !== NodeBootPhase.READY) - ); - }, [values.didBeginSignup, values.didCompleteSignup, bootPhase]); + const { bootPhase, bootReport, kickOffBootSequence } = + useBootSequence(values); const setOnboardingValues = useCallback( (newValues: Partial) => { @@ -76,59 +54,23 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { ...newValues, })); }, - [] + [setValues] ); - const setDidSignup = useCallback((didBeginSignup: boolean) => { - setValues((current) => ({ - ...current, - didBeginSignup, - })); - }, []); - - const setDidCompleteSignup = useCallback((value: boolean) => { - setValues((current) => ({ - ...current, - didCompleteSignup: value, - userWasReadyAt: Date.now(), - })); - }, []); - - const setHostingUser = useCallback((hostingUser: { id: string }) => { - setValues((current) => ({ - ...current, - hostingUser, - })); - }, []); - - const setNickname = useCallback((nickname: string | undefined) => { - setValues((current) => ({ - ...current, - nickname, - })); - }, []); - - const setNotificationToken = useCallback( - (notificationToken: string | undefined) => { + const setHostingUser = useCallback( + (hostingUser: { id: string }) => { setValues((current) => ({ ...current, - notificationToken, + hostingUser, })); }, - [] + [setValues] ); - const setTelemetry = useCallback((telemetry: boolean) => { - setValues((current) => ({ - ...current, - telemetry, - })); - }, []); - const clear = useCallback(() => { logger.log('clearing signup context'); resetValues(); - }, []); + }, [resetValues]); const handlePostSignup = useCallback(() => { try { @@ -159,11 +101,7 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { }, [values, bootReport, clear]); useEffect(() => { - if ( - values.didBeginSignup && - values.didCompleteSignup && - bootPhase === NodeBootPhase.READY - ) { + if (values.didCompleteOnboarding && bootPhase === NodeBootPhase.READY) { handlePostSignup(); } }, [values, bootPhase, clear, bootReport, handlePostSignup]); @@ -173,15 +111,10 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { value={{ ...values, bootPhase, - isOngoing, setHostingUser, - setNickname, - setNotificationToken, - setTelemetry, - setDidSignup, - setDidCompleteSignup, setOnboardingValues, handlePostSignup, + kickOffBootSequence, clear, }} > diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index e060d43f32..41b7699d8d 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -53,11 +53,15 @@ export function useBootSequence({ // detect when we're ready to start the sequence, kick things off // by advancing past IDLE - useEffect(() => { - if (bootPhase === NodeBootPhase.IDLE && hostingUser?.id) { - setBootPhase(NodeBootPhase.RESERVING); - } - }, [bootPhase, hostingUser]); + // useEffect(() => { + // if (bootPhase === NodeBootPhase.IDLE && hostingUser?.id) { + // setBootPhase(NodeBootPhase.RESERVING); + // } + // }, [bootPhase, hostingUser]); + + const kickOffBootSequence = useCallback(() => { + setBootPhase(NodeBootPhase.RESERVING); + }, [setBootPhase]); const runBootPhase = useCallback(async (): Promise => { if (!hostingUser) { @@ -290,7 +294,7 @@ export function useBootSequence({ NodeBootPhase.CHECKING_FOR_INVITE, ].includes(bootPhase); if (isInOptionalPhase && beenRunningTooLong) { - logger.trackError('accept invites abort'); + logger.trackError('accept invites abort', { inviteId: lureMeta?.id }); setBootPhase(NodeBootPhase.READY); return; } @@ -298,7 +302,7 @@ export function useBootSequence({ if (![NodeBootPhase.IDLE, NodeBootPhase.READY].includes(bootPhase)) { runBootSequence(); } - }, [runBootPhase, setBootPhase, bootPhase, bootStepCounter]); + }, [runBootPhase, setBootPhase, bootPhase, bootStepCounter, lureMeta?.id]); // once finished, set the report useEffect(() => { @@ -312,6 +316,7 @@ export function useBootSequence({ return { bootPhase, + kickOffBootSequence, bootReport: report, }; } diff --git a/packages/shared/src/db/domainTypes.ts b/packages/shared/src/db/domainTypes.ts index 1aceed2543..d53bae24b6 100644 --- a/packages/shared/src/db/domainTypes.ts +++ b/packages/shared/src/db/domainTypes.ts @@ -7,9 +7,7 @@ export interface SignupParams { nickname?: string; notificationToken?: string; telemetry?: boolean; - didBeginSignup?: boolean; - didCompleteSignup?: boolean; - isOngoing?: boolean; + didCompleteOnboarding?: boolean; hostingUser: { id: string } | null; reservedNodeId: string | null; bootPhase: NodeBootPhase; diff --git a/packages/shared/src/db/keyValue.ts b/packages/shared/src/db/keyValue.ts index cee78de864..2b931a0ef7 100644 --- a/packages/shared/src/db/keyValue.ts +++ b/packages/shared/src/db/keyValue.ts @@ -16,7 +16,7 @@ import { createDevLogger } from '../debug'; import * as ub from '../urbit'; import { NodeBootPhase, SignupParams } from './domainTypes'; -const logger = createDevLogger('keyValueStore', false); +const logger = createDevLogger('keyValueStore', true); export const ACTIVITY_SEEN_MARKER_QUERY_KEY = [ 'activity', @@ -230,6 +230,7 @@ const createStorageItem = (config: StorageItem) => { const resetValue = async (): Promise => { await AsyncStorage.setItem(key, serialize(defaultValue)); queryClient.invalidateQueries({ queryKey: [key] }); + logger.log(`reset value ${key}`); return defaultValue; }; @@ -244,10 +245,12 @@ const createStorageItem = (config: StorageItem) => { await AsyncStorage.setItem(key, serialize(newValue)); queryClient.invalidateQueries({ queryKey: [key] }); + logger.log(`set value ${key}`, newValue); }; function useValue() { - // TODo + const { data: value } = useQuery({ queryKey: [key], queryFn: getValue }); + return value === undefined ? defaultValue : value; } function useStorageItem() { @@ -259,7 +262,7 @@ const createStorageItem = (config: StorageItem) => { }; } - return { getValue, setValue, resetValue, useStorageItem }; + return { getValue, setValue, resetValue, useValue, useStorageItem }; }; export const currentOnboardingRoute = createStorageItem({ From 33a357c093b55b1acf876840153a554e808d79fd Mon Sep 17 00:00:00 2001 From: Dan Brewster Date: Tue, 22 Oct 2024 15:58:10 -0400 Subject: [PATCH 169/259] design polish #1 (#4089) * fix gallery post detail screen title fixes TLON-3055 * mark logout action destructive fixes TLON-3060 * simplify and standardize bug report screen fixes TLON-3040 * move feature flags to settings root fixes TLON-3039 * polish profile edit sequence fixes TLON-3060 * fix type error --- .../tlon-mobile/src/fixtures/Form.fixture.tsx | 11 +- .../fixtures/UserProfileScreen.fixture.tsx | 1 + .../app/features/settings/AppInfoScreen.tsx | 22 -- .../app/features/settings/ProfileScreen.tsx | 53 +++-- .../features/settings/UserBugReportScreen.tsx | 199 +++++------------- .../app/features/top/UserProfileScreen.tsx | 5 + .../ui/src/components/AttachmentSheet.tsx | 44 ++-- .../src/components/EditProfileScreenView.tsx | 182 ++++++++++------ .../src/components/FavoriteGroupsDisplay.tsx | 151 ++++--------- packages/ui/src/components/Form/Form.tsx | 45 ++-- .../src/components/Form/controlledFields.tsx | 91 ++++++-- packages/ui/src/components/Form/inputs.tsx | 158 +++++++++++++- packages/ui/src/components/PostScreenView.tsx | 4 +- .../ui/src/components/ProfileScreenView.tsx | 14 +- .../src/components/UserProfileScreenView.tsx | 8 + 15 files changed, 565 insertions(+), 423 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/Form.fixture.tsx b/apps/tlon-mobile/src/fixtures/Form.fixture.tsx index 75bb6d554a..2552f0c490 100644 --- a/apps/tlon-mobile/src/fixtures/Form.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Form.fixture.tsx @@ -2,10 +2,12 @@ import { Button, ScrollView } from '@tloncorp/ui'; import * as Form from '@tloncorp/ui/src/components/Form'; import { useMemo } from 'react'; import { useForm } from 'react-hook-form'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { FixtureWrapper } from './FixtureWrapper'; const FormFixture = () => { + const insets = useSafeAreaInsets(); const { control, reset } = useForm({ mode: 'onChange', defaultValues: { @@ -13,6 +15,7 @@ const FormFixture = () => { description: '', number: 'one', listItem: 'chat', + image: undefined, }, }); @@ -50,8 +53,14 @@ const FormFixture = () => { ]; return ( - + + {}} connectionStatus={{ complete: true, status: 'yes' }} + onPressEdit={() => {}} onPressGroup={() => { console.log('group pressed'); }} diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index daeb29defd..c4e2aedf04 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -2,10 +2,8 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; import * as store from '@tloncorp/shared/dist/store'; import { AppSetting, - ListItem, ScreenHeader, SizableText, - Stack, View, YStack, } from '@tloncorp/ui'; @@ -13,7 +11,6 @@ import { preSig } from '@urbit/aura'; import * as Application from 'expo-application'; import * as Updates from 'expo-updates'; import { useMemo } from 'react'; -import { useCallback } from 'react'; import { Platform } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; @@ -29,10 +26,6 @@ export function AppInfoScreen(props: Props) { const { data: appInfo } = store.useAppInfo(); const easUpdateDisplay = useMemo(() => getEasUpdateDisplay(Updates), []); - const onPressPreviewFeatures = useCallback(() => { - props.navigation.navigate('FeatureFlags'); - }, [props.navigation]); - return ( )} - - - - - - Feature previews - - - - diff --git a/packages/app/features/settings/ProfileScreen.tsx b/packages/app/features/settings/ProfileScreen.tsx index 62120564d1..3920ceb4fe 100644 --- a/packages/app/features/settings/ProfileScreen.tsx +++ b/packages/app/features/settings/ProfileScreen.tsx @@ -1,4 +1,5 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { useMutableRef } from '@tloncorp/shared'; import { NavBarView, ProfileScreenView, View } from '@tloncorp/ui'; import { useCallback, useEffect, useState } from 'react'; @@ -17,41 +18,67 @@ export default function ProfileScreen(props: Props) { const currentUserId = useCurrentUserId(); const { dmLink } = useDMLureLink(); const hasHostedAuth = useHasHostedAuth(); + const navigationRef = useMutableRef(props.navigation); const onAppInfoPressed = useCallback(() => { - props.navigation.navigate('AppInfo'); - }, [props.navigation]); + navigationRef.current.navigate('AppInfo'); + }, [navigationRef]); const onPushNotifPressed = useCallback(() => { - props.navigation.navigate('PushNotificationSettings'); - }, [props.navigation]); + navigationRef.current.navigate('PushNotificationSettings'); + }, [navigationRef]); const onBlockedUsersPressed = useCallback(() => { - props.navigation.navigate('BlockedUsers'); - }, [props.navigation]); + navigationRef.current.navigate('BlockedUsers'); + }, [navigationRef]); const onManageAccountPressed = useCallback(() => { - props.navigation.navigate('ManageAccount'); - }, [props.navigation]); + navigationRef.current.navigate('ManageAccount'); + }, [navigationRef]); + + const onExperimentalFeaturesPressed = useCallback(() => { + navigationRef.current.navigate('FeatureFlags'); + }, [navigationRef]); + + const onProfilePressed = useCallback(() => { + navigationRef.current.navigate('UserProfile', { userId: currentUserId }); + }, [currentUserId, navigationRef]); + + const onSendBugReportPressed = useCallback(() => { + navigationRef.current.navigate('WompWomp'); + }, [navigationRef]); + + const onNavigateToHome = useCallback(() => { + navigationRef.current.navigate('ChatList'); + }, [navigationRef]); + + const onNavigateToNotifications = useCallback(() => { + navigationRef.current.navigate('Activity'); + }, [navigationRef]); + + const onNavigateToProfileSettings = useCallback(() => { + navigationRef.current.navigate('Profile'); + }, [navigationRef]); return ( props.navigation.navigate('EditProfile')} + onProfilePressed={onProfilePressed} onLogoutPressed={handleLogout} - onSendBugReportPressed={() => props.navigation.navigate('WompWomp')} + onSendBugReportPressed={onSendBugReportPressed} onAppInfoPressed={onAppInfoPressed} onNotificationSettingsPressed={onPushNotifPressed} onBlockedUsersPressed={onBlockedUsersPressed} onManageAccountPressed={onManageAccountPressed} + onExperimentalFeaturesPressed={onExperimentalFeaturesPressed} dmLink={dmLink} /> props.navigation.navigate('ChatList')} - navigateToNotifications={() => props.navigation.navigate('Activity')} - navigateToProfileSettings={() => props.navigation.navigate('Profile')} + navigateToHome={onNavigateToHome} + navigateToNotifications={onNavigateToNotifications} + navigateToProfileSettings={onNavigateToProfileSettings} currentRoute="Profile" currentUserId={currentUserId} /> diff --git a/packages/app/features/settings/UserBugReportScreen.tsx b/packages/app/features/settings/UserBugReportScreen.tsx index a53257c37f..846f04762e 100644 --- a/packages/app/features/settings/UserBugReportScreen.tsx +++ b/packages/app/features/settings/UserBugReportScreen.tsx @@ -1,53 +1,24 @@ -import { useIsFocused } from '@react-navigation/native'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { ErrorReporter } from '@tloncorp/shared/dist'; import { Button, - Circle, - FormTextInput, - Icon, + ControlledTextareaField, + FormFrame, + FormText, ScreenHeader, - SizableText, - View, - XStack, + ScrollView, YStack, } from '@tloncorp/ui'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback } from 'react'; import { useForm } from 'react-hook-form'; -import { Keyboard, KeyboardAvoidingView, Platform } from 'react-native'; -import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { Alert, KeyboardAvoidingView } from 'react-native'; import { RootStackParamList } from '../../navigation/types'; type Props = NativeStackScreenProps; export function UserBugReportScreen({ navigation }: Props) { - const [keyboardVisible, setKeyboardVisible] = useState(false); - const isFocused = useIsFocused(); - const isFocusedRef = useRef(isFocused); - const insets = useSafeAreaInsets(); - const [state, setState] = useState<'initial' | 'sent'>('initial'); - - useEffect(() => { - const showEvent = - Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'; - const hideEvent = - Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide'; - - const keyboardDidShowListener = Keyboard.addListener(showEvent, () => { - setKeyboardVisible(true); - }); - const keyboardDidHideListener = Keyboard.addListener(hideEvent, () => { - setKeyboardVisible(false); - }); - - return () => { - keyboardDidHideListener.remove(); - keyboardDidShowListener.remove(); - }; - }, []); - - const { control, handleSubmit, formState } = useForm({ + const { control, handleSubmit } = useForm({ defaultValues: { additionalNotes: '', }, @@ -55,7 +26,6 @@ export function UserBugReportScreen({ navigation }: Props) { const sendBugReport = useCallback( (submission: { additionalNotes: string }) => { - console.log(`got additional notes`, submission.additionalNotes); const reporter = new ErrorReporter( 'User manually submitted a bug report' ); @@ -64,127 +34,54 @@ export function UserBugReportScreen({ navigation }: Props) { reporter.log(submission.additionalNotes); } reporter.report(null); - setState('sent'); - setTimeout(() => { - if (isFocusedRef.current) { - navigation.goBack(); - } - }, 3000); + Alert.alert( + 'Bug report sent', + 'Our team will investigate. Thank you for your feedback!', + [{ text: 'OK', onPress: () => navigation.goBack() }] + ); }, [navigation] ); return ( - + <> navigation.goBack() : undefined} + backAction={() => navigation.goBack()} /> - Keyboard.dismiss()} - > - - {!keyboardVisible && ( - - - - - Send a bug report - - If you experienced an issue, let us know! Sending reports helps - us improve the app for everyone. - - - )} - - {state === 'initial' ? ( - <> - - Information to help us diagnose the issue will be - automatically attached. - - - - Additional Notes - - - - - ) : ( - - - - - Report sent - - - Our team will investigate. Thank you for your feedback! - - - )} - - - - - + + + + + If you experienced an issue, let us know! Sending reports helps us + improve the app for everyone. + + + + Information to help us diagnose the issue will be automatically + attached. + + + + + + ); } diff --git a/packages/app/features/top/UserProfileScreen.tsx b/packages/app/features/top/UserProfileScreen.tsx index e18c9d8198..ae92cfb193 100644 --- a/packages/app/features/top/UserProfileScreen.tsx +++ b/packages/app/features/top/UserProfileScreen.tsx @@ -49,6 +49,10 @@ export function UserProfileScreen({ route: { params }, navigation }: Props) { [selectedGroup] ); + const handlePressEdit = useCallback(() => { + navigation.push('EditProfile'); + }, [navigation]); + return ( navigation.goBack()} connectionStatus={connectionStatus} onPressGroup={setSelectedGroup} + onPressEdit={handlePressEdit} /> [ - createActionGroup( - 'neutral', - { - title: 'Photo Library', - description: 'Choose a photo from your library', - action: pickImage, - }, - { - title: 'Take a Photo', - description: 'Use your camera to take a photo', - action: takePicture, - }, - showClearOption && { - title: 'Clear', - description: 'Remove attached media', - action: onClearAttachments, - } + () => + createActionGroups( + [ + 'neutral', + { + title: 'Photo Library', + description: 'Choose a photo from your library', + action: pickImage, + }, + { + title: 'Take a Photo', + description: 'Use your camera to take a photo', + action: takePicture, + }, + ], + showClearOption && [ + 'negative', + { + title: 'Clear', + description: 'Remove attached media', + action: onClearAttachments, + }, + ] ), - ], [onClearAttachments, pickImage, showClearOption, takePicture] ); diff --git a/packages/ui/src/components/EditProfileScreenView.tsx b/packages/ui/src/components/EditProfileScreenView.tsx index f5bc6b6124..329df348c4 100644 --- a/packages/ui/src/components/EditProfileScreenView.tsx +++ b/packages/ui/src/components/EditProfileScreenView.tsx @@ -2,14 +2,20 @@ import * as api from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; import { useCallback, useState } from 'react'; import { useForm } from 'react-hook-form'; -import { Keyboard } from 'react-native'; +import { Alert } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { ScrollView, View, YStack } from 'tamagui'; +import { ScrollView, View, XStack } from 'tamagui'; import { useContact, useCurrentUserId } from '../contexts'; -import { EditablePofileImages } from './EditableProfileImages'; +import { SigilAvatar } from './Avatar'; import { FavoriteGroupsDisplay } from './FavoriteGroupsDisplay'; -import { ControlledTextField, ControlledTextareaField, Field } from './Form'; +import { + ControlledImageField, + ControlledTextField, + ControlledTextareaField, + Field, + FormFrame, +} from './Form'; import KeyboardAvoidingView from './KeyboardAvoidingView'; import { ScreenHeader } from './ScreenHeader'; @@ -34,29 +40,45 @@ export function EditProfileScreenView(props: Props) { const { control, handleSubmit, - formState: { errors, isDirty }, + formState: { isDirty, isValid }, } = useForm({ + mode: 'onChange', defaultValues: { nickname: userContact?.nickname ?? '', bio: userContact?.bio ?? '', + avatarImage: userContact?.avatarImage ?? undefined, }, }); - const onSavePressed = useCallback(() => { + const handlePressDone = useCallback(() => { if (isDirty) { - return handleSubmit((formData) => { + handleSubmit((formData) => { props.onSaveProfile(formData); + props.onGoBack(); })(); + } else { + props.onGoBack(); } }, [handleSubmit, isDirty, props]); - const handlePressDone = () => { - props.onGoBack(); - onSavePressed(); - }; - const handlePressCancel = () => { - props.onGoBack(); + if (isDirty) { + Alert.alert('Discard changes?', 'Your changes will not be saved.', [ + { + text: 'Cancel', + style: 'cancel', + }, + { + text: 'Discard', + style: 'destructive', + onPress: () => { + props.onGoBack(); + }, + }, + ]); + } else { + props.onGoBack(); + } }; const handleUpdatePinnedGroups = useCallback( @@ -70,69 +92,97 @@ export function EditProfileScreenView(props: Props) { return ( + Cancel + + } rightControls={ - + Done } /> - - - - - - - + + + + + { + return ( + + {children} + + + ); + }} + inputProps={{ placeholder: userContact?.id }} + rules={{ + maxLength: { + value: 30, + message: 'Your nickname is limited to 30 characters', + }, + }} + /> + + - + - - - - - + + + + + + diff --git a/packages/ui/src/components/FavoriteGroupsDisplay.tsx b/packages/ui/src/components/FavoriteGroupsDisplay.tsx index b368806642..4d64e463ba 100644 --- a/packages/ui/src/components/FavoriteGroupsDisplay.tsx +++ b/packages/ui/src/components/FavoriteGroupsDisplay.tsx @@ -1,47 +1,29 @@ import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { TouchableOpacity } from 'react-native'; +import { useCallback, useMemo, useState } from 'react'; import { SizableText, XStack } from 'tamagui'; import { useGroups } from '../contexts'; import { useAlphabeticallySegmentedGroups } from '../hooks/groupsSorters'; -import { GroupPreviewSheet } from './GroupPreviewSheet'; import { GroupSelectorSheet } from './GroupSelectorSheet'; import { GroupListItem, ListItem } from './ListItem'; import { WidgetPane } from './WidgetPane'; export function FavoriteGroupsDisplay(props: { groups: db.Group[]; - editable?: boolean; - secondaryColors?: boolean; onUpdate?: (groups: db.Group[]) => void; }) { const [selectorOpen, setSelectorOpen] = useState(false); - const [selectedGroup, setSelectedGroup] = useState(null); // if editable, get sorted groups to pass to the selector const allGroups = useGroups(); const titledGroups = useMemo(() => { - if (!props.editable) return []; return allGroups?.filter((g) => !!g.title) ?? []; - }, [allGroups, props.editable]); + }, [allGroups]); const alphaSegmentedGroups = useAlphabeticallySegmentedGroups({ groups: titledGroups, - enabled: props.editable, + enabled: true, }); - // first, make sure we grab group previews. We have no guarantee that our - // Urbit has ever heard about these - useEffect(() => { - if (props.groups.length && !props.editable) { - const groupIds = props.groups - .map((g) => g && g.id) - .filter(Boolean) as string[]; - store.syncGroupPreviews(groupIds); - } - }, [props.editable, props.groups]); - // finally, make sure what we display is the up to date values, falling back // to what was passed in const compositeGroups = useMemo(() => { @@ -82,97 +64,50 @@ export function FavoriteGroupsDisplay(props: { ); return ( - - {compositeGroups.length === 0 ? ( - <> - ) : ( - compositeGroups.map((group) => { - return ( - setSelectedGroup(group)} - pressStyle={{ - backgroundColor: props.secondaryColors - ? '$border' - : '$secondaryBackground', - }} - EndContent={ - props.editable ? ( - handleFavoriteGroupsChange(group)} - > - - - - - ) : ( - <> - ) - } - /> - ); - }) - )} - {props.editable && ( - <> - setSelectorOpen(true)} + + {compositeGroups.map((group) => { + return ( + - - Add a group - - + pressable={false} + EndContent={ handleFavoriteGroupsChange(group)} + backgroundColor={'transparent'} + color={'$tertiaryText'} /> - - - g.id)} - onSelect={handleFavoriteGroupsChange} - TopContent={SheetTopContent} + } + /> + ); + })} + setSelectorOpen(true)} + backgroundColor="unset" + pressable + > + + Add a group + + + - - )} - {selectedGroup && ( - setSelectedGroup(null)} - group={selectedGroup} - /> - )} + + + g.id)} + onSelect={handleFavoriteGroupsChange} + TopContent={SheetTopContent} + /> ); } diff --git a/packages/ui/src/components/Form/Form.tsx b/packages/ui/src/components/Form/Form.tsx index b27dcaa50b..9e6dddfbf2 100644 --- a/packages/ui/src/components/Form/Form.tsx +++ b/packages/ui/src/components/Form/Form.tsx @@ -12,6 +12,11 @@ export const FormFrame = styled(YStack, { gap: '$2xl', }); +export const FormText = styled(Text, { + size: '$body', + padding: '$xl', +}); + // Single field export const FieldContext = createStyledContext<{ accent?: Accent }>({ @@ -30,20 +35,32 @@ export const Field = React.memo( label?: string; error?: string; required?: boolean; - }>(({ children, label, required, error, ...props }, ref) => { - return ( - - {label ? ( - - {label} - {required ? '*' : null} - - ) : null} - {children} - {error && {error}} - - ); - }) + renderInputContainer?: (props: { + children: React.ReactNode; + }) => React.ReactNode; + }>( + ( + { children, label, required, error, renderInputContainer, ...props }, + ref + ) => { + return ( + + {label ? ( + + {label} + {required ? '*' : null} + + ) : null} + {renderInputContainer ? renderInputContainer({ children }) : children} + {error && {error}} + + ); + } + ) ); export const FieldLabel = React.memo( diff --git a/packages/ui/src/components/Form/controlledFields.tsx b/packages/ui/src/components/Form/controlledFields.tsx index cb98f2691e..700d836ab7 100644 --- a/packages/ui/src/components/Form/controlledFields.tsx +++ b/packages/ui/src/components/Form/controlledFields.tsx @@ -10,6 +10,7 @@ import { import { Field } from './Form'; import { + ImageInput, ListItemInput, ListItemInputOption, RadioInput, @@ -20,26 +21,41 @@ import { type ControlledFieldProps< TFieldValues extends FieldValues, TName extends Path, -> = { + TInputProps extends object, + TRequireInput = false, +> = ComponentProps & { name: TName; control: Control; label?: string; rules?: RegisterOptions; - renderInput: ( - controller: UseControllerReturn - ) => React.ReactElement; -}; + inputProps?: TInputProps; + hideError?: boolean; +} & (TRequireInput extends true + ? { + renderInput: ControlledFieldRenderInput; + } + : { + renderInput?: ControlledFieldRenderInput; + }); + +type ControlledFieldRenderInput< + TFieldValues extends FieldValues, + TName extends Path, +> = (controller: UseControllerReturn) => React.ReactNode; export const ControlledField = < TFieldValues extends FieldValues, TName extends Path, + TInputProps extends object, >({ name, label, control, rules, renderInput, -}: ControlledFieldProps) => { + hideError, + ...props +}: ControlledFieldProps) => { const controller = useController({ name, control, @@ -49,7 +65,8 @@ export const ControlledField = < {renderInput(controller)} @@ -60,9 +77,10 @@ export const ControlledTextField = < TFieldValues extends FieldValues, TName extends Path, >( - props: { inputProps?: ComponentProps } & Omit< - ControlledFieldProps, - 'renderInput' + props: ControlledFieldProps< + TFieldValues, + TName, + ComponentProps > ) => { const renderInput = useCallback( @@ -75,16 +93,17 @@ export const ControlledTextField = < }, [props.inputProps] ); - return ; + return ; }; export const ControlledTextareaField = < TFieldValues extends FieldValues, TName extends Path, >( - props: { inputProps?: ComponentProps } & Omit< - ControlledFieldProps, - 'renderInput' + props: ControlledFieldProps< + TFieldValues, + TName, + ComponentProps > ) => { const renderInput = useCallback( @@ -106,15 +125,44 @@ export const ControlledTextareaField = < return ; }; +export const ControlledImageField = < + TFieldValues extends FieldValues, + TName extends Path, +>( + props: ControlledFieldProps< + TFieldValues, + TName, + ComponentProps + > +) => { + const renderInput = useCallback( + ({ + field: { + onChange, + // we pull the ref off as this input doesn't support focus + ref: _ref, + ...field + }, + }: UseControllerReturn) => { + return ( + + ); + }, + [props.inputProps] + ); + return ; +}; + export const ControlledRadioField = < TFieldValues extends FieldValues, TName extends Path, >({ options, ...props -}: { options: RadioInputOption[] } & Omit< - ControlledFieldProps, - 'renderInput' +}: { options: RadioInputOption[] } & ControlledFieldProps< + TFieldValues, + TName, + ComponentProps >) => { const renderInput = useCallback( ({ @@ -133,9 +181,12 @@ export const ControlledListItemField = < >({ options, ...props -}: { options: ListItemInputOption[] } & Omit< - ControlledFieldProps, - 'renderInput' +}: { + options: ListItemInputOption[]; +} & ControlledFieldProps< + TFieldValues, + TName, + ComponentProps >) => { const renderInput = useCallback( ({ diff --git a/packages/ui/src/components/Form/inputs.tsx b/packages/ui/src/components/Form/inputs.tsx index a108a6e14e..26f5eb786e 100644 --- a/packages/ui/src/components/Form/inputs.tsx +++ b/packages/ui/src/components/Form/inputs.tsx @@ -1,9 +1,22 @@ -import React, { ComponentProps, ReactElement } from 'react'; -import { TextInput as RNTextInput } from 'react-native'; -import { ScrollView, View, XStack, YStack, styled } from 'tamagui'; - +import { ImagePickerAsset } from 'expo-image-picker'; +import React, { + ComponentProps, + ReactElement, + useCallback, + useEffect, + useState, +} from 'react'; +import { Alert, TextInput as RNTextInput } from 'react-native'; +import { ScrollView, Spinner, View, XStack, YStack, styled } from 'tamagui'; + +import { + useAttachmentContext, + useMappedImageAttachments, +} from '../../contexts'; +import AttachmentSheet from '../AttachmentSheet'; import { Button } from '../Button'; import { Icon, IconType } from '../Icon'; +import { Image } from '../Image'; import { ListItem } from '../ListItem'; import { useBoundHandler } from '../ListItem/listItemUtils'; import { Text } from '../TextV2'; @@ -135,6 +148,143 @@ export const TextInputWithButton: React.FC = ); }); +export const ImageInput = XStack.styleable<{ + buttonLabel?: string; + value?: string; + onChange?: (value?: string) => void; +}>(function ImageInput({ buttonLabel, value, onChange }, ref) { + const [sheetOpen, setSheetOpen] = useState(false); + const [assetUri, setAssetUri] = useState( + value ?? undefined + ); + const { attachAssets, canUpload } = useAttachmentContext(); + + useEffect(() => { + if (assetUri !== value) { + onChange?.(assetUri); + } + // only want this to fire when the value changes, not the handler + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [assetUri]); + + const handleImageSelected = useCallback( + (assets: ImagePickerAsset[]) => { + attachAssets([assets[0]]); + setAssetUri(assets[0].uri); + }, + [attachAssets] + ); + + const handleSheetToggled = useCallback(() => { + if (!canUpload) { + Alert.alert('Configure storage to upload images'); + } + setSheetOpen((open) => !open); + }, [canUpload]); + + const { attachment } = useMappedImageAttachments( + assetUri ? { attachment: assetUri } : {} + ); + + useEffect(() => { + if (attachment && attachment.uploadState?.status === 'success') { + setAssetUri?.(attachment.uploadState.remoteUri); + } + }, [attachment]); + + const handleImageRemoved = useCallback(() => { + setAssetUri(undefined); + }, []); + + return ( + <> + + + {buttonLabel} + + + + {assetUri ? ( + + ) : null} + {attachment?.uploadState?.status === 'uploading' ? ( + + + + ) : null} + + + + + ); +}); + +const ImageInputButtonFrame = styled(XStack, { + context: FieldContext, + borderRadius: '$l', + overflow: 'hidden', + justifyContent: 'center', + borderWidth: 1, + borderColor: '$border', + backgroundColor: '$background', + padding: '$xl', + flex: 1, + pressStyle: { backgroundColor: '$border' }, + variants: { + empty: {}, + accent: { + negative: { + backgroundColor: '$negativeBackground', + color: '$negativeActionText', + borderColor: '$negativeBorder', + }, + }, + }, +}); + +const ImageInputButtonText = styled(Text, { + size: '$label/xl', + trimmed: false, + color: '$secondaryText', + lineHeight: '$s', + '$group-press': { color: '$tertiaryText' }, +}); + +const ImageInputPreviewFrame = styled(View, { + borderRadius: '$m', + aspectRatio: 1, + overflow: 'hidden', + backgroundColor: '$border', + alignItems: 'center', + justifyContent: 'center', + pressStyle: { opacity: 0.5 }, +}); + +const ImageInputPreviewImage = styled(Image, { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', +}); + +const ImageInputPreviewLoadingFrame = styled(View, { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + backgroundColor: 'rgba(0,0,0,.25)', + alignItems: 'center', + justifyContent: 'center', +}); + interface TextInputWithIconAndButtonProps extends ComponentProps { icon: IconType; diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 40a69796b6..d6442dbfc0 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -107,7 +107,9 @@ export function PostScreenView({ const headerTitle = isChatChannel ? `Thread: ${channel?.title ?? null}` - : parentPost?.title ?? 'Post'; + : parentPost?.title && parentPost.title !== '' + ? parentPost.title + : 'Post'; const hasLoaded = !!(posts && channel && parentPost); useEffect(() => { diff --git a/packages/ui/src/components/ProfileScreenView.tsx b/packages/ui/src/components/ProfileScreenView.tsx index d4e27fffc1..27104ad2ff 100644 --- a/packages/ui/src/components/ProfileScreenView.tsx +++ b/packages/ui/src/components/ProfileScreenView.tsx @@ -12,13 +12,14 @@ import { TlonLogo } from './TlonLogo'; interface Props { currentUserId: string; hasHostedAuth: boolean; - onEditProfilePressed?: () => void; + onProfilePressed?: () => void; onAppInfoPressed?: () => void; onNotificationSettingsPressed: () => void; onBlockedUsersPressed: () => void; onManageAccountPressed: () => void; onLogoutPressed?: () => void; onSendBugReportPressed?: () => void; + onExperimentalFeaturesPressed?: () => void; dmLink?: string; } @@ -34,6 +35,7 @@ export function ProfileScreenView(props: Props) { }, { text: 'Log out', + style: 'destructive', onPress: props.onLogoutPressed, }, ]); @@ -64,9 +66,9 @@ export function ProfileScreenView(props: Props) { } - title="Edit profile" + title="Profile" subtitle={props.currentUserId} - onPress={props.onEditProfilePressed} + onPress={props.onProfilePressed} rightIcon={'ChevronRight'} /> {showDmLure && props.dmLink !== '' && ( @@ -121,6 +123,12 @@ export function ProfileScreenView(props: Props) { rightIcon={'ChevronRight'} onPress={props.onSendBugReportPressed} /> + void; connectionStatus: api.ConnectionStatus | null; onPressGroup: (group: db.Group) => void; + onPressEdit: () => void; } export function UserProfileScreenView(props: Props) { @@ -71,6 +72,13 @@ export function UserProfileScreenView(props: Props) { } + rightControls={ + props.userId === currentUserId ? ( + + Edit + + ) : null + } /> Date: Tue, 22 Oct 2024 15:01:49 -0500 Subject: [PATCH 170/259] new web: omnibus build fixes --- apps/tlon-mobile/src/App.main.tsx | 2 +- .../tlon-mobile/src/lib/signupContext.tsx | 8 +- .../screens/Onboarding/CheckVerifyScreen.tsx | 2 +- .../screens/Onboarding/ReserveShipScreen.tsx | 2 +- .../screens/Onboarding/SetNicknameScreen.tsx | 2 +- .../screens/Onboarding/SetTelemetryScreen.tsx | 2 +- .../Onboarding/SignUpPasswordScreen.tsx | 2 +- apps/tlon-web-new/package.json | 3 +- apps/tlon-web-new/src/global.d.ts | 4 + apps/tlon-web-new/src/main.tsx | 7 + apps/tlon-web-new/src/window.ts | 1 + packages/app/hooks/useConfigureUrbitClient.ts | 5 +- packages/app/hooks/useHandleLogout.ts | 10 +- packages/app/lib/resetDb.native.ts | 3 + packages/app/lib/resetDb.ts | 3 + packages/ui/src/components/ChatList.tsx | 18 +- pnpm-lock.yaml | 272 +++++++++--------- 17 files changed, 181 insertions(+), 165 deletions(-) rename packages/app/contexts/signup.tsx => apps/tlon-mobile/src/lib/signupContext.tsx (94%) create mode 100644 packages/app/lib/resetDb.native.ts create mode 100644 packages/app/lib/resetDb.ts diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 5dc76b7cde..78916e940e 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -16,7 +16,7 @@ import { ShipProvider, useShip } from '@tloncorp/app/contexts/ship'; import { SignupProvider, useSignupContext, -} from '@tloncorp/app/contexts/signup'; +} from './lib/signupContext'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; import { useMigrations } from '@tloncorp/app/lib/nativeDb'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; diff --git a/packages/app/contexts/signup.tsx b/apps/tlon-mobile/src/lib/signupContext.tsx similarity index 94% rename from packages/app/contexts/signup.tsx rename to apps/tlon-mobile/src/lib/signupContext.tsx index 19d236d76d..6edae7a723 100644 --- a/packages/app/contexts/signup.tsx +++ b/apps/tlon-mobile/src/lib/signupContext.tsx @@ -1,3 +1,5 @@ +// This signup context lives here in the mobile app because this path can only +// be reached by the mobile app and it's only used by the mobile app. import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; import * as store from '@tloncorp/shared/dist/store'; @@ -10,9 +12,9 @@ import { useState, } from 'react'; -import { useBootSequence } from '../hooks/useBootSequence'; -import { NodeBootPhase } from '../lib/bootHelpers'; -import { connectNotifyProvider } from '../lib/notificationsApi'; +import { useBootSequence } from '@tloncorp/app/hooks/useBootSequence'; +import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; +import { connectNotifyProvider } from '@tloncorp/app/lib/notificationsApi'; const logger = createDevLogger('signup', true); diff --git a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx index df511f6f0f..a76fbd2c28 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx @@ -1,5 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { trackError, trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { Field, diff --git a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx index 747b9daef8..b21eb645be 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx @@ -1,6 +1,6 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; import { ArvosDiscussing, diff --git a/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx index 8e789ce9ec..4fb7194c4d 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx @@ -1,5 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { requestNotificationToken } from '@tloncorp/app/lib/notifications'; import { trackError } from '@tloncorp/app/utils/posthog'; import { diff --git a/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx index 29a46b78c6..0ee08ce443 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SetTelemetryScreen.tsx @@ -1,5 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { ScreenHeader, SizableText, diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx index becdc19d12..0a10cfa997 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx @@ -1,7 +1,7 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { RECAPTCHA_SITE_KEY } from '@tloncorp/app/constants'; import { useSignupParams } from '@tloncorp/app/contexts/branch'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { setEulaAgreed } from '@tloncorp/app/utils/eula'; import { trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { createDevLogger } from '@tloncorp/shared'; diff --git a/apps/tlon-web-new/package.json b/apps/tlon-web-new/package.json index 72e166d653..2f1068f381 100644 --- a/apps/tlon-web-new/package.json +++ b/apps/tlon-web-new/package.json @@ -34,6 +34,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.190.0", "@aws-sdk/s3-request-presigner": "^3.190.0", + "@babel/runtime": "^7.25.9", "@emoji-mart/data": "^1.0.6", "@emoji-mart/react": "^1.0.1", "@radix-ui/react-accordion": "^1.1.2", @@ -135,9 +136,9 @@ "react-hook-form": "^7.30.0", "react-image-size": "^2.0.0", "react-intersection-observer": "^9.4.0", - "react-native-web": "0.19.12", "react-native-safe-area-context": "^4.9.0", "react-native-screens": "~3.29.0", + "react-native-web": "0.19.12", "react-oembed-container": "github:stefkampen/react-oembed-container", "react-qr-code": "^2.0.12", "react-select": "^5.3.2", diff --git a/apps/tlon-web-new/src/global.d.ts b/apps/tlon-web-new/src/global.d.ts index c98746af76..eb8f0ca6f2 100644 --- a/apps/tlon-web-new/src/global.d.ts +++ b/apps/tlon-web-new/src/global.d.ts @@ -4,6 +4,10 @@ type Stringified = string & { [P in keyof T]: { '_ value': T[P] }; }; +declare module '@babel/runtime/regenerator' { + const regeneratorRuntime: any; + export default regeneratorRuntime; +} declare module '@emoji-mart/react'; declare module 'emoji-mart'; declare module 'react-oembed-container'; diff --git a/apps/tlon-web-new/src/main.tsx b/apps/tlon-web-new/src/main.tsx index 56a1707cf9..798b503683 100644 --- a/apps/tlon-web-new/src/main.tsx +++ b/apps/tlon-web-new/src/main.tsx @@ -9,6 +9,11 @@ import { setupDb } from '@tloncorp/app/lib/webDb'; import { PostHogProvider } from 'posthog-js/react'; import React from 'react'; import { createRoot } from 'react-dom/client'; +// At some point recently, we started getting a "regeneratorRuntime is not defined" error +// when running the app in development mode. This is a workaround for that issue. +// This is a temporary fix until we can figure out why this is happening. +// This was most likely caused by a recent dependency change. +import regeneratorRuntime from '@babel/runtime/regenerator'; import _api from './api'; import App from './app'; @@ -17,6 +22,8 @@ import { analyticsClient, captureError } from './logic/analytics'; import queryClient from './queryClient'; import './styles/index.css'; +window.regeneratorRuntime = regeneratorRuntime; + setupDb().then(() => { const oldUpdateState = EditorView.prototype.updateState; diff --git a/apps/tlon-web-new/src/window.ts b/apps/tlon-web-new/src/window.ts index 05952c2228..4cce54e71d 100644 --- a/apps/tlon-web-new/src/window.ts +++ b/apps/tlon-web-new/src/window.ts @@ -11,6 +11,7 @@ declare global { toggleDevTools: () => void; unread: any; markRead: Rope; + regeneratorRuntime: any; recents: any; ReactNativeWebView?: { postMessage: (message: string) => void; diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 41797ec4c7..589e077958 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -6,7 +6,10 @@ import { useCallback } from 'react'; import { ENABLED_LOGGERS } from '../constants'; import { useShip } from '../contexts/ship'; import { getShipAccessCode } from '../lib/hostingApi'; -import { resetDb } from '../lib/nativeDb'; +// We need to import resetDb this way because we have both a resetDb.ts and a +// resetDb.native.ts file. We need to import the right one based on the +// platform. +import { resetDb } from '../lib/resetDb'; import { initializePolyfills, platformFetch } from '../platform/polyfills'; import { useHandleLogout } from './useHandleLogout'; diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index 267fd5fec4..b2d5eefedb 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -1,9 +1,12 @@ +// TODO: Seems like we need something totally different for web than this. +// Branch context and methods removed here because a) it's not used and +// b) it breaks the web build because it relies on react-native-branch, +// which isn't made for web. import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; import * as store from '@tloncorp/shared/dist/store'; import { useCallback } from 'react'; -import { useBranch } from '../contexts/branch'; import { clearShipInfo, useShip } from '../contexts/ship'; import { removeHostingAuthTracking, @@ -16,7 +19,6 @@ const logger = createDevLogger('logout', true); export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { const { clearShip } = useShip(); - const { clearLure, clearDeepLink } = useBranch(); const handleLogout = useCallback(async () => { api.queryClient.clear(); @@ -26,8 +28,6 @@ export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { removeHostingToken(); removeHostingUserId(); removeHostingAuthTracking(); - clearLure(); - clearDeepLink(); clearSplashDismissed(); if (!resetDb) { logger.trackError('could not reset db on logout'); @@ -35,7 +35,7 @@ export function useHandleLogout({ resetDb }: { resetDb?: () => void }) { } // delay DB reset to next tick to avoid race conditions setTimeout(() => resetDb()); - }, [clearDeepLink, clearLure, clearShip, resetDb]); + }, [clearShip, resetDb]); return handleLogout; } diff --git a/packages/app/lib/resetDb.native.ts b/packages/app/lib/resetDb.native.ts new file mode 100644 index 0000000000..b11118d1cd --- /dev/null +++ b/packages/app/lib/resetDb.native.ts @@ -0,0 +1,3 @@ +import { resetDb } from './nativeDb'; + +export { resetDb }; diff --git a/packages/app/lib/resetDb.ts b/packages/app/lib/resetDb.ts new file mode 100644 index 0000000000..9274745cd5 --- /dev/null +++ b/packages/app/lib/resetDb.ts @@ -0,0 +1,3 @@ +import { resetDb } from './webDb'; + +export { resetDb }; diff --git a/packages/ui/src/components/ChatList.tsx b/packages/ui/src/components/ChatList.tsx index afcc9b2d0c..98960341d4 100644 --- a/packages/ui/src/components/ChatList.tsx +++ b/packages/ui/src/components/ChatList.tsx @@ -1,4 +1,4 @@ -import { ContentStyle, FlashList, ListRenderItem } from '@shopify/flash-list'; +import { FlashList, ListRenderItem } from '@shopify/flash-list'; import * as db from '@tloncorp/shared/dist/db'; import * as logic from '@tloncorp/shared/dist/logic'; import * as store from '@tloncorp/shared/dist/store'; @@ -17,7 +17,7 @@ import Animated, { useAnimatedStyle, useSharedValue, } from 'react-native-reanimated'; -import { Text, View, YStack, getTokenValue, useStyle } from 'tamagui'; +import { Text, View, YStack, getTokenValue } from 'tamagui'; import { interactionWithTiming } from '../utils/animation'; import { TextInputWithIconAndButton } from './Form'; @@ -78,13 +78,13 @@ export const ChatList = React.memo(function ChatListComponent({ [displayData] ); - const contentContainerStyle = useStyle( - { - padding: '$l', - paddingBottom: 100, // bottom nav height + some cushion - }, - { resolveValues: 'value' } - ) as ContentStyle; + // removed the use of useStyle here because it was causing FlashList to + // peg the CPU and freeze the app on web + // see: https://github.com/Shopify/flash-list/pull/852 + const contentContainerStyle = { + padding: getTokenValue('$l', 'size'), + paddingBottom: 100, // bottom nav height + some cushion + }; const renderItem: ListRenderItem = useCallback( ({ item }) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 792e212993..399bf5d396 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,7 +152,7 @@ importers: version: 6.9.18(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@shopify/flash-list': specifier: 1.6.3 - version: 1.6.3(@babel/runtime@7.25.6)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 1.6.3(@babel/runtime@7.25.9)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@tanstack/react-query': specifier: ~5.32.1 version: 5.32.1(react@18.2.0) @@ -977,6 +977,9 @@ importers: '@aws-sdk/s3-request-presigner': specifier: ^3.190.0 version: 3.190.0 + '@babel/runtime': + specifier: ^7.25.9 + version: 7.25.9 '@emoji-mart/data': specifier: ^1.0.6 version: 1.1.2 @@ -2346,22 +2349,22 @@ packages: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.23.4': - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.24.8': resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.20': - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} '@babel/helper-validator-identifier@7.24.7': resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.23.5': resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} @@ -3020,14 +3023,14 @@ packages: '@babel/regjsgen@0.8.0': resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - '@babel/runtime@7.23.8': - resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==} - engines: {node: '>=6.9.0'} - '@babel/runtime@7.25.6': resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.25.9': + resolution: {integrity: sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==} + engines: {node: '>=6.9.0'} + '@babel/template@7.25.0': resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} engines: {node: '>=6.9.0'} @@ -3048,18 +3051,14 @@ packages: resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} engines: {node: '>=6.9.0'} - '@babel/types@7.23.9': - resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.25.2': - resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==} - engines: {node: '>=6.9.0'} - '@babel/types@7.25.6': resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} engines: {node: '>=6.9.0'} + '@babel/types@7.25.9': + resolution: {integrity: sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -14420,7 +14419,7 @@ snapshots: '@babel/parser': 7.23.6 '@babel/template': 7.25.0 '@babel/traverse': 7.25.3 - '@babel/types': 7.23.9 + '@babel/types': 7.25.9 convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -14440,7 +14439,7 @@ snapshots: '@babel/parser': 7.25.3 '@babel/template': 7.25.0 '@babel/traverse': 7.25.3 - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 convert-source-map: 2.0.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -14451,13 +14450,13 @@ snapshots: '@babel/generator@7.17.7': dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.25.6 jsesc: 2.5.2 source-map: 0.5.7 '@babel/generator@7.25.0': dependencies: - '@babel/types': 7.25.2 + '@babel/types': 7.25.9 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 @@ -14475,7 +14474,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.24.7': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': dependencies: @@ -14586,11 +14585,11 @@ snapshots: '@babel/helper-function-name@7.23.0': dependencies: '@babel/template': 7.25.0 - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@babel/helper-member-expression-to-functions@7.23.0': dependencies: @@ -14598,7 +14597,7 @@ snapshots: '@babel/helper-module-imports@7.22.15': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 '@babel/helper-module-imports@7.24.7': dependencies: @@ -14614,7 +14613,7 @@ snapshots: '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 '@babel/helper-module-transforms@7.25.2(@babel/core@7.23.7)': dependencies: @@ -14674,7 +14673,7 @@ snapshots: '@babel/helper-simple-access@7.22.5': dependencies: - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 '@babel/helper-simple-access@7.24.7': dependencies: @@ -14689,16 +14688,16 @@ snapshots: '@babel/helper-split-export-declaration@7.22.6': dependencies: - '@babel/types': 7.25.2 - - '@babel/helper-string-parser@7.23.4': {} + '@babel/types': 7.25.6 '@babel/helper-string-parser@7.24.8': {} - '@babel/helper-validator-identifier@7.22.20': {} + '@babel/helper-string-parser@7.25.9': {} '@babel/helper-validator-identifier@7.24.7': {} + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-option@7.23.5': {} '@babel/helper-validator-option@7.24.8': {} @@ -14713,7 +14712,7 @@ snapshots: dependencies: '@babel/template': 7.25.0 '@babel/traverse': 7.25.3 - '@babel/types': 7.25.2 + '@babel/types': 7.25.9 transitivePeerDependencies: - supports-color @@ -14737,11 +14736,11 @@ snapshots: '@babel/parser@7.23.6': dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.25.6 '@babel/parser@7.25.3': dependencies: - '@babel/types': 7.25.2 + '@babel/types': 7.25.9 '@babel/parser@7.25.6': dependencies: @@ -15465,7 +15464,7 @@ snapshots: '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-module-transforms': 7.25.2(@babel/core@7.23.7) '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 transitivePeerDependencies: - supports-color @@ -15475,7 +15474,7 @@ snapshots: '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) '@babel/helper-plugin-utils': 7.24.8 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 transitivePeerDependencies: - supports-color @@ -15698,7 +15697,7 @@ snapshots: '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.23.7) - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 transitivePeerDependencies: - supports-color @@ -15709,7 +15708,7 @@ snapshots: '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 transitivePeerDependencies: - supports-color @@ -16106,11 +16105,11 @@ snapshots: '@babel/regjsgen@0.8.0': {} - '@babel/runtime@7.23.8': + '@babel/runtime@7.25.6': dependencies: regenerator-runtime: 0.14.1 - '@babel/runtime@7.25.6': + '@babel/runtime@7.25.9': dependencies: regenerator-runtime: 0.14.1 @@ -16118,7 +16117,7 @@ snapshots: dependencies: '@babel/code-frame': 7.24.7 '@babel/parser': 7.25.3 - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@babel/traverse@7.23.2': dependencies: @@ -16129,7 +16128,7 @@ snapshots: '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.6 - '@babel/types': 7.23.9 + '@babel/types': 7.25.6 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -16161,18 +16160,6 @@ snapshots: '@babel/types@7.17.0': dependencies: - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - - '@babel/types@7.23.9': - dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - - '@babel/types@7.25.2': - dependencies: - '@babel/helper-string-parser': 7.24.8 '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 @@ -16182,6 +16169,11 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@babel/types@7.25.9': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@bcoe/v8-coverage@0.2.3': {} '@dev-plugins/async-storage@0.0.3(@react-native-async-storage/async-storage@1.21.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0)))(expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13))': @@ -16222,7 +16214,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-module-imports': 7.24.7 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.25.2) - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@emotion/hash': 0.9.0 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.0 @@ -16257,7 +16249,7 @@ snapshots: '@emotion/react@11.10.0(@babel/core@7.25.2)(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@emotion/babel-plugin': 11.10.0(@babel/core@7.25.2) '@emotion/cache': 11.10.1 '@emotion/serialize': 1.1.0 @@ -16818,7 +16810,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/generator': 7.25.0 '@babel/parser': 7.25.3 - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@expo/config': 8.5.4 '@expo/env': 0.2.1 '@expo/json-file': 8.3.0 @@ -17409,15 +17401,15 @@ snapshots: '@radix-ui/primitive@1.0.0': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive@1.0.1': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-accordion@1.1.2(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -17435,7 +17427,7 @@ snapshots: '@radix-ui/react-arrow@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -17452,7 +17444,7 @@ snapshots: '@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17469,7 +17461,7 @@ snapshots: '@radix-ui/react-collection@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-context': 1.0.0(react@18.2.0) '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -17479,7 +17471,7 @@ snapshots: '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -17492,31 +17484,31 @@ snapshots: '@radix-ui/react-compose-refs@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 react: 18.2.0 '@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 '@radix-ui/react-context@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 '@radix-ui/react-context@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 '@radix-ui/react-dialog@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17539,14 +17531,14 @@ snapshots: '@radix-ui/react-direction@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 '@radix-ui/react-dismissable-layer@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -17557,7 +17549,7 @@ snapshots: '@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -17571,7 +17563,7 @@ snapshots: '@radix-ui/react-dropdown-menu@2.0.5(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17587,14 +17579,14 @@ snapshots: '@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 '@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17606,13 +17598,13 @@ snapshots: '@radix-ui/react-id@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) react: 18.2.0 '@radix-ui/react-id@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 optionalDependencies: @@ -17620,7 +17612,7 @@ snapshots: '@radix-ui/react-menu@2.0.5(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17647,7 +17639,7 @@ snapshots: '@radix-ui/react-popover@1.0.6(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17671,7 +17663,7 @@ snapshots: '@radix-ui/react-popper@1.0.0(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@floating-ui/react-dom': 0.7.2(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-arrow': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) @@ -17688,7 +17680,7 @@ snapshots: '@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@floating-ui/react-dom': 2.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17707,14 +17699,14 @@ snapshots: '@radix-ui/react-portal@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) '@radix-ui/react-portal@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -17724,7 +17716,7 @@ snapshots: '@radix-ui/react-presence@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) react: 18.2.0 @@ -17732,7 +17724,7 @@ snapshots: '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 @@ -17743,14 +17735,14 @@ snapshots: '@radix-ui/react-primitive@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-slot': 1.0.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-slot': 1.0.2(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -17760,7 +17752,7 @@ snapshots: '@radix-ui/react-radio-group@1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17779,7 +17771,7 @@ snapshots: '@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17797,13 +17789,13 @@ snapshots: '@radix-ui/react-slot@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) react: 18.2.0 '@radix-ui/react-slot@1.0.2(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 optionalDependencies: @@ -17811,7 +17803,7 @@ snapshots: '@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17828,7 +17820,7 @@ snapshots: '@radix-ui/react-toast@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-collection': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) @@ -17846,7 +17838,7 @@ snapshots: '@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-context': 1.0.1(@types/react@18.2.55)(react@18.2.0) '@radix-ui/react-direction': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17862,7 +17854,7 @@ snapshots: '@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.55)(react@18.2.0) @@ -17874,7 +17866,7 @@ snapshots: '@radix-ui/react-tooltip@1.0.0(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-context': 1.0.0(react@18.2.0) @@ -17894,7 +17886,7 @@ snapshots: '@radix-ui/react-use-callback-ref@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.55)(react@18.2.0)': @@ -17906,13 +17898,13 @@ snapshots: '@radix-ui/react-use-controllable-state@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 optionalDependencies: @@ -17920,13 +17912,13 @@ snapshots: '@radix-ui/react-use-escape-keydown@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 optionalDependencies: @@ -17934,26 +17926,26 @@ snapshots: '@radix-ui/react-use-layout-effect@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 react: 18.2.0 '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 '@radix-ui/react-use-previous@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 optionalDependencies: '@types/react': 18.2.55 '@radix-ui/react-use-rect@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@radix-ui/rect': 1.0.0 react: 18.2.0 @@ -17967,13 +17959,13 @@ snapshots: '@radix-ui/react-use-size@1.0.0(react@18.2.0)': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) react: 18.2.0 '@radix-ui/react-use-size@1.0.1(@types/react@18.2.55)(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.55)(react@18.2.0) react: 18.2.0 optionalDependencies: @@ -17981,14 +17973,14 @@ snapshots: '@radix-ui/react-visually-hidden@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) '@radix-ui/rect@1.0.0': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@radix-ui/rect@1.0.1': dependencies: @@ -18868,9 +18860,9 @@ snapshots: component-type: 1.2.2 join-component: 1.1.0 - '@shopify/flash-list@1.6.3(@babel/runtime@7.25.6)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + '@shopify/flash-list@1.6.3(@babel/runtime@7.25.9)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 react: 18.2.0 react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) recyclerlistview: 4.2.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -18965,7 +18957,7 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.25.2 + '@babel/types': 7.25.9 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.4.5))': @@ -19886,9 +19878,9 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/parser': 7.25.6 '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.25.2) - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@babel/traverse': 7.25.6 - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 '@tamagui/build': 1.112.12(@swc/helpers@0.5.13) '@tamagui/cli-color': 1.112.12 '@tamagui/config-default': 1.112.12(react@18.2.0) @@ -20215,7 +20207,7 @@ snapshots: '@testing-library/dom@9.3.1': dependencies: '@babel/code-frame': 7.24.7 - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@types/aria-query': 5.0.1 aria-query: 5.1.3 chalk: 4.1.2 @@ -20226,7 +20218,7 @@ snapshots: '@testing-library/jest-dom@5.17.0': dependencies: '@adobe/css-tools': 4.0.1 - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@types/testing-library__jest-dom': 5.14.5(patch_hash=n4thxxgg24py6nu2jafoa3v4pa) aria-query: 5.3.0 chalk: 3.0.0 @@ -20248,7 +20240,7 @@ snapshots: '@testing-library/react@14.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@testing-library/dom': 9.3.1 '@types/react-dom': 18.2.18 react: 18.2.0 @@ -20461,7 +20453,7 @@ snapshots: '@tloncorp/mock-http-api@1.2.0': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@microsoft/fetch-event-source': 2.0.1 browser-or-node: 1.3.0 core-js: 3.24.1 @@ -20495,16 +20487,16 @@ snapshots: '@types/babel__generator@7.6.4': dependencies: - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@types/babel__template@7.4.1': dependencies: '@babel/parser': 7.25.3 - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@types/babel__traverse@7.20.1': dependencies: - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 '@types/better-sqlite3@7.6.9': dependencies: @@ -20921,7 +20913,7 @@ snapshots: '@urbit/api@2.2.0': dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 big-integer: 1.6.52 core-js: 3.24.1 immer: 9.0.21 @@ -20933,7 +20925,7 @@ snapshots: '@urbit/http-api@3.2.0-dev': dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@types/node': 20.14.10 browser-or-node: 1.3.0 core-js: 3.24.1 @@ -21414,7 +21406,7 @@ snapshots: '@babel/core': 7.25.2 '@babel/parser': 7.25.6 '@babel/traverse': 7.25.6 - '@babel/types': 7.25.6 + '@babel/types': 7.25.9 transitivePeerDependencies: - supports-color @@ -22346,7 +22338,7 @@ snapshots: date-fns@2.30.0: dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 dayjs@1.11.10: {} @@ -22533,7 +22525,7 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 csstype: 3.1.0 dom-serializer@2.0.0: @@ -23485,7 +23477,7 @@ snapshots: expo@50.0.6(@babel/core@7.25.2)(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 '@expo/cli': 0.17.5(@react-native/babel-preset@0.73.21(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2)))(encoding@0.1.13)(expo-modules-autolinking@1.10.3) '@expo/config': 8.5.4 '@expo/config-plugins': 7.8.4 @@ -24121,7 +24113,7 @@ snapshots: history@5.3.0: dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 hoist-non-react-statics@3.3.2: dependencies: @@ -25646,7 +25638,7 @@ snapshots: metro-source-map@0.80.5: dependencies: '@babel/traverse': 7.25.3 - '@babel/types': 7.25.2 + '@babel/types': 7.25.6 invariant: 2.2.4 metro-symbolicate: 0.80.5 nullthrows: 1.1.1 @@ -26734,7 +26726,7 @@ snapshots: react-beautiful-dnd@13.1.1(react-dom@18.2.0(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 css-box-model: 1.2.1 memoize-one: 5.2.1 raf-schd: 4.0.3 @@ -26865,7 +26857,7 @@ snapshots: react-error-boundary@3.1.4(react@18.2.0): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 react: 18.2.0 react-fast-compare@3.2.0: {} @@ -27127,7 +27119,7 @@ snapshots: react-native-windows@0.73.11(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@jest/create-cache-key-function': 29.7.0 '@react-native-community/cli': 12.3.6(encoding@0.1.13) '@react-native-community/cli-platform-android': 12.3.6(encoding@0.1.13) @@ -27293,7 +27285,7 @@ snapshots: react-redux@7.2.8(react-dom@18.2.0(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@types/react-redux': 7.1.24 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 @@ -27339,7 +27331,7 @@ snapshots: react-select@5.4.0(@babel/core@7.25.2)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 '@emotion/cache': 11.10.1 '@emotion/react': 11.10.0(@babel/core@7.25.2)(@types/react@18.2.55)(react@18.2.0) '@types/react-transition-group': 4.4.5 @@ -27381,7 +27373,7 @@ snapshots: react-transition-group@4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -27471,7 +27463,7 @@ snapshots: redux@4.2.0: dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 reflect.getprototypeof@1.0.4: dependencies: @@ -28938,7 +28930,7 @@ snapshots: video-react@0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.9 classnames: 2.5.1 lodash.throttle: 4.1.1 prop-types: 15.8.1 @@ -29340,7 +29332,7 @@ snapshots: '@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0) '@babel/core': 7.25.2 '@babel/preset-env': 7.23.7(@babel/core@7.25.2) - '@babel/runtime': 7.25.6 + '@babel/runtime': 7.25.9 '@rollup/plugin-babel': 5.3.1(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@2.79.1) '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1) '@rollup/plugin-replace': 2.4.2(rollup@2.79.1) From 2e92d277063310f8c6e181262b83a47de61d1a29 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 16:23:05 -0400 Subject: [PATCH 171/259] finishing touches --- .../screens/Onboarding/CheckVerifyScreen.tsx | 2 +- .../screens/Onboarding/SetNicknameScreen.tsx | 11 ++++------ packages/app/contexts/signup.tsx | 13 ----------- packages/shared/src/db/keyValue.ts | 22 +------------------ 4 files changed, 6 insertions(+), 42 deletions(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx index 5c6cea0f0c..01dfb1482d 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx @@ -51,7 +51,7 @@ export const CheckVerifyScreen = ({ actionName: 'Verification Submitted', }); - signupContext.setHostingUser(user); + signupContext.setOnboardingValues({ hostingUser: user }); signupContext.kickOffBootSequence(); navigation.navigate('SetNickname', { user }); } catch (err) { diff --git a/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx index d608f65ba3..d11e37a560 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SetNicknameScreen.tsx @@ -53,13 +53,10 @@ export const SetNicknameScreen = ({ const signupContext = useSignupContext(); const onSubmit = handleSubmit(({ nickname, notificationToken }) => { - if (nickname) { - signupContext.setOnboardingValues({ nickname }); - } - - if (notificationToken) { - signupContext.setOnboardingValues({ notificationToken }); - } + signupContext.setOnboardingValues({ + nickname, + notificationToken, + }); navigation.navigate('SetTelemetry', { user, diff --git a/packages/app/contexts/signup.tsx b/packages/app/contexts/signup.tsx index 3f00ea5a2c..33a671a909 100644 --- a/packages/app/contexts/signup.tsx +++ b/packages/app/contexts/signup.tsx @@ -17,7 +17,6 @@ const defaultValues: SignupValues = { }; interface SignupContext extends SignupParams { - setHostingUser: (hostingUser: { id: string }) => void; setOnboardingValues: (newValues: Partial) => void; kickOffBootSequence: () => void; handlePostSignup: () => void; @@ -25,7 +24,6 @@ interface SignupContext extends SignupParams { } const defaultMethods = { - setHostingUser: () => {}, setOnboardingValues: () => {}, handlePostSignup: () => {}, kickOffBootSequence: () => {}, @@ -57,16 +55,6 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { [setValues] ); - const setHostingUser = useCallback( - (hostingUser: { id: string }) => { - setValues((current) => ({ - ...current, - hostingUser, - })); - }, - [setValues] - ); - const clear = useCallback(() => { logger.log('clearing signup context'); resetValues(); @@ -111,7 +99,6 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { value={{ ...values, bootPhase, - setHostingUser, setOnboardingValues, handlePostSignup, kickOffBootSequence, diff --git a/packages/shared/src/db/keyValue.ts b/packages/shared/src/db/keyValue.ts index 2b931a0ef7..2ad870d450 100644 --- a/packages/shared/src/db/keyValue.ts +++ b/packages/shared/src/db/keyValue.ts @@ -1,10 +1,5 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; -import { - UseMutationResult, - UseQueryResult, - useMutation, - useQuery, -} from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; import { StorageConfiguration, @@ -265,12 +260,6 @@ const createStorageItem = (config: StorageItem) => { return { getValue, setValue, resetValue, useValue, useStorageItem }; }; -export const currentOnboardingRoute = createStorageItem({ - key: 'currentOnboardingRoute', - defaultValue: null, -}); -export const useCurrentOnboardingRoute = currentOnboardingRoute.useStorageItem; - export const signupData = createStorageItem({ key: 'signupData', defaultValue: { @@ -279,12 +268,3 @@ export const signupData = createStorageItem({ bootPhase: NodeBootPhase.IDLE, }, }); - -// in component -// const didShowBenefitsSheet = useDidShowBenefitsSheet(); -// OR -// const { value, setValue } = useDidShowBenefitsSheet(); - -// import {didShowBenefitsSheet } from '../store/kv'; - -// didshowBenefitsSheet.useValue() From f026cbac8eac6dc62a612aa47d19080a98d30f1c Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 17:02:23 -0400 Subject: [PATCH 172/259] disable logger --- apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx | 1 + packages/shared/src/db/keyValue.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx index 01dfb1482d..31be0f9d11 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/CheckVerifyScreen.tsx @@ -192,6 +192,7 @@ function CodeInput({ paddingHorizontal="$xl" paddingVertical="$xl" width="$4xl" + textContentType={!isEmail ? 'oneTimeCode' : undefined} /> ))} diff --git a/packages/shared/src/db/keyValue.ts b/packages/shared/src/db/keyValue.ts index 2ad870d450..58778da123 100644 --- a/packages/shared/src/db/keyValue.ts +++ b/packages/shared/src/db/keyValue.ts @@ -11,7 +11,7 @@ import { createDevLogger } from '../debug'; import * as ub from '../urbit'; import { NodeBootPhase, SignupParams } from './domainTypes'; -const logger = createDevLogger('keyValueStore', true); +const logger = createDevLogger('keyValueStore', false); export const ACTIVITY_SEEN_MARKER_QUERY_KEY = [ 'activity', From 5cf3fd6cd3c60c63456f5466fbfd42ddd647fac2 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 17:06:24 -0400 Subject: [PATCH 173/259] cleanup --- .../Onboarding/RequestPhoneVerifyScreen.tsx | 4 ---- packages/app/hooks/useBootSequence.ts | 14 +++----------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/RequestPhoneVerifyScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/RequestPhoneVerifyScreen.tsx index d04a34284b..2886f7f15e 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/RequestPhoneVerifyScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/RequestPhoneVerifyScreen.tsx @@ -55,10 +55,6 @@ export const RequestPhoneVerifyScreen = ({ trackOnboardingAction({ actionName: 'Phone Verification Requested', }); - console.log('bl: heading to check verify with user', { - ...user, - phoneNumber, - }); navigation.navigate('CheckVerify', { user: { ...user, diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index 41b7699d8d..5cebce5b5f 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -28,9 +28,9 @@ interface BootSequenceReport { runBootPhase — executes a single boot step, returns the next step in the sequence runBootSequence — repeatedly executes runBootPhase until the sequence is complete - The hook remains idle until passed a hosted user. Gives up after HANDLE_INVITES_TIMEOUT seconds if - we're stuck processing invites, but the node is otherwise ready. Exposes the current boot phase to - the caller. + The hook remains idle until explicitly kicked off by the caller. Gives up after HANDLE_INVITES_TIMEOUT + seconds if we're stuck processing invites, but the node is otherwise ready. Exposes the current boot + phase to the caller. */ export function useBootSequence({ hostingUser, @@ -51,14 +51,6 @@ export function useBootSequence({ const lastRunErrored = useRef(false); const sequenceStartTimeRef = useRef(0); - // detect when we're ready to start the sequence, kick things off - // by advancing past IDLE - // useEffect(() => { - // if (bootPhase === NodeBootPhase.IDLE && hostingUser?.id) { - // setBootPhase(NodeBootPhase.RESERVING); - // } - // }, [bootPhase, hostingUser]); - const kickOffBootSequence = useCallback(() => { setBootPhase(NodeBootPhase.RESERVING); }, [setBootPhase]); From 9f4ab3e4576c6d626a885fb7c080ad6f2b23939e Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 17:14:17 -0400 Subject: [PATCH 174/259] fix import --- apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts index 8d23f55418..4582a1944b 100644 --- a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts +++ b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts @@ -1,9 +1,9 @@ import { NavigationProp, useNavigation } from '@react-navigation/native'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; +import { useShip } from '@tloncorp/app/contexts/ship'; import { useSignupContext } from '@tloncorp/app/contexts/signup'; import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; import { SignupParams, signupData } from '@tloncorp/shared/dist/db'; -import { useShip } from 'packages/app/contexts/ship'; import { useCallback, useEffect } from 'react'; import { useOnboardingContext } from '../lib/OnboardingContext'; From 2448bd4d25af38e2f8694a866287dbc58b6786ad Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 22 Oct 2024 17:56:29 -0400 Subject: [PATCH 175/259] make kickoff boot sequence idempotent --- packages/app/hooks/useBootSequence.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index 5cebce5b5f..f716f4c803 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -52,8 +52,10 @@ export function useBootSequence({ const sequenceStartTimeRef = useRef(0); const kickOffBootSequence = useCallback(() => { - setBootPhase(NodeBootPhase.RESERVING); - }, [setBootPhase]); + if (bootPhase === NodeBootPhase.IDLE) { + setBootPhase(NodeBootPhase.RESERVING); + } + }, [bootPhase]); const runBootPhase = useCallback(async (): Promise => { if (!hostingUser) { From d7e49d5ec41bee57145193ac3c67f369280b0f75 Mon Sep 17 00:00:00 2001 From: David Lee Date: Tue, 22 Oct 2024 15:02:12 -0700 Subject: [PATCH 176/259] Coerce custom channel type to chat earlier in flow --- packages/shared/src/store/useCreateChannel.ts | 2 +- .../ui/src/components/ManageChannels/CreateChannelSheet.tsx | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/store/useCreateChannel.ts b/packages/shared/src/store/useCreateChannel.ts index 5300bc9403..19517dbeaf 100644 --- a/packages/shared/src/store/useCreateChannel.ts +++ b/packages/shared/src/store/useCreateChannel.ts @@ -50,7 +50,7 @@ export function useCreateChannel({ channelId: id, title, description, - channelType: channelType === 'custom' ? 'chat' : channelType, + channelType, contentConfiguration: contentConfiguration ?? channelContentConfigurationForChannelType(channelType), diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index a30d595b8d..8ee015b8b5 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -81,6 +81,8 @@ export function CreateChannelSheet({ let contentConfiguration: ChannelContentConfiguration | undefined; if (data.channelType === 'custom') { contentConfiguration = customChannelConfigRef.current?.getFormValue(); + // HACK: We don't have a custom channel type yet, so call it a chat + data.channelType = 'chat'; } createChannel({ title: data.title, From b04953b54d5a8cf94e744a22fc938a6ff5f4d549 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 22 Oct 2024 17:28:34 -0500 Subject: [PATCH 177/259] debug: rename helper for clarity --- packages/app/features/settings/AppInfoScreen.tsx | 4 ++-- packages/app/lib/debug.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index f939cd1566..86da2c1940 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -24,7 +24,7 @@ import { getEmailClients, openComposer } from 'react-native-email-link'; import { ScrollView } from 'react-native-gesture-handler'; import { NOTIFY_PROVIDER, NOTIFY_SERVICE } from '../../constants'; -import { toggleDebug } from '../../lib/debug'; +import { setDebug } from '../../lib/debug'; import { getEasUpdateDisplay } from '../../lib/platformHelpers'; import { RootStackParamList } from '../../navigation/types'; @@ -72,7 +72,7 @@ export function AppInfoScreen(props: Props) { }, [props.navigation]); const toggleDebugFlag = useCallback((enabled: boolean) => { - toggleDebug(enabled); + setDebug(enabled); if (!enabled) { return; } diff --git a/packages/app/lib/debug.ts b/packages/app/lib/debug.ts index e2bade1beb..37b7a15fa4 100644 --- a/packages/app/lib/debug.ts +++ b/packages/app/lib/debug.ts @@ -12,7 +12,7 @@ storage useDebugStore.getState().toggle(enabled); }); -export const toggleDebug = async (enabled: boolean) => { +export const setDebug = async (enabled: boolean) => { console.log(`Debug mode ${enabled ? 'enabled' : 'disabled'}`); useDebugStore.getState().toggle(enabled); From c50e364578911d4b13a573fd326b3998891926a4 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 23 Oct 2024 08:01:37 -0500 Subject: [PATCH 178/259] fix imports in other onboarding screens --- apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts | 2 +- apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx | 2 +- apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts index 4582a1944b..44904dd682 100644 --- a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts +++ b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts @@ -1,7 +1,7 @@ import { NavigationProp, useNavigation } from '@react-navigation/native'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; import { useShip } from '@tloncorp/app/contexts/ship'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '../lib/signupContext'; import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; import { SignupParams, signupData } from '@tloncorp/shared/dist/db'; import { useCallback, useEffect } from 'react'; diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx index 821379aa65..6f6116599a 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpEmailScreen.tsx @@ -7,7 +7,7 @@ import { useLureMetadata, useSignupParams, } from '@tloncorp/app/contexts/branch'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { identifyTlonEmployee, trackError, diff --git a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx index c09a776b34..22e503e22c 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx @@ -5,7 +5,7 @@ import { EMAIL_REGEX, } from '@tloncorp/app/constants'; import { useShip } from '@tloncorp/app/contexts/ship'; -import { useSignupContext } from '@tloncorp/app/contexts/signup'; +import { useSignupContext } from '.././../lib/signupContext'; import { getShipAccessCode, getShipsWithStatus, From 6f5cbc32c81a897646e0a207b35e049633db95f8 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 23 Oct 2024 09:39:07 -0500 Subject: [PATCH 179/259] spike: bare text input for chat input --- packages/ui/src/components/BareChatInput.tsx | 550 ++++++++++++++++++ .../src/components/draftInputs/ChatInput.tsx | 5 +- 2 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 packages/ui/src/components/BareChatInput.tsx diff --git a/packages/ui/src/components/BareChatInput.tsx b/packages/ui/src/components/BareChatInput.tsx new file mode 100644 index 0000000000..1f28cd9e5f --- /dev/null +++ b/packages/ui/src/components/BareChatInput.tsx @@ -0,0 +1,550 @@ +import { extractContentTypesFromPost } from '@tloncorp/shared'; +import { contentReferenceToCite } from '@tloncorp/shared/dist/api'; +import * as db from '@tloncorp/shared/dist/db'; +import { + Block, + Story, + citeToPath, + pathToCite, +} from '@tloncorp/shared/dist/urbit'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { Keyboard, TextInput } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { getFontSize } from 'tamagui'; +import { Text, View, YStack, getToken, useWindowDimensions } from 'tamagui'; + +import { + Attachment, + UploadedImageAttachment, + useAttachmentContext, +} from '../contexts'; +import { DEFAULT_MESSAGE_INPUT_HEIGHT } from './MessageInput'; +import { AttachmentPreviewList } from './MessageInput/AttachmentPreviewList'; +import { + MessageInputContainer, + MessageInputProps, +} from './MessageInput/MessageInputBase'; + +interface Mention { + id: string; + display: string; + start: number; + end: number; +} + +export default function BareChatInput({ + shouldBlur, + setShouldBlur, + send, + channelId, + groupMembers, + storeDraft, + clearDraft, + getDraft, + editingPost, + setEditingPost, + editPost, + showAttachmentButton, + paddingHorizontal, + initialHeight = DEFAULT_MESSAGE_INPUT_HEIGHT, + backgroundColor, + placeholder = 'Message', + image, + showInlineAttachments, + channelType, + onSend, + goBack, + shouldAutoFocus, +}: MessageInputProps) { + const { bottom, top } = useSafeAreaInsets(); + const { height } = useWindowDimensions(); + const headerHeight = 48; + const maxInputHeightBasic = useMemo( + () => height - headerHeight - bottom - top, + [height, bottom, top, headerHeight] + ); + const { + attachments, + addAttachment, + clearAttachments, + resetAttachments, + waitForAttachmentUploads, + } = useAttachmentContext(); + const [text, setText] = useState(''); + const [mentions, setMentions] = useState([]); + const [isSending, setIsSending] = useState(false); + const [sendError, setSendError] = useState(false); + const [hasSetInitialContent, setHasSetInitialContent] = useState(false); + const [editorIsEmpty, setEditorIsEmpty] = useState(attachments.length === 0); + const [showMentionPopup, setShowMentionPopup] = useState(false); + const [hasAutoFocused, setHasAutoFocused] = useState(false); + const [mentionStartIndex, setMentionStartIndex] = useState( + null + ); + const [mentionSearchText, setMentionSearchText] = useState(''); + const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); + const inputRef = useRef(null); + + const handleTextChange = (newText: string) => { + const oldText = text; + setText(newText); + + // Check if we're deleting a trigger symbol + if (newText.length < oldText.length && showMentionPopup) { + const deletedChar = oldText[newText.length]; + if (deletedChar === '@' || deletedChar === '~') { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + return; + } + } + + // Check for @ symbol + const lastAtSymbol = newText.lastIndexOf('@'); + if (lastAtSymbol >= 0 && lastAtSymbol === newText.length - 1) { + setShowMentionPopup(true); + setMentionStartIndex(lastAtSymbol); + setMentionSearchText(''); + } else if (showMentionPopup && mentionStartIndex !== null) { + // Update mention search text + const searchText = newText.slice(mentionStartIndex + 1); + if (!searchText.includes(' ')) { + setMentionSearchText(searchText); + } else { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + } + } + + // Check for ~ symbol + const lastSig = newText.lastIndexOf('~'); + if (lastSig >= 0 && lastSig === newText.length - 1) { + setShowMentionPopup(true); + setMentionStartIndex(lastSig); + setMentionSearchText(''); + } else if (showMentionPopup && mentionStartIndex !== null) { + // Update mention search text + const searchText = newText.slice(mentionStartIndex + 1); + if (!searchText.includes(' ')) { + setMentionSearchText(searchText); + } else { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + } + } + + // Update mention positions when text changes + if (mentions.length > 0) { + const updatedMentions = mentions.filter( + (mention) => + mention.start <= newText.length && + newText.slice(mention.start, mention.end) === mention.display + ); + if (updatedMentions.length !== mentions.length) { + setMentions(updatedMentions); + } + } + }; + + const handleSelectMention = useCallback( + (contact: db.Contact) => { + if (mentionStartIndex === null) return; + + const mentionDisplay = `${contact.id}`; + const beforeMention = text.slice(0, mentionStartIndex); + const afterMention = text.slice( + mentionStartIndex + (mentionSearchText?.length || 0) + 1 + ); + + const newText = beforeMention + mentionDisplay + ' ' + afterMention; + const newMention: Mention = { + id: contact.id, + display: mentionDisplay, + start: mentionStartIndex, + end: mentionStartIndex + mentionDisplay.length, + }; + + setText(newText); + setMentions((prev) => [...prev, newMention]); + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + + // Force focus back to input after mention selection + inputRef.current?.focus(); + }, + [mentionStartIndex, text, mentionSearchText] + ); + + const renderTextWithMentions = useMemo(() => { + if (!text) { + return null; + } + + if (mentions.length === 0) { + return null; + } + + const textParts: JSX.Element[] = []; + let lastIndex = 0; + + mentions + .sort((a, b) => a.start - b.start) + .forEach((mention, index) => { + if (mention.start > lastIndex) { + textParts.push( + + {text.slice(lastIndex, mention.start)} + + ); + } + + textParts.push( + + {mention.display} + + ); + + lastIndex = mention.end; + }); + + if (lastIndex < text.length) { + textParts.push( + + {text.slice(lastIndex)} + + ); + } + + return ( + + {textParts} + + ); + }, [mentions, text, initialHeight, maxInputHeight]); + + const sendMessage = useCallback( + async (isEdit?: boolean) => { + const story: Story = []; + // This is where we'll need to parse the text into inlines + + const finalAttachments = await waitForAttachmentUploads(); + + const blocks = finalAttachments.flatMap((attachment): Block[] => { + if (attachment.type === 'reference') { + const cite = pathToCite(attachment.path); + return cite ? [{ cite }] : []; + } + if ( + attachment.type === 'image' && + (!image || attachment.file.uri !== image?.uri) + ) { + return [ + { + image: { + src: attachment.uploadState.remoteUri, + height: attachment.file.height, + width: attachment.file.width, + alt: 'image', + }, + }, + ]; + } + + if ( + image && + attachment.type === 'image' && + attachment.file.uri === image?.uri && + isEdit && + channelType === 'gallery' + ) { + return [ + { + image: { + src: image.uri, + height: image.height, + width: image.width, + alt: 'image', + }, + }, + ]; + } + + return []; + }); + + if (blocks && blocks.length > 0) { + if (channelType === 'chat') { + story.unshift(...blocks.map((block) => ({ block }))); + } else { + story.push(...blocks.map((block) => ({ block }))); + } + } + + const metadata: db.PostMetadata = {}; + + if (image) { + const attachment = finalAttachments.find( + (a): a is UploadedImageAttachment => + a.type === 'image' && a.file.uri === image.uri + ); + if (!attachment) { + throw new Error('unable to attach image'); + } + metadata['image'] = attachment.uploadState.remoteUri; + } + + if (isEdit && editingPost) { + if (editingPost.parentId) { + await editPost?.(editingPost, story, editingPost.parentId, metadata); + } + await editPost?.(editingPost, story, undefined, metadata); + setEditingPost?.(undefined); + } else { + // not awaiting since we don't want to wait for the send to complete + // before clearing the draft and the editor content + send(story, channelId, metadata); + } + + onSend?.(); + setText(''); + setMentions([]); + clearAttachments(); + clearDraft(); + }, + [ + onSend, + waitForAttachmentUploads, + editingPost, + clearAttachments, + clearDraft, + editPost, + setEditingPost, + image, + channelType, + send, + channelId, + ] + ); + + const runSendMessage = useCallback( + async (isEdit: boolean) => { + setIsSending(true); + try { + await sendMessage(isEdit); + } catch (e) { + console.error('failed to send', e); + setSendError(true); + } + setIsSending(false); + setSendError(false); + }, + [sendMessage] + ); + + const handleSend = useCallback(async () => { + Keyboard.dismiss(); + runSendMessage(false); + }, [runSendMessage]); + + const handleEdit = useCallback(async () => { + Keyboard.dismiss(); + if (!editingPost) { + return; + } + runSendMessage(true); + }, [runSendMessage, editingPost]); + + // Make sure the user can still see some of the scroller when the keyboard is up + useEffect(() => { + Keyboard.addListener('keyboardDidShow', () => { + const keyboardHeight = Keyboard.metrics()?.height || 300; + setMaxInputHeight(maxInputHeightBasic - keyboardHeight); + }); + + Keyboard.addListener('keyboardDidHide', () => { + setMaxInputHeight(maxInputHeightBasic); + }); + }, [maxInputHeightBasic]); + + // Handle autofocus + useEffect(() => { + if (!shouldBlur && shouldAutoFocus && !hasAutoFocused) { + inputRef.current?.focus(); + setHasAutoFocused(true); + } + }, [shouldBlur, shouldAutoFocus, hasAutoFocused]); + + // Blur input when needed + useEffect(() => { + if (shouldBlur) { + inputRef.current?.blur(); + setShouldBlur(false); + } + }, [shouldBlur, setShouldBlur]); + + // Check if editor is empty + useEffect(() => { + setEditorIsEmpty(text === '' && attachments.length === 0); + }, [text, attachments]); + + // Set initial content from draft or post that is being edited + useEffect(() => { + if (!hasSetInitialContent) { + // messageInputLogger.log('Setting initial content'); + try { + getDraft().then((draft) => { + if (!editingPost && draft) { + // We'll need to parse the draft content here + // NOTE: drafts are currently stored as tiptap JSONContent + setEditorIsEmpty(false); + setHasSetInitialContent(true); + } + + if (editingPost && editingPost.content) { + const { + story, + references: postReferences, + blocks, + } = extractContentTypesFromPost(editingPost); + + if (story === null && !postReferences && blocks.length === 0) { + return; + } + + const attachments: Attachment[] = []; + + postReferences.forEach((p) => { + const cite = contentReferenceToCite(p); + const path = citeToPath(cite); + attachments.push({ + type: 'reference', + reference: p, + path, + }); + }); + + blocks.forEach((b) => { + if ('image' in b) { + attachments.push({ + type: 'image', + file: { + uri: b.image.src, + height: b.image.height, + width: b.image.width, + }, + }); + } + }); + + resetAttachments(attachments); + + // We'll need to parse the post content here + setEditorIsEmpty(false); + setHasSetInitialContent(true); + } + + if (editingPost?.image) { + addAttachment({ + type: 'image', + file: { + uri: editingPost.image, + height: 0, + width: 0, + }, + }); + } + }); + } catch (e) { + console.error('Error setting initial content', e); + } + } + }, [ + getDraft, + hasSetInitialContent, + editingPost, + resetAttachments, + addAttachment, + ]); + + // Store draft when text changes + useEffect(() => { + // NOTE: drafts are currently stored as tiptap JSONContent + // storeDraft(text); + }, [text, storeDraft]); + + return ( + setEditingPost?.(undefined)} + onPressEdit={handleEdit} + goBack={goBack} + > + + {showInlineAttachments && } + + {mentions.length > 0 && ( + + {renderTextWithMentions} + + )} + + + ); +} diff --git a/packages/ui/src/components/draftInputs/ChatInput.tsx b/packages/ui/src/components/draftInputs/ChatInput.tsx index 7ce1dc2fea..2aaf739cb8 100644 --- a/packages/ui/src/components/draftInputs/ChatInput.tsx +++ b/packages/ui/src/components/draftInputs/ChatInput.tsx @@ -1,6 +1,7 @@ import { SafeAreaView } from 'react-native-safe-area-context'; -import { MessageInput } from '../MessageInput'; +import BareChatInput from '../BareChatInput'; +// import { MessageInput } from '../MessageInput'; import { ParentAgnosticKeyboardAvoidingView } from '../ParentAgnosticKeyboardAvoidingView'; import { DraftInputContext } from './shared'; @@ -26,7 +27,7 @@ export function ChatInput({ return ( - Date: Wed, 23 Oct 2024 10:59:13 -0400 Subject: [PATCH 180/259] track app install, app update, and signed in before signup events --- .../src/components/AuthenticatedApp.tsx | 2 ++ apps/tlon-mobile/src/hooks/analytics.ts | 36 +++++++++++++++++++ apps/tlon-mobile/src/lib/lifecycleEvents.ts | 23 ++++++++++++ apps/tlon-mobile/src/lib/signupContext.tsx | 10 +++--- .../screens/Onboarding/ShipLoginScreen.tsx | 9 +++++ .../screens/Onboarding/TlonLoginScreen.tsx | 11 +++++- .../src/screens/Onboarding/WelcomeScreen.tsx | 4 ++- packages/shared/src/db/keyValue.ts | 10 ++++++ packages/shared/src/logic/analytics.ts | 3 ++ 9 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 apps/tlon-mobile/src/hooks/analytics.ts create mode 100644 apps/tlon-mobile/src/lib/lifecycleEvents.ts diff --git a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx index ce04c47457..07bd7ccb3f 100644 --- a/apps/tlon-mobile/src/components/AuthenticatedApp.tsx +++ b/apps/tlon-mobile/src/components/AuthenticatedApp.tsx @@ -11,6 +11,7 @@ import { ZStack } from '@tloncorp/ui'; import { useCallback, useEffect } from 'react'; import { AppStateStatus } from 'react-native'; +import { useCheckAppUpdated } from '../hooks/analytics'; import { useDeepLinkListener } from '../hooks/useDeepLinkListener'; import useNotificationListener from '../hooks/useNotificationListener'; @@ -23,6 +24,7 @@ function AuthenticatedApp() { useDeepLinkListener(); useNavigationLogging(); useNetworkLogger(); + useCheckAppUpdated(); useEffect(() => { configureClient(); diff --git a/apps/tlon-mobile/src/hooks/analytics.ts b/apps/tlon-mobile/src/hooks/analytics.ts new file mode 100644 index 0000000000..e432784bc3 --- /dev/null +++ b/apps/tlon-mobile/src/hooks/analytics.ts @@ -0,0 +1,36 @@ +import { useLureMetadata } from '@tloncorp/app/contexts/branch'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; +import { useEffect } from 'react'; + +import { checkLatestVersion } from '../lib/lifecycleEvents'; + +const logger = createDevLogger('analytics hooks', true); + +export function useCheckAppInstalled() { + const lureMeta = useLureMetadata(); + useEffect(() => { + async function checkNewlyInstalled() { + const { status } = await checkLatestVersion(); + if (status === 'installed') { + logger.trackEvent(AnalyticsEvent.AppInstalled, { + hadInitialInvite: lureMeta !== null, + }); + } + } + checkNewlyInstalled(); + }, []); +} + +export function useCheckAppUpdated() { + useEffect(() => { + async function checkNewlyInstalled() { + const { status, version } = await checkLatestVersion(); + if (status === 'updated') { + logger.trackEvent(AnalyticsEvent.AppUpdated, { + latestVersion: version, + }); + } + } + checkNewlyInstalled(); + }, []); +} diff --git a/apps/tlon-mobile/src/lib/lifecycleEvents.ts b/apps/tlon-mobile/src/lib/lifecycleEvents.ts new file mode 100644 index 0000000000..70061ffe40 --- /dev/null +++ b/apps/tlon-mobile/src/lib/lifecycleEvents.ts @@ -0,0 +1,23 @@ +import { getEasUpdateDisplay } from '@tloncorp/app/lib/platformHelpers'; +import { lastAppVersion } from '@tloncorp/shared/dist/db'; +import * as Application from 'expo-application'; +import * as Updates from 'expo-updates'; + +export async function checkLatestVersion() { + const lastVersion = await lastAppVersion.getValue(); + + const buildVersion = Application.nativeBuildVersion; + const otaVersion = getEasUpdateDisplay(Updates); + const currentVersion = `${buildVersion}:${otaVersion}`; + + lastAppVersion.setValue(currentVersion); + if (!lastVersion) { + return { status: 'installed', version: currentVersion }; + } + + if (lastVersion !== currentVersion) { + return { status: 'updated', version: currentVersion }; + } + + return { status: 'unchanged', version: currentVersion }; +} diff --git a/apps/tlon-mobile/src/lib/signupContext.tsx b/apps/tlon-mobile/src/lib/signupContext.tsx index 051f9b62ca..ca6c43930f 100644 --- a/apps/tlon-mobile/src/lib/signupContext.tsx +++ b/apps/tlon-mobile/src/lib/signupContext.tsx @@ -1,15 +1,14 @@ // This signup context lives here in the mobile app because this path can only // be reached by the mobile app and it's only used by the mobile app. +import { useBootSequence } from '@tloncorp/app/hooks/useBootSequence'; +import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; +import { connectNotifyProvider } from '@tloncorp/app/lib/notificationsApi'; import { createDevLogger } from '@tloncorp/shared/dist'; import * as api from '@tloncorp/shared/dist/api'; -import { SignupParams, signupData } from '@tloncorp/shared/dist/db'; +import { SignupParams, didSignUp, signupData } from '@tloncorp/shared/dist/db'; import * as store from '@tloncorp/shared/dist/store'; import { createContext, useCallback, useContext, useEffect } from 'react'; -import { useBootSequence } from '@tloncorp/app/hooks/useBootSequence'; -import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; -import { connectNotifyProvider } from '@tloncorp/app/lib/notificationsApi'; - const logger = createDevLogger('signup', true); type SignupValues = Omit; @@ -65,6 +64,7 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => { const handlePostSignup = useCallback(() => { try { logger.log('running post-signup actions'); + didSignUp.setValue(true); const postSignupParams = { nickname: values.nickname, telemetry: values.telemetry, diff --git a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx index 2e67695262..817a4b6a02 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx @@ -8,7 +8,9 @@ import { useShip } from '@tloncorp/app/contexts/ship'; import { setEulaAgreed } from '@tloncorp/app/utils/eula'; import { getShipFromCookie } from '@tloncorp/app/utils/ship'; import { transformShipURL } from '@tloncorp/app/utils/string'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; +import { didSignUp } from '@tloncorp/shared/dist/db'; import { Field, KeyboardAvoidingView, @@ -24,6 +26,8 @@ import { Controller, useForm } from 'react-hook-form'; import type { OnboardingStackParamList } from '../../types'; +const logger = createDevLogger('ShipLoginScreen', true); + type Props = NativeStackScreenProps; type FormData = { @@ -92,6 +96,11 @@ export const ShipLoginScreen = ({ navigation }: Props) => { authCookie, authType: 'self', }); + + const hasSignedUp = await didSignUp.getValue(); + if (!hasSignedUp) { + logger.trackEvent(AnalyticsEvent.LoggedInBeforeSignup); + } } else { setRemoteError( "Sorry, we couldn't log in to your ship. It may be busy or offline." diff --git a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx index 22e503e22c..0c2cb7da56 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx @@ -5,7 +5,6 @@ import { EMAIL_REGEX, } from '@tloncorp/app/constants'; import { useShip } from '@tloncorp/app/contexts/ship'; -import { useSignupContext } from '.././../lib/signupContext'; import { getShipAccessCode, getShipsWithStatus, @@ -14,7 +13,9 @@ import { } from '@tloncorp/app/lib/hostingApi'; import { isEulaAgreed, setEulaAgreed } from '@tloncorp/app/utils/eula'; import { getShipUrl } from '@tloncorp/app/utils/ship'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; +import { didSignUp } from '@tloncorp/shared/dist/db'; import { Field, KeyboardAvoidingView, @@ -29,6 +30,7 @@ import { useCallback, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import type { OnboardingStackParamList } from '../../types'; +import { useSignupContext } from '.././../lib/signupContext'; type Props = NativeStackScreenProps; @@ -38,6 +40,8 @@ type FormData = { eulaAgreed: boolean; }; +const logger = createDevLogger('TlonLoginScreen', true); + export const TlonLoginScreen = ({ navigation }: Props) => { const [isSubmitting, setIsSubmitting] = useState(false); const [remoteError, setRemoteError] = useState(); @@ -95,6 +99,11 @@ export const TlonLoginScreen = ({ navigation }: Props) => { authCookie, authType: 'hosted', }); + + const hasSignedUp = await didSignUp.getValue(); + if (!hasSignedUp) { + logger.trackEvent(AnalyticsEvent.LoggedInBeforeSignup); + } } else { setRemoteError( 'Please agree to the End User License Agreement to continue.' diff --git a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx index ba9e399ffa..aba76d3063 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx @@ -1,4 +1,3 @@ -import { useIsFocused } from '@react-navigation/native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; import { setDidShowBenefitsSheet } from '@tloncorp/shared/dist/db'; @@ -20,6 +19,7 @@ import { useCallback, useState } from 'react'; import { Pressable } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { useCheckAppInstalled } from '../../hooks/analytics'; import type { OnboardingStackParamList } from '../../types'; export const Text = TlonText.Text; @@ -32,6 +32,8 @@ export const WelcomeScreen = ({ navigation }: Props) => { const [open, setOpen] = useState(false); const { data: didShowBenefitsSheet } = useDidShowBenefitsSheet(); + useCheckAppInstalled(); + const handleBenefitsSheetOpenChange = useCallback((open: boolean) => { if (!open) { setTimeout(() => { diff --git a/packages/shared/src/db/keyValue.ts b/packages/shared/src/db/keyValue.ts index 58778da123..778ead5f1b 100644 --- a/packages/shared/src/db/keyValue.ts +++ b/packages/shared/src/db/keyValue.ts @@ -268,3 +268,13 @@ export const signupData = createStorageItem({ bootPhase: NodeBootPhase.IDLE, }, }); + +export const lastAppVersion = createStorageItem({ + key: 'lastAppVersion', + defaultValue: null, +}); + +export const didSignUp = createStorageItem({ + key: 'didSignUp', + defaultValue: false, +}); diff --git a/packages/shared/src/logic/analytics.ts b/packages/shared/src/logic/analytics.ts index f86422a452..b4ba996d6c 100644 --- a/packages/shared/src/logic/analytics.ts +++ b/packages/shared/src/logic/analytics.ts @@ -1,4 +1,7 @@ export enum AnalyticsEvent { InviteShared = 'Invite Link Shared', OnboardingSessionRevived = 'Onboarding Session Revived', + AppInstalled = 'App Installed', + AppUpdated = 'App Updated', + LoggedInBeforeSignup = 'Logged In Without Signing Up', } From ec23fb2bd1fb2a0c23724b288c34c643f332e9c1 Mon Sep 17 00:00:00 2001 From: Dan Brewster Date: Wed, 23 Oct 2024 13:04:14 -0400 Subject: [PATCH 181/259] use deploy key secret to push glob update (#4106) --- .github/workflows/deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d4f3321501..d24344fa59 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -73,6 +73,7 @@ jobs: - uses: actions/checkout@v3 with: ref: ${{ env.tag }} + ssh-key: ${{ secrets.DEPLOY_KEY }} - uses: actions/download-artifact@v3 with: name: "ui-dist" From 37de027acb99f37847f84f43df3bf6e0b1567ff5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 23 Oct 2024 17:09:25 +0000 Subject: [PATCH 182/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 53049d403c..cf1a28f4c5 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v4.l0ohn.clu7u.59ejp.p6lmk.jr5to.glob' 0v4.l0ohn.clu7u.59ejp.p6lmk.jr5to] + glob-http+['https://bootstrap.urbit.org/glob-0v3.j1k95.bj1do.768t7.ckdnu.39j36.glob' 0v3.j1k95.bj1do.768t7.ckdnu.39j36] base+'groups' version+[6 4 2] website+'https://tlon.io' From a9769356fde8141c176fa13b017e30e54c02c540 Mon Sep 17 00:00:00 2001 From: Dan Brewster Date: Wed, 23 Oct 2024 13:36:48 -0400 Subject: [PATCH 183/259] fix profile layout when bio is empty (#4107) --- .../fixtures/UserProfileScreen.fixture.tsx | 40 ++++++++++++++++--- .../src/components/UserProfileScreenView.tsx | 2 +- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx b/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx index 83a99940c5..20c326668e 100644 --- a/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx @@ -4,16 +4,31 @@ import { AppDataContextProvider, UserProfileScreenView, } from '@tloncorp/ui/src'; +import { useFixtureInput } from 'react-cosmos/client'; import { FixtureWrapper } from './FixtureWrapper'; import { group } from './fakeData'; const exampleContacts: Record = { - zod: { + base: { + id: '~solfer-magfed', + nickname: 'Dan b', + color: faker.color.rgb(), + bio: faker.lorem.paragraphs(2), + avatarImage: faker.image.avatar(), + coverImage: faker.image.urlLoremFlickr(), + pinnedGroups: [ + { + contactId: '~fabled-faster', + groupId: group.id, + group, + }, + ], + }, + noBio: { id: '~fabled-faster', nickname: 'É. Urcades', color: faker.color.rgb(), - bio: faker.lorem.paragraphs(2), avatarImage: faker.image.avatar(), coverImage: faker.image.urlLoremFlickr(), pinnedGroups: [ @@ -24,17 +39,22 @@ const exampleContacts: Record = { }, ], }, + empty: { + id: '~latter-bolden', + }, }; -function ProfileScreenFixture() { +function ProfileScreenFixture({ contactId }: { contactId: string }) { + const [isCurrentUser] = useFixtureInput('isCurrentUser', false); + return ( {}} connectionStatus={{ complete: true, status: 'yes' }} onPressEdit={() => {}} @@ -47,4 +67,12 @@ function ProfileScreenFixture() { ); } -export default ; +export default { + 'Full Profile': , + 'Profile without bio': ( + + ), + 'Empty profile': ( + + ), +}; diff --git a/packages/ui/src/components/UserProfileScreenView.tsx b/packages/ui/src/components/UserProfileScreenView.tsx index 7fba71d30c..17355e0803 100644 --- a/packages/ui/src/components/UserProfileScreenView.tsx +++ b/packages/ui/src/components/UserProfileScreenView.tsx @@ -245,7 +245,7 @@ function UserInfoRow(props: { userId: string; hasNickname: boolean }) { onPress={handleCopy} padding="$l" gap="$xl" - flex={1} + width={'100%'} > From 311c0f4d843e5bf361331475f38470b609afd059 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 23 Oct 2024 12:44:10 -0500 Subject: [PATCH 184/259] move mentions logic out to useMentions, move BareChatInput to its own directory --- .../index.tsx} | 118 ++++-------------- .../components/BareChatInput/useMentions.tsx | 115 +++++++++++++++++ 2 files changed, 137 insertions(+), 96 deletions(-) rename packages/ui/src/components/{BareChatInput.tsx => BareChatInput/index.tsx} (78%) create mode 100644 packages/ui/src/components/BareChatInput/useMentions.tsx diff --git a/packages/ui/src/components/BareChatInput.tsx b/packages/ui/src/components/BareChatInput/index.tsx similarity index 78% rename from packages/ui/src/components/BareChatInput.tsx rename to packages/ui/src/components/BareChatInput/index.tsx index 1f28cd9e5f..45bc83df4d 100644 --- a/packages/ui/src/components/BareChatInput.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -17,20 +17,14 @@ import { Attachment, UploadedImageAttachment, useAttachmentContext, -} from '../contexts'; -import { DEFAULT_MESSAGE_INPUT_HEIGHT } from './MessageInput'; -import { AttachmentPreviewList } from './MessageInput/AttachmentPreviewList'; +} from '../../contexts'; +import { DEFAULT_MESSAGE_INPUT_HEIGHT } from '../MessageInput'; +import { AttachmentPreviewList } from '../MessageInput/AttachmentPreviewList'; import { MessageInputContainer, MessageInputProps, -} from './MessageInput/MessageInputBase'; - -interface Mention { - id: string; - display: string; - start: number; - end: number; -} +} from '../MessageInput/MessageInputBase'; +import { useMentions } from './useMentions'; export default function BareChatInput({ shouldBlur, @@ -71,17 +65,19 @@ export default function BareChatInput({ waitForAttachmentUploads, } = useAttachmentContext(); const [text, setText] = useState(''); - const [mentions, setMentions] = useState([]); const [isSending, setIsSending] = useState(false); const [sendError, setSendError] = useState(false); const [hasSetInitialContent, setHasSetInitialContent] = useState(false); const [editorIsEmpty, setEditorIsEmpty] = useState(attachments.length === 0); - const [showMentionPopup, setShowMentionPopup] = useState(false); const [hasAutoFocused, setHasAutoFocused] = useState(false); - const [mentionStartIndex, setMentionStartIndex] = useState( - null - ); - const [mentionSearchText, setMentionSearchText] = useState(''); + const { + handleMention, + handleSelectMention, + mentionSearchText, + mentions, + setMentions, + showMentionPopup, + } = useMentions(); const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); const inputRef = useRef(null); @@ -89,94 +85,23 @@ export default function BareChatInput({ const oldText = text; setText(newText); - // Check if we're deleting a trigger symbol - if (newText.length < oldText.length && showMentionPopup) { - const deletedChar = oldText[newText.length]; - if (deletedChar === '@' || deletedChar === '~') { - setShowMentionPopup(false); - setMentionStartIndex(null); - setMentionSearchText(''); - return; - } - } - - // Check for @ symbol - const lastAtSymbol = newText.lastIndexOf('@'); - if (lastAtSymbol >= 0 && lastAtSymbol === newText.length - 1) { - setShowMentionPopup(true); - setMentionStartIndex(lastAtSymbol); - setMentionSearchText(''); - } else if (showMentionPopup && mentionStartIndex !== null) { - // Update mention search text - const searchText = newText.slice(mentionStartIndex + 1); - if (!searchText.includes(' ')) { - setMentionSearchText(searchText); - } else { - setShowMentionPopup(false); - setMentionStartIndex(null); - setMentionSearchText(''); - } - } - - // Check for ~ symbol - const lastSig = newText.lastIndexOf('~'); - if (lastSig >= 0 && lastSig === newText.length - 1) { - setShowMentionPopup(true); - setMentionStartIndex(lastSig); - setMentionSearchText(''); - } else if (showMentionPopup && mentionStartIndex !== null) { - // Update mention search text - const searchText = newText.slice(mentionStartIndex + 1); - if (!searchText.includes(' ')) { - setMentionSearchText(searchText); - } else { - setShowMentionPopup(false); - setMentionStartIndex(null); - setMentionSearchText(''); - } - } - - // Update mention positions when text changes - if (mentions.length > 0) { - const updatedMentions = mentions.filter( - (mention) => - mention.start <= newText.length && - newText.slice(mention.start, mention.end) === mention.display - ); - if (updatedMentions.length !== mentions.length) { - setMentions(updatedMentions); - } - } + handleMention(oldText, newText); }; - const handleSelectMention = useCallback( + const onMentionSelect = useCallback( (contact: db.Contact) => { - if (mentionStartIndex === null) return; - - const mentionDisplay = `${contact.id}`; - const beforeMention = text.slice(0, mentionStartIndex); - const afterMention = text.slice( - mentionStartIndex + (mentionSearchText?.length || 0) + 1 - ); + const newText = handleSelectMention(contact, text); - const newText = beforeMention + mentionDisplay + ' ' + afterMention; - const newMention: Mention = { - id: contact.id, - display: mentionDisplay, - start: mentionStartIndex, - end: mentionStartIndex + mentionDisplay.length, - }; + if (!newText) { + return; + } setText(newText); - setMentions((prev) => [...prev, newMention]); - setShowMentionPopup(false); - setMentionStartIndex(null); - setMentionSearchText(''); // Force focus back to input after mention selection inputRef.current?.focus(); }, - [mentionStartIndex, text, mentionSearchText] + [handleSelectMention, text] ); const renderTextWithMentions = useMemo(() => { @@ -339,6 +264,7 @@ export default function BareChatInput({ channelType, send, channelId, + setMentions, ] ); @@ -499,7 +425,7 @@ export default function BareChatInput({ mentionText={mentionSearchText} showAttachmentButton={showAttachmentButton} groupMembers={groupMembers} - onSelectMention={handleSelectMention} + onSelectMention={onMentionSelect} isSending={isSending} isEditing={!!editingPost} cancelEditing={() => setEditingPost?.(undefined)} diff --git a/packages/ui/src/components/BareChatInput/useMentions.tsx b/packages/ui/src/components/BareChatInput/useMentions.tsx new file mode 100644 index 0000000000..29e6fd614b --- /dev/null +++ b/packages/ui/src/components/BareChatInput/useMentions.tsx @@ -0,0 +1,115 @@ +import * as db from '@tloncorp/shared/dist/db'; +import { useState } from 'react'; + +interface Mention { + id: string; + display: string; + start: number; + end: number; +} + +export const useMentions = () => { + const [showMentionPopup, setShowMentionPopup] = useState(false); + const [mentionStartIndex, setMentionStartIndex] = useState( + null + ); + const [mentionSearchText, setMentionSearchText] = useState(''); + const [mentions, setMentions] = useState([]); + + const handleMention = (oldText: string, newText: string) => { + // Check if we're deleting a trigger symbol + if (newText.length < oldText.length && showMentionPopup) { + const deletedChar = oldText[newText.length]; + if (deletedChar === '@' || deletedChar === '~') { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + return; + } + } + + // Check for @ symbol + const lastAtSymbol = newText.lastIndexOf('@'); + if (lastAtSymbol >= 0 && lastAtSymbol === newText.length - 1) { + setShowMentionPopup(true); + setMentionStartIndex(lastAtSymbol); + setMentionSearchText(''); + } else if (showMentionPopup && mentionStartIndex !== null) { + // Update mention search text + const searchText = newText.slice(mentionStartIndex + 1); + if (!searchText.includes(' ')) { + setMentionSearchText(searchText); + } else { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + } + } + + // Check for ~ symbol + const lastSig = newText.lastIndexOf('~'); + if (lastSig >= 0 && lastSig === newText.length - 1) { + setShowMentionPopup(true); + setMentionStartIndex(lastSig); + setMentionSearchText(''); + } else if (showMentionPopup && mentionStartIndex !== null) { + // Update mention search text + const searchText = newText.slice(mentionStartIndex + 1); + if (!searchText.includes(' ')) { + setMentionSearchText(searchText); + } else { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + } + } + + // Update mention positions when text changes + if (mentions.length > 0) { + const updatedMentions = mentions.filter( + (mention) => + mention.start <= newText.length && + newText.slice(mention.start, mention.end) === mention.display + ); + if (updatedMentions.length !== mentions.length) { + setMentions(updatedMentions); + } + } + }; + + const handleSelectMention = (contact: db.Contact, text: string) => { + if (mentionStartIndex === null) return; + + const mentionDisplay = `${contact.id}`; + const beforeMention = text.slice(0, mentionStartIndex); + const afterMention = text.slice( + mentionStartIndex + (mentionSearchText?.length || 0) + 1 + ); + + const newText = beforeMention + mentionDisplay + ' ' + afterMention; + const newMention: Mention = { + id: contact.id, + display: mentionDisplay, + start: mentionStartIndex, + end: mentionStartIndex + mentionDisplay.length, + }; + + setMentions((prev) => [...prev, newMention]); + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); + + return newText; + }; + + return { + mentions, + setMentions, + mentionSearchText, + setMentionSearchText, + handleMention, + handleSelectMention, + showMentionPopup, + setShowMentionPopup, + }; +}; From fb1aaa6915cd4dbe3e86960a4d46c74b06916f9c Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 23 Oct 2024 15:03:28 -0400 Subject: [PATCH 185/259] bump version --- apps/tlon-mobile/android/app/build.gradle | 2 +- apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/tlon-mobile/android/app/build.gradle b/apps/tlon-mobile/android/app/build.gradle index 4ae092d499..983b265bb3 100644 --- a/apps/tlon-mobile/android/app/build.gradle +++ b/apps/tlon-mobile/android/app/build.gradle @@ -88,7 +88,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion compileSdk rootProject.ext.compileSdkVersion versionCode 108 - versionName "4.1.0" + versionName "4.1.1" buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString()) } diff --git a/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj b/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj index 0e17d10661..41736a3f82 100644 --- a/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj +++ b/apps/tlon-mobile/ios/Landscape.xcodeproj/project.pbxproj @@ -1395,7 +1395,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.1.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -1433,7 +1433,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.1.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", From fcec15cd50929dd01cbf9c6bc3c226a710d20c19 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 23 Oct 2024 17:27:09 -0400 Subject: [PATCH 186/259] switch posthob by environment, update ota action to account for expo configured env vars --- .github/workflows/mobile-update.yml | 30 ++++++++++++++++------------- apps/tlon-mobile/app.config.ts | 4 +++- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/mobile-update.yml b/.github/workflows/mobile-update.yml index e48097dc37..78217269f5 100644 --- a/.github/workflows/mobile-update.yml +++ b/.github/workflows/mobile-update.yml @@ -7,7 +7,7 @@ on: description: Select profile options: - preview - - production + - placeholder platform: type: choice description: Select platform @@ -15,6 +15,10 @@ on: - all - android - ios + message: + type: string + description: Brief description of what this update contains + required: true jobs: deploy: runs-on: ubuntu-latest @@ -35,19 +39,19 @@ jobs: run: pnpm install - name: Build packages run: pnpm build:all - - name: Create build vars - id: vars - run: | - echo "profile=${{ inputs.profile || 'preview' }}" >> $GITHUB_OUTPUT - name: Push update for selected platforms working-directory: ./apps/tlon-mobile run: - eas update --auto --profile ${{ steps.vars.outputs.profile }} - --platform ${{ inputs.platform || 'all' }} --non-interactive + eas update --channel ${{ inputs.profile }} --platform ${{ + inputs.platform || 'all' }} --message '${{inputs.message}}' + --non-interactive env: - NOTIFY_PROVIDER: - "${{ steps.vars.outputs.profile == 'preview' && - 'binnec-dozzod-marnus' || 'rivfur-livmet' }}" - NOTIFY_SERVICE: - "${{ steps.vars.outputs.profile == 'preview' && - 'tlon-preview-release' || 'groups-native' }}" + BRANCH_DOMAIN_PROD: ${{ secrets.BRANCH_DOMAIN_PROD }} + BRANCH_DOMAIN_TEST: ${{ secrets.BRANCH_DOMAIN_TEST }} + BRANCH_KEY_PROD: ${{ secrets.BRANCH_KEY_PROD }} + BRANCH_KEY_TEST: ${{ secrets.BRANCH_KEY_TEST }} + POST_HOG_API_KEY_TEST: ${{ secrets.POST_HOG_API_KEY_TEST }} + POST_HOG_API_KEY_PROD: ${{ secrets.POST_HOG_API_KEY_PROD }} + RECAPTCHA_SITE_KEY_ANDROID: ${{ secrets.RECAPTCHA_SITE_KEY_ANDROID }} + RECAPTCHA_SITE_KEY_IOS: ${{ secrets.RECAPTCHA_SITE_KEY_IOS }} + TLON_EMPLOYEE_GROUP: ${{ secrets.TLON_EMPLOYEE_GROUP }} diff --git a/apps/tlon-mobile/app.config.ts b/apps/tlon-mobile/app.config.ts index e2ecd6872a..bb74ac897f 100644 --- a/apps/tlon-mobile/app.config.ts +++ b/apps/tlon-mobile/app.config.ts @@ -19,7 +19,9 @@ export default ({ config }: ConfigContext): ExpoConfig => ({ eas: { projectId, }, - postHogApiKey: process.env.POST_HOG_API_KEY, + postHogApiKey: isPreview + ? process.env.POST_HOG_API_KEY_TEST + : process.env.POST_HOG_API_KEY_PROD, postHogInDev: process.env.POST_HOG_IN_DEV, notifyProvider: process.env.NOTIFY_PROVIDER, notifyService: process.env.NOTIFY_SERVICE, From f23cc1dc10620b7b07b8193a7c56510be0fb5b9e Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 23 Oct 2024 17:37:10 -0400 Subject: [PATCH 187/259] fix pnpm --- .github/workflows/mobile-update.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mobile-update.yml b/.github/workflows/mobile-update.yml index 78217269f5..af4e1d0a07 100644 --- a/.github/workflows/mobile-update.yml +++ b/.github/workflows/mobile-update.yml @@ -35,15 +35,19 @@ jobs: with: eas-version: latest token: ${{ secrets.EXPO_TOKEN }} - - name: Install dependencies - run: pnpm install + - name: Setup PNPM + uses: pnpm/action-setup@v3 + with: + run_install: | + - recursive: true + args: [--frozen-lockfile] - name: Build packages run: pnpm build:all - name: Push update for selected platforms working-directory: ./apps/tlon-mobile run: eas update --channel ${{ inputs.profile }} --platform ${{ - inputs.platform || 'all' }} --message '${{inputs.message}}' + inputs.platform || 'all' }} --message '${{ inputs.message }}' --non-interactive env: BRANCH_DOMAIN_PROD: ${{ secrets.BRANCH_DOMAIN_PROD }} From df1aa94c0a31b8cc50565f07bec178a4bd509244 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 23 Oct 2024 17:56:39 -0400 Subject: [PATCH 188/259] explicitly set app variant --- .github/workflows/mobile-update.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mobile-update.yml b/.github/workflows/mobile-update.yml index af4e1d0a07..ebf2a8c3a0 100644 --- a/.github/workflows/mobile-update.yml +++ b/.github/workflows/mobile-update.yml @@ -50,6 +50,7 @@ jobs: inputs.platform || 'all' }} --message '${{ inputs.message }}' --non-interactive env: + APP_VARIANT: ${{ inputs.profile }} BRANCH_DOMAIN_PROD: ${{ secrets.BRANCH_DOMAIN_PROD }} BRANCH_DOMAIN_TEST: ${{ secrets.BRANCH_DOMAIN_TEST }} BRANCH_KEY_PROD: ${{ secrets.BRANCH_KEY_PROD }} From aa407f352ffb6dde2d5cf79f5f92cc766939ca68 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Wed, 23 Oct 2024 18:09:08 -0400 Subject: [PATCH 189/259] add production back in --- .github/workflows/mobile-update.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mobile-update.yml b/.github/workflows/mobile-update.yml index ebf2a8c3a0..1d1c4f68d5 100644 --- a/.github/workflows/mobile-update.yml +++ b/.github/workflows/mobile-update.yml @@ -7,7 +7,7 @@ on: description: Select profile options: - preview - - placeholder + - production platform: type: choice description: Select platform From 8d19889da9becc8d37ef36aa7310346a3fcecab8 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Wed, 23 Oct 2024 17:13:19 -0500 Subject: [PATCH 190/259] sync: guard against accidentally starting multiple sync starts --- packages/shared/src/store/sync.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/store/sync.ts b/packages/shared/src/store/sync.ts index 4d9b07703c..681b54a50c 100644 --- a/packages/shared/src/store/sync.ts +++ b/packages/shared/src/store/sync.ts @@ -13,7 +13,7 @@ import { resetActivityFetchers, } from '../store/useActivityFetchers'; import { useLureState } from './lure'; -import { updateIsSyncing, updateSession } from './session'; +import { getSyncing, updateIsSyncing, updateSession } from './session'; import { SyncCtx, SyncPriority, syncQueue } from './syncQueue'; import { addToChannelPosts, clearChannelPostsQueries } from './useChannelPosts'; @@ -1026,6 +1026,10 @@ export const clearSyncQueue = () => { concerns and punts on full correctness. */ export const handleDiscontinuity = async () => { + if (getSyncing()) { + // we probably don't want to do this while we're already syncing + return; + } updateSession(null); // drop potentially outdated newest post markers @@ -1043,6 +1047,11 @@ export const handleChannelStatusChange = async (status: ChannelStatus) => { }; export const syncStart = async (alreadySubscribed?: boolean) => { + if (getSyncing()) { + // we probably don't want multiple sync starts + return; + } + updateIsSyncing(true); logger.crumb(`sync start running${alreadySubscribed ? ' (recovery)' : ''}`); From d8fb978a0b5c9242e83769f16c6b824b9b3dfa8d Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 24 Oct 2024 04:15:19 +0000 Subject: [PATCH 191/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index cf1a28f4c5..d3640016db 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v3.j1k95.bj1do.768t7.ckdnu.39j36.glob' 0v3.j1k95.bj1do.768t7.ckdnu.39j36] + glob-http+['https://bootstrap.urbit.org/glob-0v3.rhppp.m7lse.s7lts.qbgd6.kj4uk.glob' 0v3.rhppp.m7lse.s7lts.qbgd6.kj4uk] base+'groups' version+[6 4 2] website+'https://tlon.io' From 62d62048f5f9efef5b05e61b3261b9d4ecf17d93 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 24 Oct 2024 04:50:08 +0000 Subject: [PATCH 192/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index d3640016db..4f45e6d959 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v3.rhppp.m7lse.s7lts.qbgd6.kj4uk.glob' 0v3.rhppp.m7lse.s7lts.qbgd6.kj4uk] + glob-http+['https://bootstrap.urbit.org/glob-0v2.gkr79.a2mt0.igle8.qrl1s.4iqae.glob' 0v2.gkr79.a2mt0.igle8.qrl1s.4iqae] base+'groups' version+[6 4 2] website+'https://tlon.io' From 5c2bed8a36c9ac1be6090610a3d132a112d5aa4f Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 05:12:55 -0500 Subject: [PATCH 193/259] parse text from input to JSONContent --- packages/shared/src/logic/index.ts | 1 + packages/shared/src/logic/tiptap.ts | 4 +- .../src/components/BareChatInput/helpers.ts | 218 ++++++++++++++++++ .../ui/src/components/BareChatInput/index.tsx | 17 +- .../components/BareChatInput/useMentions.tsx | 2 +- .../components/MessageInput/index.native.tsx | 5 +- .../ui/src/components/MessageInput/index.tsx | 7 +- 7 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 packages/ui/src/components/BareChatInput/helpers.ts diff --git a/packages/shared/src/logic/index.ts b/packages/shared/src/logic/index.ts index e460101969..b7fbc5db2a 100644 --- a/packages/shared/src/logic/index.ts +++ b/packages/shared/src/logic/index.ts @@ -7,3 +7,4 @@ export * from './activity'; export * from './branch'; export * from './deeplinks'; export * from './analytics'; +export * from './tiptap'; diff --git a/packages/shared/src/logic/tiptap.ts b/packages/shared/src/logic/tiptap.ts index 00f90e7caa..224dc7a970 100644 --- a/packages/shared/src/logic/tiptap.ts +++ b/packages/shared/src/logic/tiptap.ts @@ -503,7 +503,7 @@ export function JSONToInlines( } } -const makeText = (t: string) => ({ type: 'text', text: t }); +export const makeText = (t: string) => ({ type: 'text', text: t }); const makeLink = (link: Link['link']) => ({ type: 'text', marks: [{ type: 'link', attrs: { href: link.href } }], @@ -846,7 +846,7 @@ export function normalizeInline(inline: Inline[]): Inline[] { ); } -export const REF_REGEX = /\/1\/(chan|group|desk)\/[^\s]+/g; +const REF_REGEX = /\/1\/(chan|group|desk)\/[^\s]+/g; export function refPasteRule(onReference: (r: Cite) => void) { return new PasteRule({ diff --git a/packages/ui/src/components/BareChatInput/helpers.ts b/packages/ui/src/components/BareChatInput/helpers.ts new file mode 100644 index 0000000000..5f6cdce9e9 --- /dev/null +++ b/packages/ui/src/components/BareChatInput/helpers.ts @@ -0,0 +1,218 @@ +import { makeMention, makeParagraph, makeText } from '@tloncorp/shared'; +import { JSONContent } from '@tloncorp/shared/dist/urbit'; + +import { Mention } from './useMentions'; + +const isBoldStart = (text: string): boolean => { + return text.startsWith('**'); +}; + +const isBoldEnd = (text: string): boolean => { + return text.endsWith('**'); +}; + +const isItalicStart = (text: string): boolean => { + return text.startsWith('*'); +}; + +const isItalicEnd = (text: string): boolean => { + return text.endsWith('*'); +}; + +const isCodeStart = (text: string): boolean => { + return text.startsWith('`'); +}; + +const isCodeEnd = (text: string): boolean => { + return text.endsWith('`'); +}; + +const urlRegex = + /(^|[^\w\s])((https?:\/\/|www\.)[^\s,?!.]+(?:[.][^\s,?!.]+)*(?:[^\s,?!.])*)([,?!.])?/; + +const isUrl = (text: string): boolean => { + return urlRegex.test(text); +}; + +const processLine = (line: string, mentions: Mention[]): JSONContent => { + const parsedContent: JSONContent[] = []; + let isBolding = false; + let isItalicizing = false; + let isCoding = false; + line.split(' ').forEach((word) => { + const marks = []; + const mention = mentions.find((mention) => mention.display === word); + if (mention) { + parsedContent.push(makeMention(mention.id)); + parsedContent.push(makeText(' ')); + return; + } + + if (isUrl(word)) { + const match = urlRegex.exec(word); + if (match) { + const [_, precedingChar, url, , followingChar] = match; + + if (precedingChar && precedingChar !== '') { + parsedContent.push(makeText(precedingChar)); + } + + parsedContent.push({ + type: 'text', + text: url, + marks: [ + { + type: 'link', + attrs: { + href: url, + }, + }, + ], + }); + + if (followingChar) { + parsedContent.push(makeText(followingChar)); + } + + parsedContent.push(makeText(' ')); + return; + } + } + + if (isCodeStart(word)) { + isCoding = true; + word = word.slice(1); + } + + if (isCoding) { + marks.push({ type: 'code' }); + if (isCodeEnd(word)) { + isCoding = false; + word = word.slice(0, -1); + } + + parsedContent.push({ + ...makeText(word), + marks, + }); + + parsedContent.push(makeText(' ')); + return; + } + + if (isBoldStart(word)) { + isBolding = true; + word = word.slice(2); + } + + if (isItalicStart(word)) { + isItalicizing = true; + word = word.slice(1); + } + + if (isBolding) { + marks.push({ type: 'bold' }); + if (isBoldEnd(word)) { + isBolding = false; + word = word.slice(0, -2); + } + } + + if (isItalicizing) { + marks.push({ type: 'italics' }); + if (isItalicEnd(word)) { + isItalicizing = false; + word = word.slice(0, -1); + } + } + + if (marks.length > 0) { + parsedContent.push({ + ...makeText(word), + marks, + }); + } else { + parsedContent.push(makeText(word)); + } + + parsedContent.push(makeText(' ')); + }); + + return makeParagraph(parsedContent); +}; + +function processTextLines(lines: string[], mentions: Mention[]): JSONContent[] { + return lines.map((line) => processLine(line.trim(), mentions)); +} + +export function textAndMentionsToContent( + text: string, + mentions: Mention[] +): JSONContent { + if (text === '') { + return []; + } + + const lines = text.split('\n'); + const content: JSONContent[] = []; + let currentLines: string[] = []; + let inCodeBlock = false; + let currentCodeBlock: string[] = []; + const language = 'plaintext'; + + lines.forEach((line) => { + if (line.startsWith('```')) { + if (!inCodeBlock) { + if (currentLines.length > 0) { + content.push(...processTextLines(currentLines, mentions)); + currentLines = []; + } + + inCodeBlock = true; + } else { + inCodeBlock = false; + content.push({ + type: 'codeBlock', + content: [ + { + type: 'text', + text: currentCodeBlock.join('\n'), + }, + ], + attrs: { + language, + }, + }); + currentCodeBlock = []; + } + } else if (inCodeBlock) { + currentCodeBlock.push(line); + } else { + currentLines.push(line); + } + }); + + if (inCodeBlock && currentCodeBlock.length > 0) { + content.push({ + type: 'codeBlock', + content: [ + { + type: 'text', + text: currentCodeBlock.join('\n'), + }, + ], + attrs: { + language, + }, + }); + } + + if (currentLines.length > 0) { + content.push(...processTextLines(currentLines, mentions)); + } + + return { + type: 'doc', + content, + }; +} diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 45bc83df4d..55b593b587 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -1,10 +1,11 @@ -import { extractContentTypesFromPost } from '@tloncorp/shared'; +import { JSONToInlines, extractContentTypesFromPost } from '@tloncorp/shared'; import { contentReferenceToCite } from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; import { Block, Story, citeToPath, + constructStory, pathToCite, } from '@tloncorp/shared/dist/urbit'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -24,6 +25,7 @@ import { MessageInputContainer, MessageInputProps, } from '../MessageInput/MessageInputBase'; +import { textAndMentionsToContent } from './helpers'; import { useMentions } from './useMentions'; export default function BareChatInput({ @@ -165,8 +167,9 @@ export default function BareChatInput({ const sendMessage = useCallback( async (isEdit?: boolean) => { - const story: Story = []; - // This is where we'll need to parse the text into inlines + const jsonContent = textAndMentionsToContent(text, mentions); + const inlines = JSONToInlines(jsonContent); + const story = constructStory(inlines); const finalAttachments = await waitForAttachmentUploads(); @@ -254,6 +257,8 @@ export default function BareChatInput({ }, [ onSend, + mentions, + text, waitForAttachmentUploads, editingPost, clearAttachments, @@ -410,9 +415,9 @@ export default function BareChatInput({ // Store draft when text changes useEffect(() => { - // NOTE: drafts are currently stored as tiptap JSONContent - // storeDraft(text); - }, [text, storeDraft]); + const jsonContent = textAndMentionsToContent(text, mentions); + storeDraft(jsonContent); + }, [text, mentions, storeDraft]); return ( ( const newInlines = inlines .map((inline) => { if (typeof inline === 'string') { - if (inline.match(tiptap.REF_REGEX)) { + if (inline.match(REF_REGEX)) { return null; } return inline; @@ -461,7 +462,7 @@ export const MessageInput = forwardRef( editor, editorJson, pastedText, - matchRegex: tiptap.REF_REGEX, + matchRegex: REF_REGEX, processMatch: async (match) => { const cite = pathToCite(match); if (cite) { diff --git a/packages/ui/src/components/MessageInput/index.tsx b/packages/ui/src/components/MessageInput/index.tsx index 91123cf70a..9902540c7e 100644 --- a/packages/ui/src/components/MessageInput/index.tsx +++ b/packages/ui/src/components/MessageInput/index.tsx @@ -14,6 +14,7 @@ import Strike from '@tiptap/extension-strike'; import Text from '@tiptap/extension-text'; import { EditorContent, useEditor } from '@tiptap/react'; import { + REF_REGEX, createDevLogger, extractContentTypesFromPost, tiptap, @@ -283,7 +284,7 @@ export function MessageInput({ return; } if (pastedText) { - const isRef = pastedText.match(tiptap.REF_REGEX); + const isRef = pastedText.match(REF_REGEX); if (isRef) { const cite = pathToCite(isRef[0]); @@ -317,13 +318,13 @@ export function MessageInput({ if (typeof inline === 'string') { const inlineLength = inline.length; const refLength = - inline.match(tiptap.REF_REGEX)?.[0].length || 0; + inline.match(REF_REGEX)?.[0].length || 0; if (inlineLength === refLength) { return null; } - return inline.replace(tiptap.REF_REGEX, ''); + return inline.replace(REF_REGEX, ''); } return inline; }) From 840deb78f357940821975e0913de17d54fd7a045 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 06:12:55 -0500 Subject: [PATCH 194/259] merge adjacent text nodes --- .../src/components/BareChatInput/helpers.ts | 42 ++++++++++++++++++- .../ui/src/components/BareChatInput/index.tsx | 3 +- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/helpers.ts b/packages/ui/src/components/BareChatInput/helpers.ts index 5f6cdce9e9..8da0028de2 100644 --- a/packages/ui/src/components/BareChatInput/helpers.ts +++ b/packages/ui/src/components/BareChatInput/helpers.ts @@ -34,6 +34,45 @@ const isUrl = (text: string): boolean => { return urlRegex.test(text); }; +function areMarksEqual(marks1: any[] = [], marks2: any[] = []): boolean { + if (marks1.length !== marks2.length) return false; + return marks1.every((mark1, i) => { + const mark2 = marks2[i]; + return mark1.type === mark2.type && + JSON.stringify(mark1.attrs || {}) === JSON.stringify(mark2.attrs || {}); + }); +} + +// Merge adjacent text nodes with the same marks +function mergeTextNodes(nodes: JSONContent[]): JSONContent[] { + const merged: JSONContent[] = []; + let currentNode: JSONContent | null = null; + + nodes.forEach((node) => { + if (!currentNode) { + currentNode = { ...node }; + return; + } + + if ( + currentNode.type === 'text' && + node.type === 'text' && + areMarksEqual(currentNode.marks, node.marks) + ) { + currentNode.text! += node.text; + } else { + merged.push(currentNode); + currentNode = { ...node }; + } + }); + + if (currentNode) { + merged.push(currentNode); + } + + return merged; +} + const processLine = (line: string, mentions: Mention[]): JSONContent => { const parsedContent: JSONContent[] = []; let isBolding = false; @@ -100,6 +139,7 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { return; } + // A word can be both bold and italicized if (isBoldStart(word)) { isBolding = true; word = word.slice(2); @@ -138,7 +178,7 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { parsedContent.push(makeText(' ')); }); - return makeParagraph(parsedContent); + return makeParagraph(mergeTextNodes(parsedContent)); }; function processTextLines(lines: string[], mentions: Mention[]): JSONContent[] { diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 55b593b587..e8c794f9fd 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -3,7 +3,6 @@ import { contentReferenceToCite } from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; import { Block, - Story, citeToPath, constructStory, pathToCite, @@ -170,6 +169,8 @@ export default function BareChatInput({ const jsonContent = textAndMentionsToContent(text, mentions); const inlines = JSONToInlines(jsonContent); const story = constructStory(inlines); + console.log('jsonContent', jsonContent); + console.log('inlines', inlines); const finalAttachments = await waitForAttachmentUploads(); From e95b72db9dbcfa2138133c5272d09931b67dfb40 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 06:36:01 -0500 Subject: [PATCH 195/259] parse and attach refs --- .../ui/src/components/BareChatInput/index.tsx | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index e8c794f9fd..1f96f73ae9 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -1,5 +1,12 @@ -import { JSONToInlines, extractContentTypesFromPost } from '@tloncorp/shared'; -import { contentReferenceToCite } from '@tloncorp/shared/dist/api'; +import { + JSONToInlines, + REF_REGEX, + extractContentTypesFromPost, +} from '@tloncorp/shared'; +import { + contentReferenceToCite, + toContentReference, +} from '@tloncorp/shared/dist/api'; import * as db from '@tloncorp/shared/dist/db'; import { Block, @@ -82,11 +89,46 @@ export default function BareChatInput({ const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); const inputRef = useRef(null); + const processReferences = useCallback( + (text: string): string => { + const references = text.match(REF_REGEX); + if (!references) { + return text; + } + + let newText = text; + references.forEach((ref) => { + const cite = pathToCite(ref); + if (!cite) { + return; + } + const reference = toContentReference(cite); + if (!reference) { + return; + } + + addAttachment({ + type: 'reference', + reference, + path: ref, + }); + + newText = newText.replace(ref, ''); + }); + + return newText; + }, + [addAttachment] + ); + const handleTextChange = (newText: string) => { const oldText = text; - setText(newText); - handleMention(oldText, newText); + const textWithoutRefs = processReferences(newText); + + setText(textWithoutRefs); + + handleMention(oldText, textWithoutRefs); }; const onMentionSelect = useCallback( From 535e2d8b8340ab723dfd25a3ed5a021ccd575e1a Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 09:01:06 -0500 Subject: [PATCH 196/259] mentions: always check for trigger symbols before/after current cursor position --- .../ui/src/components/BareChatInput/index.tsx | 1 - .../components/BareChatInput/useMentions.tsx | 69 +++++++++++-------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 1f96f73ae9..d8f93b8bf8 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -513,7 +513,6 @@ export default function BareChatInput({ backgroundColor="transparent" position="absolute" pointerEvents="none" - justifyContent="center" > {renderTextWithMentions} diff --git a/packages/ui/src/components/BareChatInput/useMentions.tsx b/packages/ui/src/components/BareChatInput/useMentions.tsx index 60e369406e..0a0fc6e73f 100644 --- a/packages/ui/src/components/BareChatInput/useMentions.tsx +++ b/packages/ui/src/components/BareChatInput/useMentions.tsx @@ -17,9 +17,20 @@ export const useMentions = () => { const [mentions, setMentions] = useState([]); const handleMention = (oldText: string, newText: string) => { + // Find cursor position by comparing old and new text + let cursorPosition = newText.length; + if (oldText.length !== newText.length) { + for (let i = 0; i < Math.min(oldText.length, newText.length); i++) { + if (oldText[i] !== newText[i]) { + cursorPosition = i + (newText.length > oldText.length ? 1 : 0); + break; + } + } + } + // Check if we're deleting a trigger symbol if (newText.length < oldText.length && showMentionPopup) { - const deletedChar = oldText[newText.length]; + const deletedChar = oldText[cursorPosition]; if (deletedChar === '@' || deletedChar === '~') { setShowMentionPopup(false); setMentionStartIndex(null); @@ -28,40 +39,40 @@ export const useMentions = () => { } } - // Check for @ symbol - const lastAtSymbol = newText.lastIndexOf('@'); - if (lastAtSymbol >= 0 && lastAtSymbol === newText.length - 1) { - setShowMentionPopup(true); - setMentionStartIndex(lastAtSymbol); - setMentionSearchText(''); - } else if (showMentionPopup && mentionStartIndex !== null) { - // Update mention search text - const searchText = newText.slice(mentionStartIndex + 1); - if (!searchText.includes(' ')) { - setMentionSearchText(searchText); - } else { - setShowMentionPopup(false); - setMentionStartIndex(null); - setMentionSearchText(''); - } - } + // Get the text before and after cursor + const beforeCursor = newText.slice(0, cursorPosition); + const afterCursor = newText.slice(cursorPosition); - // Check for ~ symbol - const lastSig = newText.lastIndexOf('~'); - if (lastSig >= 0 && lastSig === newText.length - 1) { - setShowMentionPopup(true); - setMentionStartIndex(lastSig); - setMentionSearchText(''); - } else if (showMentionPopup && mentionStartIndex !== null) { - // Update mention search text - const searchText = newText.slice(mentionStartIndex + 1); - if (!searchText.includes(' ')) { - setMentionSearchText(searchText); + // Find the last trigger symbol before cursor + const lastAtSymbol = beforeCursor.lastIndexOf('@'); + const lastSig = beforeCursor.lastIndexOf('~'); + const lastTriggerIndex = Math.max(lastAtSymbol, lastSig); + + if (lastTriggerIndex >= 0) { + // Check if there's a space between the trigger and cursor + const textBetweenTriggerAndCursor = beforeCursor.slice( + lastTriggerIndex + 1 + ); + const hasSpace = textBetweenTriggerAndCursor.includes(' '); + + // Only show popup if we're right after the trigger or actively searching + if ( + !hasSpace && + (cursorPosition === lastTriggerIndex + 1 || + (cursorPosition > lastTriggerIndex && !afterCursor.includes(' '))) + ) { + setShowMentionPopup(true); + setMentionStartIndex(lastTriggerIndex); + setMentionSearchText(textBetweenTriggerAndCursor); } else { setShowMentionPopup(false); setMentionStartIndex(null); setMentionSearchText(''); } + } else { + setShowMentionPopup(false); + setMentionStartIndex(null); + setMentionSearchText(''); } // Update mention positions when text changes From 49b9a78b1aaaa36d2d9a61c94e92ce283793da27 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 11:02:24 -0500 Subject: [PATCH 197/259] handle editing, saving/restoring drafts, fix issue with rendering multiple mentions --- .../src/components/BareChatInput/helpers.ts | 67 ++++++++- .../ui/src/components/BareChatInput/index.tsx | 134 +++++++++--------- 2 files changed, 133 insertions(+), 68 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/helpers.ts b/packages/ui/src/components/BareChatInput/helpers.ts index 8da0028de2..489c184bc1 100644 --- a/packages/ui/src/components/BareChatInput/helpers.ts +++ b/packages/ui/src/components/BareChatInput/helpers.ts @@ -38,8 +38,10 @@ function areMarksEqual(marks1: any[] = [], marks2: any[] = []): boolean { if (marks1.length !== marks2.length) return false; return marks1.every((mark1, i) => { const mark2 = marks2[i]; - return mark1.type === mark2.type && - JSON.stringify(mark1.attrs || {}) === JSON.stringify(mark2.attrs || {}); + return ( + mark1.type === mark2.type && + JSON.stringify(mark1.attrs || {}) === JSON.stringify(mark2.attrs || {}) + ); }); } @@ -256,3 +258,64 @@ export function textAndMentionsToContent( content, }; } + +export function contentToTextAndMentions(jsonContent: JSONContent): { + text: string; + mentions: Mention[]; +} { + const text: string[] = []; + const mentions: Mention[] = []; + const content = jsonContent.content; + + if (!content) { + return { + text: '', + mentions: [], + }; + } + + content.forEach((node) => { + if (node.type === 'paragraph') { + if (!node.content) { + return; + } + node.content.forEach((child) => { + if (child.type === 'text') { + if (!child.text) { + return; + } + text.push(child.text); + } else if (child.type === 'mention') { + if (!child.attrs || !child.attrs.id) { + return; + } + + text.push(`~${child.attrs.id}`); + + const mentionStartIndex = text.join('').lastIndexOf('~'); + const mentionEndIndex = mentionStartIndex + child.attrs.id.length + 1; + + mentions.push({ + id: child.attrs!.id, + display: `~${child.attrs!.id}`, + start: mentionStartIndex, + end: mentionEndIndex, + }); + } + }); + text.push('\n'); + } else if (node.type === 'codeBlock') { + if (!node.content || !node.content[0].text) { + return; + } + text.push('```\n'); + text.push(node.content[0].text); + text.push('\n```\n'); + } + }); + + return { + text: text.join(''), + mentions, + }; +} diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index d8f93b8bf8..a792af3104 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -1,6 +1,7 @@ import { JSONToInlines, REF_REGEX, + diaryMixedToJSON, extractContentTypesFromPost, } from '@tloncorp/shared'; import { @@ -10,6 +11,7 @@ import { import * as db from '@tloncorp/shared/dist/db'; import { Block, + Story, citeToPath, constructStory, pathToCite, @@ -31,7 +33,7 @@ import { MessageInputContainer, MessageInputProps, } from '../MessageInput/MessageInputBase'; -import { textAndMentionsToContent } from './helpers'; +import { contentToTextAndMentions, textAndMentionsToContent } from './helpers'; import { useMentions } from './useMentions'; export default function BareChatInput({ @@ -129,6 +131,9 @@ export default function BareChatInput({ setText(textWithoutRefs); handleMention(oldText, textWithoutRefs); + + const jsonContent = textAndMentionsToContent(textWithoutRefs, mentions); + storeDraft(jsonContent); }; const onMentionSelect = useCallback( @@ -148,71 +153,53 @@ export default function BareChatInput({ ); const renderTextWithMentions = useMemo(() => { - if (!text) { - return null; - } - - if (mentions.length === 0) { + if (!text || mentions.length === 0) { return null; } + const sortedMentions = [...mentions].sort((a, b) => a.start - b.start); const textParts: JSX.Element[] = []; - let lastIndex = 0; - - mentions - .sort((a, b) => a.start - b.start) - .forEach((mention, index) => { - if (mention.start > lastIndex) { - textParts.push( - - {text.slice(lastIndex, mention.start)} - - ); - } - textParts.push( - - {mention.display} - - ); - - lastIndex = mention.end; - }); - - if (lastIndex < text.length) { + // Handle text before first mention + if (sortedMentions[0].start > 0) { textParts.push( - - {text.slice(lastIndex)} + + {text.slice(0, sortedMentions[0].start)} ); } - return ( - - {textParts} - - ); - }, [mentions, text, initialHeight, maxInputHeight]); + // Handle mentions and text between them + sortedMentions.forEach((mention, index) => { + textParts.push( + + {mention.display} + + ); + + // Add text between this mention and the next one (or end of text) + const nextStart = sortedMentions[index + 1]?.start ?? text.length; + if (mention.end < nextStart) { + textParts.push( + + {text.slice(mention.end, nextStart)} + + ); + } + }); + + return textParts; + }, [mentions, text]); const sendMessage = useCallback( async (isEdit?: boolean) => { const jsonContent = textAndMentionsToContent(text, mentions); const inlines = JSONToInlines(jsonContent); const story = constructStory(inlines); - console.log('jsonContent', jsonContent); - console.log('inlines', inlines); const finalAttachments = await waitForAttachmentUploads(); @@ -380,14 +367,16 @@ export default function BareChatInput({ // Set initial content from draft or post that is being edited useEffect(() => { if (!hasSetInitialContent) { - // messageInputLogger.log('Setting initial content'); try { getDraft().then((draft) => { - if (!editingPost && draft) { + if (!editingPost && draft && draft.length > 0) { // We'll need to parse the draft content here // NOTE: drafts are currently stored as tiptap JSONContent setEditorIsEmpty(false); setHasSetInitialContent(true); + const { text, mentions } = contentToTextAndMentions(draft); + setText(text); + setMentions(mentions); } if (editingPost && editingPost.content) { @@ -427,8 +416,15 @@ export default function BareChatInput({ }); resetAttachments(attachments); - - // We'll need to parse the post content here + const jsonContent = diaryMixedToJSON( + story?.filter( + (c) => !('type' in c) && !('block' in c && 'image' in c.block) + ) as Story + ); + + const { text, mentions } = contentToTextAndMentions(jsonContent); + setText(text); + setMentions(mentions); setEditorIsEmpty(false); setHasSetInitialContent(true); } @@ -454,13 +450,16 @@ export default function BareChatInput({ editingPost, resetAttachments, addAttachment, + setMentions, ]); - // Store draft when text changes - useEffect(() => { - const jsonContent = textAndMentionsToContent(text, mentions); - storeDraft(jsonContent); - }, [text, mentions, storeDraft]); + const handleCancelEditing = useCallback(() => { + setEditingPost?.(undefined); + setHasSetInitialContent(false); + setText(''); + clearDraft(); + clearAttachments(); + }, [setEditingPost, clearDraft, clearAttachments]); return ( setEditingPost?.(undefined)} + cancelEditing={handleCancelEditing} onPressEdit={handleEdit} goBack={goBack} > @@ -509,12 +508,15 @@ export default function BareChatInput({ placeholder={placeholder} /> {mentions.length > 0 && ( - - {renderTextWithMentions} + + + {renderTextWithMentions} + )} From b1faf9f9e544e336ddb2182c62210da8a8b9006f Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 11:41:36 -0500 Subject: [PATCH 198/259] switch to bare chat input for replies --- packages/ui/src/components/PostScreenView.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index d6442dbfc0..19736cbcaa 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -11,13 +11,13 @@ import { Text, View, YStack } from 'tamagui'; import { NavigationProvider, useCurrentUserId } from '../contexts'; import { AttachmentProvider } from '../contexts/attachment'; import * as utils from '../utils'; +import BareChatInput from './BareChatInput'; import { BigInput } from './BigInput'; import { ChannelFooter } from './Channel/ChannelFooter'; import { ChannelHeader } from './Channel/ChannelHeader'; import { DetailView } from './DetailView'; import { GroupPreviewAction, GroupPreviewSheet } from './GroupPreviewSheet'; import KeyboardAvoidingView from './KeyboardAvoidingView'; -import { MessageInput } from './MessageInput'; import { TlonEditorBridge } from './MessageInput/toolbarActions.native'; export function PostScreenView({ @@ -209,7 +209,7 @@ export function PostScreenView({ ) : null} {negotiationMatch && channel && canWrite && ( - )} {!negotiationMatch && channel && canWrite && ( From 1fabc6c3fcd38f3fd2ea07b3ce61bb97043bdd0e Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 24 Oct 2024 12:32:21 -0500 Subject: [PATCH 199/259] more format parsing cleanup, add markdown formatting to restored drafts/edit content --- .../src/components/BareChatInput/helpers.ts | 79 +++++++++++++++++-- .../ui/src/components/BareChatInput/index.tsx | 27 +++++-- 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/helpers.ts b/packages/ui/src/components/BareChatInput/helpers.ts index 489c184bc1..cd4babc1bf 100644 --- a/packages/ui/src/components/BareChatInput/helpers.ts +++ b/packages/ui/src/components/BareChatInput/helpers.ts @@ -80,6 +80,7 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { let isBolding = false; let isItalicizing = false; let isCoding = false; + let isEndOfFormatting = false; line.split(' ').forEach((word) => { const marks = []; const mention = mentions.find((mention) => mention.display === word); @@ -128,6 +129,7 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { if (isCoding) { marks.push({ type: 'code' }); if (isCodeEnd(word)) { + isEndOfFormatting = true; isCoding = false; word = word.slice(0, -1); } @@ -137,7 +139,12 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { marks, }); - parsedContent.push(makeText(' ')); + if (isEndOfFormatting) { + parsedContent.push(makeText(' ')); + isEndOfFormatting = false; + return; + } + parsedContent.push({ ...makeText(' '), marks }); return; } @@ -156,6 +163,7 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { marks.push({ type: 'bold' }); if (isBoldEnd(word)) { isBolding = false; + isEndOfFormatting = true; word = word.slice(0, -2); } } @@ -164,6 +172,7 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { marks.push({ type: 'italics' }); if (isItalicEnd(word)) { isItalicizing = false; + isEndOfFormatting = true; word = word.slice(0, -1); } } @@ -173,11 +182,22 @@ const processLine = (line: string, mentions: Mention[]): JSONContent => { ...makeText(word), marks, }); + + if (isEndOfFormatting) { + parsedContent.push(makeText(' ')); + isEndOfFormatting = false; + return; + } + + parsedContent.push({ + ...makeText(' '), + marks, + }); + return; } else { parsedContent.push(makeText(word)); + parsedContent.push(makeText(' ')); } - - parsedContent.push(makeText(' ')); }); return makeParagraph(mergeTextNodes(parsedContent)); @@ -274,17 +294,67 @@ export function contentToTextAndMentions(jsonContent: JSONContent): { }; } + let paragrahCount = 0; content.forEach((node) => { if (node.type === 'paragraph') { + if (paragrahCount > 0) { + text.push('\n'); + } + paragrahCount++; if (!node.content) { return; } + + let isBolding = false; + let isItalicizing = false; + let isCoding = false; + let lastMarks: string[] = []; node.content.forEach((child) => { if (child.type === 'text') { if (!child.text) { return; } - text.push(child.text); + if (child.marks) { + child.marks.forEach((mark) => { + if (mark.type === 'bold') { + isBolding = true; + } else if (mark.type === 'italics') { + isItalicizing = true; + } else if (mark.type === 'code') { + isCoding = true; + } + }); + + if (isBolding && !lastMarks.includes('bold')) { + text.push('**'); + } + + if (isItalicizing && !lastMarks.includes('italics')) { + text.push('*'); + } + + if (isCoding && !lastMarks.includes('code')) { + text.push('`'); + } + + text.push(child.text); + + if (isBolding && !lastMarks.includes('bold')) { + text.push('**'); + } + + if (isItalicizing && !lastMarks.includes('italics')) { + text.push('*'); + } + + if (isCoding && !lastMarks.includes('code')) { + text.push('`'); + } + + lastMarks = child.marks.map((mark) => mark.type); + } else { + text.push(child.text); + } } else if (child.type === 'mention') { if (!child.attrs || !child.attrs.id) { return; @@ -303,7 +373,6 @@ export function contentToTextAndMentions(jsonContent: JSONContent): { }); } }); - text.push('\n'); } else if (node.type === 'codeBlock') { if (!node.content || !node.content[0].text) { return; diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index a792af3104..4c5581489c 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -1,6 +1,7 @@ import { JSONToInlines, REF_REGEX, + createDevLogger, diaryMixedToJSON, extractContentTypesFromPost, } from '@tloncorp/shared'; @@ -36,6 +37,8 @@ import { import { contentToTextAndMentions, textAndMentionsToContent } from './helpers'; import { useMentions } from './useMentions'; +const bareChatInputLogger = createDevLogger('bareChatInput', false); + export default function BareChatInput({ shouldBlur, setShouldBlur, @@ -133,6 +136,7 @@ export default function BareChatInput({ handleMention(oldText, textWithoutRefs); const jsonContent = textAndMentionsToContent(textWithoutRefs, mentions); + bareChatInputLogger.log('setting draft', jsonContent); storeDraft(jsonContent); }; @@ -309,7 +313,7 @@ export default function BareChatInput({ try { await sendMessage(isEdit); } catch (e) { - console.error('failed to send', e); + bareChatInputLogger.trackError('failed to send', e); setSendError(true); } setIsSending(false); @@ -367,14 +371,25 @@ export default function BareChatInput({ // Set initial content from draft or post that is being edited useEffect(() => { if (!hasSetInitialContent) { + bareChatInputLogger.log('setting initial content'); try { getDraft().then((draft) => { - if (!editingPost && draft && draft.length > 0) { - // We'll need to parse the draft content here - // NOTE: drafts are currently stored as tiptap JSONContent + bareChatInputLogger.log('got draft', draft); + if ( + !editingPost && + draft && + draft.content && + draft.content.length > 0 + ) { setEditorIsEmpty(false); setHasSetInitialContent(true); + bareChatInputLogger.log('setting initial content', draft); const { text, mentions } = contentToTextAndMentions(draft); + bareChatInputLogger.log( + 'setting initial content text and mentions', + text, + mentions + ); setText(text); setMentions(mentions); } @@ -422,7 +437,9 @@ export default function BareChatInput({ ) as Story ); + bareChatInputLogger.log('jsonContent', jsonContent); const { text, mentions } = contentToTextAndMentions(jsonContent); + bareChatInputLogger.log('setting initial content', text, mentions); setText(text); setMentions(mentions); setEditorIsEmpty(false); @@ -441,7 +458,7 @@ export default function BareChatInput({ } }); } catch (e) { - console.error('Error setting initial content', e); + bareChatInputLogger.error('Error setting initial content', e); } } }, [ From 8ed4e582a090a26d692603e2b399a26376988de1 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Thu, 24 Oct 2024 14:23:06 -0400 Subject: [PATCH 200/259] fire invite link added event even if they get it on the welcome screen --- .../src/screens/Onboarding/WelcomeScreen.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx index aba76d3063..349df0d7b9 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx @@ -1,5 +1,6 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; +import { trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { setDidShowBenefitsSheet } from '@tloncorp/shared/dist/db'; import { useDidShowBenefitsSheet } from '@tloncorp/shared/dist/store'; import { @@ -15,7 +16,7 @@ import { YStack, } from '@tloncorp/ui'; import { OnboardingBenefitsSheet } from '@tloncorp/ui/src/components/Onboarding/OnboardingBenefitsSheet'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { Pressable } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -47,6 +48,15 @@ export const WelcomeScreen = ({ navigation }: Props) => { navigation.navigate('SignUpEmail'); }, [navigation]); + useEffect(() => { + if (lureMeta) { + trackOnboardingAction({ + actionName: 'Invite Link Added', + lure: lureMeta.id, + }); + } + }, [lureMeta]); + return ( From 2d126ac6f077313c39fc332f54132570ba1a6cc7 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 24 Oct 2024 14:59:44 -0400 Subject: [PATCH 201/259] onboarding: add show/hide to password fields --- .../Onboarding/SignUpPasswordScreen.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx index f48cbf9c95..1ea91e4869 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/SignUpPasswordScreen.tsx @@ -4,7 +4,6 @@ import { RECAPTCHA_SITE_KEY, } from '@tloncorp/app/constants'; import { useSignupParams } from '@tloncorp/app/contexts/branch'; -import { useSignupContext } from '.././../lib/signupContext'; import { setEulaAgreed } from '@tloncorp/app/utils/eula'; import { trackOnboardingAction } from '@tloncorp/app/utils/posthog'; import { createDevLogger } from '@tloncorp/shared'; @@ -15,7 +14,7 @@ import { ListItem, Modal, ScreenHeader, - TextInput, + TextInputWithButton, TlonText, View, YStack, @@ -27,6 +26,7 @@ import { getTokenValue } from 'tamagui'; import { useOnboardingContext } from '../../lib/OnboardingContext'; import type { OnboardingStackParamList } from '../../types'; +import { useSignupContext } from '.././../lib/signupContext'; type Props = NativeStackScreenProps; @@ -68,6 +68,9 @@ export const SignUpPasswordScreen = ({ }); const { height } = useWindowDimensions(); + const [passwordVisible, setPasswordVisible] = useState(false); + const [confirmPasswordVisible, setConfirmPasswordVisible] = useState(false); + const handlePressEula = useCallback(() => { navigation.navigate('EULA'); }, [navigation]); @@ -235,17 +238,19 @@ export const SignUpPasswordScreen = ({ error={errors.password?.message} paddingTop="$m" > - setFocus('confirmPassword')} value={value} - secureTextEntry + secureTextEntry={!passwordVisible} autoCapitalize="none" autoCorrect={false} returnKeyType="next" enablesReturnKeyAutomatically + buttonText={passwordVisible ? 'Hide' : 'Show'} + onButtonPress={() => setPasswordVisible(!passwordVisible)} /> )} @@ -264,18 +269,22 @@ export const SignUpPasswordScreen = ({ label="Confirm Password" error={errors.confirmPassword?.message} > - + setConfirmPasswordVisible(!confirmPasswordVisible) + } /> )} From 12dee68cedc3fa5b4355aa6ce42a76a38c393d0d Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 24 Oct 2024 16:16:09 -0400 Subject: [PATCH 202/259] fixtures: wrap onboarding screens in , add fixture options to wrappers --- .../src/fixtures/FixtureWrapper.tsx | 8 +- .../src/fixtures/Onboarding.fixture.tsx | 102 ++++++++++-------- 2 files changed, 62 insertions(+), 48 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx b/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx index 923b6a86b8..87d5d70bc2 100644 --- a/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx +++ b/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx @@ -3,6 +3,7 @@ import { QueryClientProvider, queryClient } from '@tloncorp/shared/dist'; import type { ColorProp } from '@tloncorp/ui'; import { Theme, View } from '@tloncorp/ui'; import type { PropsWithChildren } from 'react'; +import { useFixtureSelect } from 'react-cosmos/client'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -14,7 +15,6 @@ export const FixtureWrapper = ({ children, backgroundColor, innerBackgroundColor, - theme = 'light', safeArea, }: PropsWithChildren<{ fillWidth?: boolean; @@ -23,10 +23,14 @@ export const FixtureWrapper = ({ horizontalAlign?: 'left' | 'center' | 'right'; backgroundColor?: ColorProp; innerBackgroundColor?: ColorProp; - theme?: 'light' | 'dark'; safeArea?: boolean; }>) => { const insets = useSafeAreaInsets(); + + const [theme] = useFixtureSelect('themeName', { + options: ['light', 'dark'], + }); + return ( diff --git a/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx b/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx index 02922c502f..dce5585792 100644 --- a/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx @@ -8,7 +8,9 @@ import { QueryClientProvider, queryClient, } from '@tloncorp/shared/dist'; +import { Theme } from '@tloncorp/ui'; import { PropsWithChildren, useState } from 'react'; +import { useFixtureSelect } from 'react-cosmos/client'; import { OnboardingStack, OnboardingStackNavigator } from '../OnboardingStack'; import { OnboardingProvider } from '../lib/OnboardingContext'; @@ -59,57 +61,65 @@ function OnboardingFixture({ } : undefined ); + + const [theme] = useFixtureSelect('themeName', { + options: ['light', 'dark'], + }); + return ( - Promise.resolve('abc'), - execRecaptchaLogin: () => Promise.resolve('abc'), - getLandscapeAuthCookie: () => Promise.resolve('abc'), - //@ts-expect-error partial implementation - hostingApi: { - signUpHostingUser: async () => Promise.resolve({}), - logInHostingUser: () => Promise.resolve(sampleUser), - getHostingAvailability: async () => - Promise.resolve({ enabled: true, validEmail: true }), - getHostingUser: async () => Promise.resolve(sampleUser as User), - getReservableShips: async () => - Promise.resolve([ - { id: '~solfer-magfed', readyForDistribution: true }, - ]), - getShipAccessCode: async () => Promise.resolve({ code: 'xyz' }), - allocateReservedShip: async () => Promise.resolve({}), - getShipsWithStatus: async () => - Promise.resolve({ - shipId: '~solfer-magfed', - status: 'Ready', - }), - reserveShip: async () => - Promise.resolve({ - id: '~solfer-magfed', - reservedBy: '1', - }), - checkPhoneVerify: async () => Promise.resolve({ verified: true }), - verifyEmailDigits: async () => Promise.resolve({ verified: true }), - requestPhoneVerify: async () => Promise.resolve({}), - }, - }} - > - + void, - clearLure: () => setLure(undefined), - clearDeepLink: () => {}, - deepLinkPath: undefined, - priorityToken: undefined, + initRecaptcha: () => Promise.resolve('abc'), + execRecaptchaLogin: () => Promise.resolve('abc'), + getLandscapeAuthCookie: () => Promise.resolve('abc'), + //@ts-expect-error partial implementation + hostingApi: { + signUpHostingUser: async () => Promise.resolve({}), + logInHostingUser: () => Promise.resolve(sampleUser), + getHostingAvailability: async () => + Promise.resolve({ enabled: true, validEmail: true }), + getHostingUser: async () => Promise.resolve(sampleUser as User), + getReservableShips: async () => + Promise.resolve([ + { id: '~solfer-magfed', readyForDistribution: true }, + ]), + getShipAccessCode: async () => Promise.resolve({ code: 'xyz' }), + allocateReservedShip: async () => Promise.resolve({}), + getShipsWithStatus: async () => + Promise.resolve({ + shipId: '~solfer-magfed', + status: 'Ready', + }), + reserveShip: async () => + Promise.resolve({ + id: '~solfer-magfed', + reservedBy: '1', + }), + checkPhoneVerify: async () => Promise.resolve({ verified: true }), + verifyEmailDigits: async () => + Promise.resolve({ verified: true }), + requestPhoneVerify: async () => Promise.resolve({}), + }, }} > - - {children ?? } - - - + void, + clearLure: () => setLure(undefined), + clearDeepLink: () => {}, + deepLinkPath: undefined, + priorityToken: undefined, + }} + > + + {children ?? } + + + + ); } From cdf44dad78c90ea750e39bfb8af82705180ebef9 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 24 Oct 2024 16:16:31 -0400 Subject: [PATCH 203/259] assets: add fill="currentColor" to arvos_discussing --- packages/ui/src/assets/arvos_discussing.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/assets/arvos_discussing.svg b/packages/ui/src/assets/arvos_discussing.svg index 51621d4a80..0e2663a97b 100644 --- a/packages/ui/src/assets/arvos_discussing.svg +++ b/packages/ui/src/assets/arvos_discussing.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From a44c5447c7b068578a75e9b553ffc7141b0ff6e9 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 24 Oct 2024 16:56:25 -0400 Subject: [PATCH 204/259] login: show tlon password, +code --- .../src/screens/Onboarding/ShipLoginScreen.tsx | 9 +++++++-- .../src/screens/Onboarding/TlonLoginScreen.tsx | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx index 817a4b6a02..e0a7694687 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx @@ -17,6 +17,7 @@ import { OnboardingTextBlock, ScreenHeader, TextInput, + TextInputWithButton, TlonText, View, YStack, @@ -58,6 +59,8 @@ export const ShipLoginScreen = ({ navigation }: Props) => { }); const { setShip } = useShip(); + const [codevisible, setCodeVisible] = useState(false); + const isValidUrl = useCallback((url: string) => { const urlPattern = /^(https?:\/\/)?(localhost|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|[\w.-]+\.([a-z]{2,}))(:\d+)?$/i; @@ -199,7 +202,7 @@ export const ShipLoginScreen = ({ navigation }: Props) => { }} render={({ field: { onChange, onBlur, value } }) => ( - { @@ -209,11 +212,13 @@ export const ShipLoginScreen = ({ navigation }: Props) => { onChangeText={onChange} onSubmitEditing={onSubmit} value={value} - secureTextEntry + secureTextEntry={!codevisible} autoCapitalize="none" autoCorrect={false} returnKeyType="send" enablesReturnKeyAutomatically + buttonText={codevisible ? 'Hide' : 'Show'} + onButtonPress={() => setCodeVisible(!codevisible)} /> )} diff --git a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx index 0c2cb7da56..671642f81d 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx @@ -22,6 +22,7 @@ import { OnboardingTextBlock, ScreenHeader, TextInput, + TextInputWithButton, TlonText, View, YStack, @@ -63,6 +64,8 @@ export const TlonLoginScreen = ({ navigation }: Props) => { }); const { setShip } = useShip(); + const [passwordVisible, setPasswordVisible] = useState(false); + const handleForgotPassword = () => { const { email } = getValues(); navigation.navigate('ResetPassword', { email }); @@ -227,7 +230,7 @@ export const TlonLoginScreen = ({ navigation }: Props) => { }} render={({ field: { onChange, onBlur, value } }) => ( - { onBlur(); @@ -236,11 +239,13 @@ export const TlonLoginScreen = ({ navigation }: Props) => { onChangeText={onChange} onSubmitEditing={onSubmit} value={value} - secureTextEntry + secureTextEntry={!passwordVisible} autoCapitalize="none" autoCorrect={false} returnKeyType="send" enablesReturnKeyAutomatically + buttonText={passwordVisible ? 'Hide' : 'Show'} + onButtonPress={() => setPasswordVisible(!passwordVisible)} /> )} From 4261779dc8a4b03b40c8e0af29367358118cd2a5 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 24 Oct 2024 17:00:13 -0400 Subject: [PATCH 205/259] fixtures: fix tsc error --- apps/tlon-mobile/src/fixtures/Channel.fixture.tsx | 3 +-- apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx index 9e3dae72a4..906427b6d0 100644 --- a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx @@ -71,11 +71,10 @@ const fakeLoadingMostRecentFile: Upload = { const ChannelFixtureWrapper = ({ children, - theme, }: PropsWithChildren<{ theme?: 'light' | 'dark' }>) => { return ( - + {children} diff --git a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx index 627970be00..dac91e9227 100644 --- a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx @@ -55,7 +55,7 @@ export default { ), dark: ( - + From ae4258536e260e7bd306ea08a4a3937dda0f58af Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 25 Oct 2024 10:16:50 -0500 Subject: [PATCH 206/259] Use tlontext, fix darkmode color issue, tweak padding/lineheight/letterspacing --- .../ui/src/components/BareChatInput/index.tsx | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 4c5581489c..e716dba9ab 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -20,9 +20,17 @@ import { import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Keyboard, TextInput } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; -import { getFontSize } from 'tamagui'; -import { Text, View, YStack, getToken, useWindowDimensions } from 'tamagui'; - +import { + View, + YStack, + getFontSize, + getToken, + getVariableValue, + useTheme, + useWindowDimensions, +} from 'tamagui'; + +import { TlonText } from '../..'; import { Attachment, UploadedImageAttachment, @@ -167,31 +175,31 @@ export default function BareChatInput({ // Handle text before first mention if (sortedMentions[0].start > 0) { textParts.push( - + {text.slice(0, sortedMentions[0].start)} - + ); } // Handle mentions and text between them sortedMentions.forEach((mention, index) => { textParts.push( - {mention.display} - + ); // Add text between this mention and the next one (or end of text) const nextStart = sortedMentions[index + 1]?.start ?? text.length; if (mention.end < nextStart) { textParts.push( - + {text.slice(mention.end, nextStart)} - + ); } }); @@ -517,23 +525,28 @@ export default function BareChatInput({ minHeight: initialHeight, maxHeight: maxInputHeight - getToken('$s', 'size'), paddingHorizontal: getToken('$l', 'space'), - paddingVertical: getToken('$s', 'space'), + paddingTop: getToken('$m', 'space') + 2, + paddingBottom: getToken('$s', 'space'), fontSize: getFontSize('$m'), textAlignVertical: 'center', lineHeight: getFontSize('$m') * 1.5, + letterSpacing: -0.032, + color: getVariableValue(useTheme().primaryText), }} placeholder={placeholder} /> {mentions.length > 0 && ( - {renderTextWithMentions} - + )} From f7832ae5791697133f66a1e2a97832742a15e02e Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 25 Oct 2024 10:19:40 -0500 Subject: [PATCH 207/259] remove commented out import --- packages/ui/src/components/draftInputs/ChatInput.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ui/src/components/draftInputs/ChatInput.tsx b/packages/ui/src/components/draftInputs/ChatInput.tsx index 2aaf739cb8..9f3f14cd55 100644 --- a/packages/ui/src/components/draftInputs/ChatInput.tsx +++ b/packages/ui/src/components/draftInputs/ChatInput.tsx @@ -1,7 +1,6 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import BareChatInput from '../BareChatInput'; -// import { MessageInput } from '../MessageInput'; import { ParentAgnosticKeyboardAvoidingView } from '../ParentAgnosticKeyboardAvoidingView'; import { DraftInputContext } from './shared'; From 12b887fb33fdee07c5ff251f643ed214f2b129e1 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 25 Oct 2024 11:51:29 -0500 Subject: [PATCH 208/259] add OS specific padding adjustments for better alignment on both platforms --- packages/ui/src/components/BareChatInput/index.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index e716dba9ab..f0d0dc0a40 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -18,7 +18,7 @@ import { pathToCite, } from '@tloncorp/shared/dist/urbit'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { Keyboard, TextInput } from 'react-native'; +import { Keyboard, Platform, TextInput } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { View, @@ -486,6 +486,9 @@ export default function BareChatInput({ clearAttachments(); }, [setEditingPost, clearDraft, clearAttachments]); + const paddingTopAdjustment = Platform.OS === 'ios' ? 2 : 4; + const mentionLineHeightAdjustment = Platform.OS === 'ios' ? 1.3 : 1.5; + return ( From fde03acc114f7a1b9a435752d8bd7f095d082152 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Fri, 25 Oct 2024 11:57:10 -0500 Subject: [PATCH 209/259] fix dependency cycle issue --- .../ui/src/components/BareChatInput/index.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index f0d0dc0a40..abd4520ce8 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -30,7 +30,6 @@ import { useWindowDimensions, } from 'tamagui'; -import { TlonText } from '../..'; import { Attachment, UploadedImageAttachment, @@ -42,6 +41,7 @@ import { MessageInputContainer, MessageInputProps, } from '../MessageInput/MessageInputBase'; +import { RawText, Text } from '../TextV2/Text'; import { contentToTextAndMentions, textAndMentionsToContent } from './helpers'; import { useMentions } from './useMentions'; @@ -175,31 +175,31 @@ export default function BareChatInput({ // Handle text before first mention if (sortedMentions[0].start > 0) { textParts.push( - + {text.slice(0, sortedMentions[0].start)} - + ); } // Handle mentions and text between them sortedMentions.forEach((mention, index) => { textParts.push( - {mention.display} - + ); // Add text between this mention and the next one (or end of text) const nextStart = sortedMentions[index + 1]?.start ?? text.length; if (mention.end < nextStart) { textParts.push( - + {text.slice(mention.end, nextStart)} - + ); } }); @@ -540,7 +540,7 @@ export default function BareChatInput({ /> {mentions.length > 0 && ( - {renderTextWithMentions} - + )} From 2a87f945cf0f57951a79581ab5d54f13c3c75f2c Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Fri, 25 Oct 2024 12:00:28 -0500 Subject: [PATCH 210/259] groups-ui: run preload contacts --- desk/app/groups-ui.hoon | 50 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/desk/app/groups-ui.hoon b/desk/app/groups-ui.hoon index 3fe638d04d..e6d36188c9 100644 --- a/desk/app/groups-ui.hoon +++ b/desk/app/groups-ui.hoon @@ -7,7 +7,7 @@ |% +$ card card:agent:gall +$ current-state - $: %1 + $: %2 pins=(list whom:u) first-load=? == @@ -88,13 +88,23 @@ =+ !<(old=versioned-state vase) =? old ?=(~ old) *current-state =? old ?=(%0 -.old) (state-0-to-1 old) - ?> ?=(%1 -.old) + =? cor ?=(%1 -.old) + (emit %pass /preload-contacts %agent [our dap]:bowl %poke noun+!>(%preload-contacts)) + =? old ?=(%1 -.old) (state-1-to-2 old) + ?> ?=(%2 -.old) =. state old init :: - +$ versioned-state $@(~ $%(state-1 state-0)) - +$ state-1 current-state + +$ versioned-state $@(~ $%(state-2 state-1 state-0)) + +$ state-2 current-state + +$ state-1 + $: %1 + pins=(list whom:u) + first-load=? + == :: + ++ state-1-to-2 + |=(state-1 [%2 pins first-load]) +$ state-0 [%0 first-load=?] ++ state-0-to-1 |=(state-0 [%1 ~ first-load]) @@ -199,6 +209,11 @@ ^+ cor ?+ mark ~|(bad-mark/mark !!) %ui-vita (emit (active:vita-client bowl)) + :: + %noun + ?+ q.vase ~|(bad-poke+mark !!) + %preload-contacts preload-contacts + == :: %ui-vita-toggle =+ !<(=vita-enabled:u vase) @@ -228,8 +243,9 @@ ^+ cor ?+ pole ~|(bad-agent-take/pole !!) ~ cor - [%set-activity ~] cor + [%contact ~] cor [%vita-toggle ~] cor + [%set-activity ~] cor == :: ++ arvo @@ -238,4 +254,28 @@ ?+ wire !! [%build ~] cor == +++ preload-contacts + =+ .^(chat-running=? (scry %gu %chat /$)) + =? cor chat-running + =+ .^ [dms=(map ship dm:c) *] + (scry %gx %chat /full/noun) + == + %- emil + %+ murn + ~(tap by dms) + |= [=ship =dm:c] + ?~ latest=(ram:on:writs:c wit.pact.dm) ~ + =/ count (wyt:on:writs:c wit.pact.dm) + =/ cutoff (sub now.bowl ~d30) + ?. &((gth count 10) (gth -.u.latest cutoff)) ~ + `[%pass /contact %agent [our.bowl %contacts] %poke contact-action-1+!>([%page ship ~])] + =+ .^(pals-running=? (scry %gu %pals /$)) + =? cor pals-running + =+ .^(targets=(set ship) (scry %gx %pals /targets/noun)) + %- emil + %+ turn + ~(tap in targets) + |= =ship + [%pass /contact %agent [our.bowl %contacts] %poke contact-action-1+!>([%page ship ~])] + cor -- From 140f5d1b364c663deebb06ff7d4a6a27b638e2da Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 25 Oct 2024 17:24:53 +0000 Subject: [PATCH 211/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index 4f45e6d959..c3b94f4bae 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v2.gkr79.a2mt0.igle8.qrl1s.4iqae.glob' 0v2.gkr79.a2mt0.igle8.qrl1s.4iqae] + glob-http+['https://bootstrap.urbit.org/glob-0v7.l7jnk.63qrr.ccg4p.ca9be.gs1ra.glob' 0v7.l7jnk.63qrr.ccg4p.ca9be.gs1ra] base+'groups' version+[6 4 2] website+'https://tlon.io' From 38877a8bdd1b575831c63ffb8fa25ec6e5b3fddc Mon Sep 17 00:00:00 2001 From: David Lee Date: Sat, 26 Oct 2024 20:01:24 -0700 Subject: [PATCH 212/259] Dismiss image viewer on swipe down --- .../src/components/ImageViewerScreenView.tsx | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/packages/ui/src/components/ImageViewerScreenView.tsx b/packages/ui/src/components/ImageViewerScreenView.tsx index 50be792606..d0270223d3 100644 --- a/packages/ui/src/components/ImageViewerScreenView.tsx +++ b/packages/ui/src/components/ImageViewerScreenView.tsx @@ -1,36 +1,41 @@ import { ImageZoom } from '@likashefqet/react-native-image-zoom'; import * as db from '@tloncorp/shared/dist/db'; -import { BlurView } from 'expo-blur'; import * as Haptics from 'expo-haptics'; -import { useRef, useState } from 'react'; +import { ElementRef, useRef, useState } from 'react'; import { Dimensions, TouchableOpacity } from 'react-native'; +import { + Directions, + Gesture, + GestureDetector, +} from 'react-native-gesture-handler'; +import { runOnJS } from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Stack, View, XStack, YStack, ZStack } from 'tamagui'; -import { Close } from '../assets/icons'; -import { Button } from './Button'; import { Icon } from './Icon'; -import { IconButton } from './IconButton'; - -interface ImageZoomRef { - reset: () => void; -} export function ImageViewerScreenView(props: { post?: db.Post | null; uri?: string; goBack: () => void; }) { - const zoomableRef = useRef(null); + const zoomableRef = useRef>(null); const [showOverlay, setShowOverlay] = useState(true); const [minPanPointers, setMinPanPointers] = useState(2); const { top } = useSafeAreaInsets(); + // We can't observe the zoom on `react-native-image-zoom`, so we have to + // track it manually. + // Call `setIsAtMinZoom` whenever you think user switches between zoomed all + // the way out / zoomed in by some amount. + const [isAtMinZoom, setIsAtMinZoom] = useState(true); + function onSingleTap() { setShowOverlay(!showOverlay); } function handlePinchEnd(event: { scale: number }) { + setIsAtMinZoom(event.scale <= 1); if (event.scale > 1) { setMinPanPointers(1); } else { @@ -45,12 +50,22 @@ export function ImageViewerScreenView(props: { } else { setMinPanPointers(2); zoomableRef.current?.reset(); + setIsAtMinZoom(true); Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); } } + const dismissGesture = Gesture.Fling() + .enabled(isAtMinZoom) + .direction(Directions.DOWN) + .onEnd((_event, success) => { + if (success) { + runOnJS(props.goBack)(); + } + }); + return ( - <> + ) : null} - + ); } From 71f1d1c769964e356f5cf4f939e1af4da7cba1d9 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 27 Oct 2024 11:36:32 -0700 Subject: [PATCH 213/259] Enable imports from @tloncorp/shared/{subpackage} --- packages/shared/package.json | 9 +++++++++ packages/ui/package.json | 1 + packages/ui/tsconfig.json | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/shared/package.json b/packages/shared/package.json index 18c4814f60..2af676ad16 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -4,6 +4,15 @@ "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", + "exports": { + ".": "./src/index.ts", + "./api": "./src/api/index.ts", + "./client": "./src/client/index.ts", + "./db": "./src/db/index.ts", + "./logic": "./src/logic/index.ts", + "./store": "./src/store/index.ts", + "./urbit": "./src/urbit/index.ts" + }, "scripts": { "build": "tsup", "preinstall": "rm -f ./tsconfig.tsbuildinfo", diff --git a/packages/ui/package.json b/packages/ui/package.json index 8330d1f820..96581a00e0 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,7 @@ { "name": "@tloncorp/ui", "version": "1.0.0", + "type": "module", "types": "./src", "main": "src/index.tsx", "module:jsx": "src", diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index fc89b66e0c..2d14224768 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -3,6 +3,6 @@ "include": ["./src"], "compilerOptions": { "composite": true, - "moduleResolution": "node" + "moduleResolution": "bundler" } } From fd4bdf2b4d6a4194a1ac18532b7f33dfa344fe5d Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 27 Oct 2024 11:45:13 -0700 Subject: [PATCH 214/259] Simple find-and-replace shared/dist -> shared --- apps/tlon-mobile/index.js | 2 +- apps/tlon-mobile/src/App.main.tsx | 7 ++----- .../ActionSheet/GroupPreviewSheet.fixture.tsx | 2 +- apps/tlon-mobile/src/fixtures/Activity.fixture.tsx | 2 +- .../src/fixtures/BlockSectionList.fixture.tsx | 2 +- apps/tlon-mobile/src/fixtures/Channel.fixture.tsx | 6 +++--- .../tlon-mobile/src/fixtures/ChatMessage.fixture.tsx | 2 +- .../fixtures/DetailView/detailViewFixtureBase.tsx | 2 +- apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx | 2 +- .../tlon-mobile/src/fixtures/GalleryPost.fixture.tsx | 2 +- apps/tlon-mobile/src/fixtures/GroupList.fixture.tsx | 2 +- .../src/fixtures/MessageActions.fixture.tsx | 2 +- apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx | 2 +- .../src/fixtures/PostReference.fixture.tsx | 2 +- .../src/fixtures/UserProfileScreen.fixture.tsx | 2 +- apps/tlon-mobile/src/fixtures/activityHelpers.tsx | 8 ++++---- apps/tlon-mobile/src/fixtures/contentHelpers.tsx | 6 +++--- apps/tlon-mobile/src/fixtures/fakeData.ts | 6 +++--- apps/tlon-mobile/src/hooks/analytics.ts | 2 +- apps/tlon-mobile/src/hooks/useDeepLinkListener.ts | 4 ++-- .../tlon-mobile/src/hooks/useNotificationListener.ts | 10 +++++----- .../src/hooks/useReviveSavedOnboarding.ts | 6 +++--- apps/tlon-mobile/src/lib/OnboardingContext.tsx | 2 +- apps/tlon-mobile/src/lib/lifecycleEvents.ts | 2 +- apps/tlon-mobile/src/lib/refreshHostingAuth.ts | 2 +- apps/tlon-mobile/src/lib/signupContext.tsx | 8 ++++---- .../src/screens/Onboarding/PasteInviteLinkScreen.tsx | 2 +- .../src/screens/Onboarding/ShipLoginScreen.tsx | 6 +++--- .../src/screens/Onboarding/TlonLoginScreen.tsx | 6 +++--- .../src/screens/Onboarding/WelcomeScreen.tsx | 4 ++-- apps/tlon-mobile/src/types.ts | 2 +- apps/tlon-web-new/src/app.tsx | 2 +- apps/tlon-web-new/src/logic/analytics.ts | 2 +- apps/tlon-web-new/src/logic/utils.ts | 8 ++++---- apps/tlon-web-new/src/mocks/chat.ts | 4 ++-- apps/tlon-web-new/src/mocks/groups.ts | 2 +- apps/tlon-web-new/src/mocks/handlers.ts | 4 ++-- apps/tlon-web-new/src/mocks/heaps.ts | 2 +- apps/tlon-web-new/src/state/settings.ts | 2 +- apps/tlon-web-new/src/window.ts | 2 +- apps/tlon-web-new/tsconfig.json | 1 - apps/tlon-web/src/channels/ChannelActions.tsx | 4 ++-- apps/tlon-web/src/channels/ChannelSortSelector.tsx | 2 +- apps/tlon-web/src/channels/ChannelTypeSelector.tsx | 2 +- apps/tlon-web/src/channels/ChannelViewSelector.tsx | 2 +- apps/tlon-web/src/channels/ChannelVolumeDialog.tsx | 2 +- apps/tlon-web/src/channels/DisplayDropdown.tsx | 2 +- apps/tlon-web/src/channels/EditChannelForm.tsx | 7 ++----- .../src/channels/NewChannel/NewChannelForm.tsx | 2 +- apps/tlon-web/src/channels/ThreadVolumeDialog.tsx | 2 +- apps/tlon-web/src/chat/ChatChannel.tsx | 2 +- apps/tlon-web/src/chat/ChatContent/ChatContent.tsx | 4 ++-- apps/tlon-web/src/chat/ChatInput/ChatInput.tsx | 6 +++--- apps/tlon-web/src/chat/ChatMessage/ChatMessage.tsx | 4 ++-- .../src/chat/ChatMessage/ChatMessageOptions.tsx | 2 +- .../src/chat/ChatMessage/DeletedChatMessage.tsx | 2 +- .../src/chat/ChatMessage/DeletedChatReply.tsx | 2 +- apps/tlon-web/src/chat/ChatNotice.tsx | 2 +- .../tlon-web/src/chat/ChatReactions/ChatReaction.tsx | 2 +- .../src/chat/ChatReactions/ChatReactions.tsx | 2 +- apps/tlon-web/src/chat/ChatScroller/ChatScroller.tsx | 6 +++--- apps/tlon-web/src/chat/ChatSearch/ChatSearch.tsx | 2 +- .../src/chat/ChatSearch/ChatSearchResult.tsx | 4 ++-- .../src/chat/ChatSearch/ChatSearchResults.tsx | 4 ++-- .../src/chat/ChatSearch/useChatSearchInput.tsx | 2 +- apps/tlon-web/src/chat/ChatThread/ChatThread.tsx | 2 +- apps/tlon-web/src/chat/ChatWindow.tsx | 2 +- apps/tlon-web/src/chat/UnreadAlerts.tsx | 2 +- apps/tlon-web/src/chat/useChatStore.ts | 7 ++----- apps/tlon-web/src/components/About/AboutView.tsx | 2 +- apps/tlon-web/src/components/Avatar.tsx | 2 +- apps/tlon-web/src/components/ClubName.tsx | 2 +- apps/tlon-web/src/components/DevLog/DevLogView.tsx | 2 +- apps/tlon-web/src/components/Leap/useLeap.tsx | 6 +++--- apps/tlon-web/src/components/MessageEditor.tsx | 2 +- .../src/components/References/ContentReference.tsx | 2 +- .../src/components/References/CurioReference.tsx | 2 +- .../components/References/UnavailableReference.tsx | 2 +- .../src/components/References/WritBaseReference.tsx | 2 +- .../src/components/Settings/BlockedUsersView.tsx | 2 +- apps/tlon-web/src/components/Settings/Settings.tsx | 2 +- .../src/components/Settings/SettingsView.tsx | 2 +- apps/tlon-web/src/components/Sidebar/GroupList.tsx | 2 +- .../tlon-web/src/components/Sidebar/Sidebar.test.tsx | 2 +- .../src/components/Sidebar/useSearchFilter.ts | 2 +- apps/tlon-web/src/components/VolumeSetting.tsx | 2 +- apps/tlon-web/src/diary/DiaryChannel.tsx | 4 ++-- apps/tlon-web/src/diary/DiaryCommentField.tsx | 4 ++-- .../src/diary/DiaryContent/DiaryContent.test.tsx | 2 +- .../tlon-web/src/diary/DiaryContent/DiaryContent.tsx | 4 ++-- apps/tlon-web/src/diary/DiaryHeader.tsx | 2 +- apps/tlon-web/src/diary/DiaryList/DiaryGridItem.tsx | 2 +- apps/tlon-web/src/diary/DiaryList/DiaryGridView.tsx | 2 +- apps/tlon-web/src/diary/DiaryList/DiaryListItem.tsx | 2 +- apps/tlon-web/src/diary/DiaryMarkdownEditor.tsx | 2 +- apps/tlon-web/src/diary/DiaryNote.tsx | 2 +- apps/tlon-web/src/diary/DiaryNoteHeadline.tsx | 2 +- apps/tlon-web/src/diary/DiaryVerse.tsx | 2 +- .../src/diary/NoteReactions/NoteReactions.tsx | 2 +- apps/tlon-web/src/diary/diary-add-note.tsx | 4 ++-- apps/tlon-web/src/dms/BroadcastHero.tsx | 2 +- apps/tlon-web/src/dms/BroadcastWindow.tsx | 2 +- apps/tlon-web/src/dms/DMHero.tsx | 2 +- apps/tlon-web/src/dms/DMOptions.tsx | 2 +- apps/tlon-web/src/dms/DMThread.tsx | 4 ++-- apps/tlon-web/src/dms/Dm.tsx | 2 +- apps/tlon-web/src/dms/DmWindow.tsx | 2 +- apps/tlon-web/src/dms/MessagesList.tsx | 2 +- apps/tlon-web/src/dms/MultiDMInfoForm.tsx | 2 +- apps/tlon-web/src/dms/MultiDm.tsx | 2 +- apps/tlon-web/src/dms/MultiDmHero.tsx | 2 +- apps/tlon-web/src/groups/AddGroup/SearchResults.tsx | 2 +- .../src/groups/ChannelsList/ChannelJoinSelector.tsx | 2 +- .../src/groups/ChannelsList/ChannelPermsSelector.tsx | 2 +- .../src/groups/ChannelsList/ChannelsListItem.tsx | 2 +- .../src/groups/ChannelsList/DeleteChannelModal.tsx | 2 +- .../src/groups/ChannelsList/EditChannelModal.tsx | 2 +- .../src/groups/ChannelsList/GroupChannelManager.tsx | 2 +- .../src/groups/ChannelsList/SectionNameEditInput.tsx | 2 +- apps/tlon-web/src/groups/ChannelsList/types.ts | 2 +- apps/tlon-web/src/groups/FindGroups.tsx | 2 +- apps/tlon-web/src/groups/GangPreview/GangPreview.tsx | 2 +- apps/tlon-web/src/groups/GroupAdmin/GroupInfo.tsx | 2 +- .../src/groups/GroupAdmin/GroupInfoEditor.tsx | 2 +- .../src/groups/GroupAdmin/GroupInfoFields.tsx | 2 +- .../src/groups/GroupAdmin/GroupInvitesPrivacy.tsx | 2 +- .../src/groups/GroupAdmin/GroupMemberItem.tsx | 2 +- apps/tlon-web/src/groups/GroupAdmin/GroupMembers.tsx | 2 +- .../src/groups/GroupAdmin/PrivacySelector.tsx | 2 +- apps/tlon-web/src/groups/GroupJoinList.tsx | 2 +- .../src/groups/GroupSidebar/ChannelList.test.tsx | 2 +- .../tlon-web/src/groups/GroupSidebar/ChannelList.tsx | 2 +- apps/tlon-web/src/groups/GroupSummary.tsx | 2 +- apps/tlon-web/src/groups/GroupVolumeDialog.tsx | 2 +- apps/tlon-web/src/groups/LureAutojoiner.tsx | 2 +- apps/tlon-web/src/groups/LureInviteBlock.tsx | 2 +- apps/tlon-web/src/groups/NewGroup/NewGroup.tsx | 2 +- apps/tlon-web/src/groups/NewGroup/NewGroupInvite.tsx | 2 +- apps/tlon-web/src/groups/RoleInput/RoleSelector.tsx | 2 +- apps/tlon-web/src/groups/useGroupJoin.ts | 2 +- apps/tlon-web/src/heap/EditCurioForm.tsx | 4 ++-- apps/tlon-web/src/heap/HeapBlock.tsx | 2 +- apps/tlon-web/src/heap/HeapChannel.tsx | 4 ++-- apps/tlon-web/src/heap/HeapContent.tsx | 8 ++------ apps/tlon-web/src/heap/HeapDetail.tsx | 4 ++-- apps/tlon-web/src/heap/HeapDetail/HeapDetailBody.tsx | 2 +- .../src/heap/HeapDetail/HeapDetailHeader.tsx | 7 ++----- .../HeapDetailSidebar/HeapDetailComments.tsx | 4 ++-- .../HeapDetailSidebar/HeapDetailSidebarInfo.tsx | 2 +- apps/tlon-web/src/heap/HeapHeader.tsx | 2 +- apps/tlon-web/src/heap/HeapRow.tsx | 2 +- apps/tlon-web/src/heap/HeapTextInput.tsx | 4 ++-- apps/tlon-web/src/logic/analytics.ts | 2 +- apps/tlon-web/src/logic/channel.ts | 12 ++++-------- apps/tlon-web/src/logic/getKindData.ts | 2 +- apps/tlon-web/src/logic/heap.ts | 9 +++------ apps/tlon-web/src/logic/messageSender.ts | 2 +- apps/tlon-web/src/logic/tiptap.test.ts | 4 ++-- apps/tlon-web/src/logic/tiptap.ts | 4 ++-- apps/tlon-web/src/logic/useGroupSort.ts | 2 +- apps/tlon-web/src/logic/useIsGroupUnread.ts | 2 +- apps/tlon-web/src/logic/useMessageSort.ts | 2 +- apps/tlon-web/src/logic/useScrollerMessages.ts | 6 +++--- apps/tlon-web/src/logic/useStickyUnread.ts | 2 +- apps/tlon-web/src/logic/utils.ts | 8 ++++---- apps/tlon-web/src/mocks/chat.ts | 4 ++-- apps/tlon-web/src/mocks/groups.ts | 2 +- apps/tlon-web/src/mocks/handlers.ts | 4 ++-- apps/tlon-web/src/mocks/heaps.ts | 2 +- apps/tlon-web/src/notifications/ActivitySummary.tsx | 2 +- apps/tlon-web/src/notifications/DMNotification.tsx | 4 ++-- .../tlon-web/src/notifications/GroupNotification.tsx | 4 ++-- apps/tlon-web/src/notifications/Notification.tsx | 2 +- apps/tlon-web/src/notifications/Notifications.tsx | 4 ++-- .../src/profiles/EditProfile/EditProfile.tsx | 4 ++-- apps/tlon-web/src/profiles/Profile.tsx | 2 +- apps/tlon-web/src/profiles/ShareDMLure.tsx | 2 +- apps/tlon-web/src/replies/ReplyMessage.tsx | 6 +++--- apps/tlon-web/src/replies/ReplyMessageOptions.tsx | 2 +- .../src/replies/ReplyReactions/ReplyReactions.tsx | 2 +- apps/tlon-web/src/replies/replies.ts | 7 ++----- apps/tlon-web/src/state/activity.ts | 2 +- apps/tlon-web/src/state/bootstrap.ts | 2 +- apps/tlon-web/src/state/broadcasts.ts | 4 ++-- apps/tlon-web/src/state/channel/channel.ts | 6 +++--- apps/tlon-web/src/state/channel/util.ts | 2 +- apps/tlon-web/src/state/chat/chat.ts | 12 ++++-------- apps/tlon-web/src/state/chat/search.ts | 4 ++-- apps/tlon-web/src/state/chat/utils.ts | 4 ++-- apps/tlon-web/src/state/contact.ts | 2 +- apps/tlon-web/src/state/groups/groups.ts | 6 +++--- apps/tlon-web/src/state/groups/groupsReducer.ts | 2 +- apps/tlon-web/src/state/groups/type.ts | 6 +++--- apps/tlon-web/src/state/hark.ts | 2 +- apps/tlon-web/src/state/lure/lure.ts | 4 ++-- apps/tlon-web/src/state/negotiation.ts | 2 +- apps/tlon-web/src/state/pins.ts | 2 +- apps/tlon-web/src/state/settings.ts | 2 +- apps/tlon-web/src/window.ts | 2 +- apps/tlon-web/tsconfig.json | 2 +- packages/app/contexts/branch.tsx | 4 ++-- .../app/features/channels/ChannelMembersScreen.tsx | 2 +- packages/app/features/channels/ChannelMetaScreen.tsx | 6 +++--- packages/app/features/groups/EditChannelScreen.tsx | 2 +- packages/app/features/groups/GroupMembersScreen.tsx | 2 +- packages/app/features/groups/GroupMetaScreen.tsx | 6 +++--- packages/app/features/groups/GroupPrivacyScreen.tsx | 4 ++-- packages/app/features/settings/AppInfoScreen.tsx | 4 ++-- .../app/features/settings/BlockedUsersScreen.tsx | 4 ++-- packages/app/features/settings/EditProfileScreen.tsx | 4 ++-- .../settings/PushNotificationSettingsScreen.tsx | 8 ++++---- packages/app/features/top/ActivityScreen.tsx | 6 +++--- packages/app/features/top/ChannelScreen.tsx | 10 +++++----- packages/app/features/top/ChannelSearchScreen.tsx | 4 ++-- packages/app/features/top/ChatListScreen.tsx | 8 ++++---- .../app/features/top/ContactHostedGroupsScreen.tsx | 2 +- packages/app/features/top/CreateGroupScreen.tsx | 2 +- packages/app/features/top/GroupChannelsScreen.tsx | 4 ++-- packages/app/features/top/PostScreen.tsx | 6 +++--- packages/app/features/top/UserProfileScreen.tsx | 4 ++-- packages/app/features/top/useConnectionStatus.tsx | 4 ++-- packages/app/hooks/useBootSequence.ts | 4 ++-- packages/app/hooks/useBranchLink.ts | 2 +- packages/app/hooks/useCalmSettings.ts | 2 +- packages/app/hooks/useChannelContext.ts | 8 ++++---- packages/app/hooks/useChannelNavigation.ts | 4 ++-- packages/app/hooks/useConfigureUrbitClient.ts | 6 +++--- packages/app/hooks/useCurrentUser.native.ts | 2 +- packages/app/hooks/useGroupActions.tsx | 2 +- packages/app/hooks/useGroupContext.ts | 4 ++-- packages/app/hooks/useGroupNavigation.ts | 2 +- packages/app/hooks/useHandleLogout.native.ts | 6 +++--- packages/app/hooks/useHandleLogout.ts | 6 +++--- packages/app/hooks/useNavigationLogger.ts | 2 +- packages/app/hooks/useNetworkLogger.ts | 2 +- packages/app/lib/betterSqlite3Connection.ts | 6 +++--- packages/app/lib/bootHelpers.ts | 4 ++-- packages/app/lib/devMenuItems.ts | 2 +- packages/app/lib/hostingApi.ts | 2 +- packages/app/lib/nativeDb.ts | 4 ++-- packages/app/lib/notificationsApi.ts | 2 +- packages/app/lib/opsqliteConnection.ts | 4 ++-- packages/app/lib/sqliteConnection.ts | 4 ++-- packages/app/lib/webDb.ts | 6 +++--- packages/app/lib/webMigrator.ts | 2 +- packages/app/navigation/types.ts | 2 +- packages/app/provider/AppDataProvider.tsx | 2 +- packages/app/utils/images.ts | 2 +- packages/app/utils/perf.tsx | 4 ++-- packages/app/utils/posthog.ts | 2 +- packages/editor/global.d.ts | 2 +- packages/shared/package.json | 1 + packages/shared/tsconfig.json | 1 - .../ui/src/components/Activity/ActivityHeader.tsx | 2 +- .../ui/src/components/Activity/ActivityListItem.tsx | 12 ++++++------ .../src/components/Activity/ActivityScreenView.tsx | 6 +++--- .../components/Activity/ActivitySourceContent.tsx | 4 ++-- .../components/Activity/ActivitySummaryMessage.tsx | 4 ++-- .../ui/src/components/AddChats/CreateGroupWidget.tsx | 6 +++--- .../src/components/AddChats/ViewUserGroupsWidget.tsx | 4 ++-- packages/ui/src/components/AttachmentSheet.tsx | 4 ++-- packages/ui/src/components/AuthorRow.tsx | 2 +- packages/ui/src/components/Avatar.tsx | 2 +- packages/ui/src/components/BareChatInput/helpers.ts | 2 +- packages/ui/src/components/BareChatInput/index.tsx | 6 +++--- .../ui/src/components/BareChatInput/useMentions.tsx | 2 +- packages/ui/src/components/BigInput.native.tsx | 2 +- packages/ui/src/components/BigInput.tsx | 2 +- packages/ui/src/components/BlockedContactsWidget.tsx | 2 +- packages/ui/src/components/Channel/BaubleHeader.tsx | 2 +- .../ui/src/components/Channel/ChannelDivider.tsx | 4 ++-- packages/ui/src/components/Channel/ChannelHeader.tsx | 2 +- .../ui/src/components/Channel/DmInviteOptions.tsx | 4 ++-- .../ui/src/components/Channel/EmptyChannelNotice.tsx | 2 +- packages/ui/src/components/Channel/Scroller.tsx | 6 +++--- packages/ui/src/components/Channel/index.tsx | 6 +++--- .../ui/src/components/ChannelMembersScreenView.tsx | 2 +- packages/ui/src/components/ChannelNavSection.tsx | 2 +- packages/ui/src/components/ChannelNavSections.tsx | 2 +- .../src/components/ChannelSearch/SearchResults.tsx | 2 +- .../ui/src/components/ChannelSearch/SearchStatus.tsx | 2 +- packages/ui/src/components/ChannelSwitcherSheet.tsx | 2 +- packages/ui/src/components/ChatList.tsx | 6 +++--- .../ui/src/components/ChatMessage/ChatMessage.tsx | 2 +- .../ChatMessageActions/Component.android.tsx | 2 +- .../ChatMessage/ChatMessageActions/Component.tsx | 2 +- .../ChatMessage/ChatMessageActions/EmojiToolbar.tsx | 4 ++-- .../ChatMessageActions/MessageActions.tsx | 6 +++--- .../ChatMessageActions/MessageContainer.tsx | 2 +- .../ChatMessage/ChatMessageDeliveryStatus.tsx | 2 +- .../ChatMessage/ChatMessageReplySummary.tsx | 4 ++-- .../src/components/ChatMessage/ReactionsDisplay.tsx | 4 ++-- .../src/components/ChatMessage/ViewReactionsPane.tsx | 2 +- .../components/ChatMessage/ViewReactionsSheet.tsx | 2 +- packages/ui/src/components/ChatOptionsSheet.tsx | 8 ++++---- packages/ui/src/components/ContactBook.tsx | 2 +- packages/ui/src/components/ContactRow.tsx | 2 +- .../components/ContentReference/ContentReference.tsx | 6 +++--- packages/ui/src/components/CreateGroupView.tsx | 2 +- packages/ui/src/components/DetailView.tsx | 4 ++-- packages/ui/src/components/EditProfileScreenView.tsx | 4 ++-- packages/ui/src/components/EditableProfileImages.tsx | 4 ++-- .../ui/src/components/Embed/AudioEmbed.native.tsx | 2 +- packages/ui/src/components/FavoriteGroupsDisplay.tsx | 2 +- .../ui/src/components/GalleryPost/GalleryPost.tsx | 2 +- .../ui/src/components/GroupChannelsScreenView.tsx | 2 +- packages/ui/src/components/GroupJoinRequestSheet.tsx | 2 +- .../ui/src/components/GroupMembersScreenView.tsx | 4 ++-- packages/ui/src/components/GroupPreviewSheet.tsx | 4 ++-- packages/ui/src/components/GroupPrivacySelector.tsx | 2 +- packages/ui/src/components/GroupSelectorSheet.tsx | 2 +- packages/ui/src/components/ImageViewerScreenView.tsx | 2 +- .../ui/src/components/InviteFriendsToTlonButton.tsx | 6 +++--- packages/ui/src/components/InviteUsersSheet.tsx | 2 +- packages/ui/src/components/InviteUsersWidget.tsx | 4 ++-- .../ui/src/components/ListItem/ChannelListItem.tsx | 4 ++-- packages/ui/src/components/ListItem/ChatListItem.tsx | 4 ++-- .../ui/src/components/ListItem/ContactListItem.tsx | 2 +- .../ui/src/components/ListItem/GroupListItem.tsx | 4 ++-- .../components/ListItem/InteractableChatListItem.tsx | 6 +++--- packages/ui/src/components/ListItem/ListItem.tsx | 2 +- .../ui/src/components/ListItem/listItemUtils.tsx | 2 +- .../components/ManageChannels/CreateChannelSheet.tsx | 2 +- .../ManageChannels/EditChannelScreenView.tsx | 2 +- .../ManageChannels/ManageChannelsScreenView.tsx | 2 +- packages/ui/src/components/MentionPopup.tsx | 4 ++-- .../components/MessageInput/InputMentionPopup.tsx | 2 +- .../src/components/MessageInput/MessageInputBase.tsx | 4 ++-- packages/ui/src/components/MessageInput/helpers.ts | 4 ++-- .../ui/src/components/MessageInput/index.native.tsx | 10 +++++----- packages/ui/src/components/MessageInput/index.tsx | 11 +++++------ packages/ui/src/components/MetaEditorScreenView.tsx | 4 ++-- packages/ui/src/components/NavBarView.tsx | 2 +- .../ui/src/components/NotebookPost/NotebookPost.tsx | 2 +- .../src/components/Onboarding/OnboardingInvite.tsx | 2 +- .../src/components/PostContent/ContentRenderer.tsx | 2 +- .../ui/src/components/PostContent/contentUtils.tsx | 6 +++--- packages/ui/src/components/PostScreenView.tsx | 8 ++++---- packages/ui/src/components/ProfileRow.tsx | 2 +- packages/ui/src/components/ProfileSheet.tsx | 9 +++------ packages/ui/src/components/SendPostRetrySheet.tsx | 2 +- packages/ui/src/components/UserProfileScreenView.tsx | 6 +++--- packages/ui/src/components/draftInputs/shared.ts | 4 ++-- packages/ui/src/contexts/appDataContext.tsx | 4 ++-- packages/ui/src/contexts/attachment.tsx | 4 ++-- packages/ui/src/contexts/channel.tsx | 2 +- packages/ui/src/contexts/chatOptions.tsx | 4 ++-- packages/ui/src/contexts/componentsKits.tsx | 4 ++-- packages/ui/src/contexts/groups.tsx | 2 +- packages/ui/src/contexts/navigation.tsx | 2 +- packages/ui/src/contexts/requests.tsx | 4 ++-- packages/ui/src/contexts/thread.tsx | 2 +- packages/ui/src/hooks/contactSorters.ts | 6 +++--- packages/ui/src/hooks/groupsSorters.ts | 4 ++-- packages/ui/src/utils/channelUtils.tsx | 4 ++-- packages/ui/src/utils/postUtils.tsx | 2 +- packages/ui/src/utils/user.ts | 4 ++-- packages/ui/tsconfig.json | 3 +-- tsconfig.json | 2 +- 359 files changed, 572 insertions(+), 608 deletions(-) diff --git a/apps/tlon-mobile/index.js b/apps/tlon-mobile/index.js index b49fc5ed68..f6405e93ad 100644 --- a/apps/tlon-mobile/index.js +++ b/apps/tlon-mobile/index.js @@ -6,7 +6,7 @@ import '@tloncorp/app/lib/devMenuItems'; import { setupDb } from '@tloncorp/app/lib/nativeDb'; import { addCustomEnabledLoggers } from '@tloncorp/shared'; import { useDebugStore } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { setStorage } from '@tloncorp/ui'; import { registerRootComponent } from 'expo'; import 'expo-dev-client'; diff --git a/apps/tlon-mobile/src/App.main.tsx b/apps/tlon-mobile/src/App.main.tsx index 19078488e6..cbca5f114c 100644 --- a/apps/tlon-mobile/src/App.main.tsx +++ b/apps/tlon-mobile/src/App.main.tsx @@ -13,17 +13,13 @@ import { import ErrorBoundary from '@tloncorp/app/ErrorBoundary'; import { BranchProvider } from '@tloncorp/app/contexts/branch'; import { ShipProvider, useShip } from '@tloncorp/app/contexts/ship'; -import { - SignupProvider, - useSignupContext, -} from './lib/signupContext'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; import { useMigrations } from '@tloncorp/app/lib/nativeDb'; import { PlatformState } from '@tloncorp/app/lib/platformHelpers'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { FeatureFlagConnectedInstrumentationProvider } from '@tloncorp/app/utils/perf'; import { posthogAsync } from '@tloncorp/app/utils/posthog'; -import { QueryClientProvider, queryClient } from '@tloncorp/shared/dist/api'; +import { QueryClientProvider, queryClient } from '@tloncorp/shared/api'; import { LoadingSpinner, PortalProvider, @@ -40,6 +36,7 @@ import { SafeAreaProvider } from 'react-native-safe-area-context'; import { OnboardingStack } from './OnboardingStack'; import AuthenticatedApp from './components/AuthenticatedApp'; +import { SignupProvider, useSignupContext } from './lib/signupContext'; // Android notification tap handler passes initial params here const App = () => { diff --git a/apps/tlon-mobile/src/fixtures/ActionSheet/GroupPreviewSheet.fixture.tsx b/apps/tlon-mobile/src/fixtures/ActionSheet/GroupPreviewSheet.fixture.tsx index 8abf398171..82d8f2b55d 100644 --- a/apps/tlon-mobile/src/fixtures/ActionSheet/GroupPreviewSheet.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/ActionSheet/GroupPreviewSheet.fixture.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { GroupPreviewSheet } from '@tloncorp/ui'; import { group } from '../fakeData'; diff --git a/apps/tlon-mobile/src/fixtures/Activity.fixture.tsx b/apps/tlon-mobile/src/fixtures/Activity.fixture.tsx index fb66135b3f..31577598d8 100644 --- a/apps/tlon-mobile/src/fixtures/Activity.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Activity.fixture.tsx @@ -1,4 +1,4 @@ -import * as logic from '@tloncorp/shared/dist/logic'; +import * as logic from '@tloncorp/shared/logic'; import { ActivityScreenContent, AppDataContextProvider, diff --git a/apps/tlon-mobile/src/fixtures/BlockSectionList.fixture.tsx b/apps/tlon-mobile/src/fixtures/BlockSectionList.fixture.tsx index 7cabfbc976..569932e8f9 100644 --- a/apps/tlon-mobile/src/fixtures/BlockSectionList.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/BlockSectionList.fixture.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { BlockSectionList, ContactRow } from '@tloncorp/ui'; import { SectionListRenderItemInfo } from 'react-native'; diff --git a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx index 906427b6d0..406ed3d3e4 100644 --- a/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Channel.fixture.tsx @@ -3,9 +3,9 @@ import { useChannel, useGroupPreview, usePostWithRelations, -} from '@tloncorp/shared/dist'; -import type { Upload } from '@tloncorp/shared/dist/api'; -import type * as db from '@tloncorp/shared/dist/db'; +} from '@tloncorp/shared'; +import type { Upload } from '@tloncorp/shared/api'; +import type * as db from '@tloncorp/shared/db'; import { AppDataContextProvider, Channel, diff --git a/apps/tlon-mobile/src/fixtures/ChatMessage.fixture.tsx b/apps/tlon-mobile/src/fixtures/ChatMessage.fixture.tsx index 4ed4398ee5..da5784eefa 100644 --- a/apps/tlon-mobile/src/fixtures/ChatMessage.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/ChatMessage.fixture.tsx @@ -1,5 +1,5 @@ // tamagui-ignore -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { AppDataContextProvider, ChannelDivider, diff --git a/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx b/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx index 77b9db7de4..3d5e20798d 100644 --- a/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx +++ b/apps/tlon-mobile/src/fixtures/DetailView/detailViewFixtureBase.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { AppDataContextProvider, RequestsProvider } from '@tloncorp/ui'; import { PostScreenView } from '@tloncorp/ui/src'; diff --git a/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx b/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx index 87d5d70bc2..c4a274de7f 100644 --- a/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx +++ b/apps/tlon-mobile/src/fixtures/FixtureWrapper.tsx @@ -1,5 +1,5 @@ // tamagui-ignore -import { QueryClientProvider, queryClient } from '@tloncorp/shared/dist'; +import { QueryClientProvider, queryClient } from '@tloncorp/shared'; import type { ColorProp } from '@tloncorp/ui'; import { Theme, View } from '@tloncorp/ui'; import type { PropsWithChildren } from 'react'; diff --git a/apps/tlon-mobile/src/fixtures/GalleryPost.fixture.tsx b/apps/tlon-mobile/src/fixtures/GalleryPost.fixture.tsx index 4c381a295b..7a81f19851 100644 --- a/apps/tlon-mobile/src/fixtures/GalleryPost.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/GalleryPost.fixture.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { AppDataContextProvider, GalleryPost, diff --git a/apps/tlon-mobile/src/fixtures/GroupList.fixture.tsx b/apps/tlon-mobile/src/fixtures/GroupList.fixture.tsx index c19c1f192a..215eef729f 100644 --- a/apps/tlon-mobile/src/fixtures/GroupList.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/GroupList.fixture.tsx @@ -1,4 +1,4 @@ -import type * as db from '@tloncorp/shared/dist/db'; +import type * as db from '@tloncorp/shared/db'; import { ChatList } from '@tloncorp/ui'; import { FixtureWrapper } from './FixtureWrapper'; diff --git a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx index dac91e9227..0dd33e00f6 100644 --- a/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/MessageActions.fixture.tsx @@ -1,5 +1,5 @@ import { ChannelAction } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ChatMessageActions, Modal, ZStack } from '@tloncorp/ui'; import { createRef, useEffect, useState } from 'react'; import { View } from 'react-native'; diff --git a/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx b/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx index dce5585792..fd9a2c3ec4 100644 --- a/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/Onboarding.fixture.tsx @@ -7,7 +7,7 @@ import { DeepLinkData, QueryClientProvider, queryClient, -} from '@tloncorp/shared/dist'; +} from '@tloncorp/shared'; import { Theme } from '@tloncorp/ui'; import { PropsWithChildren, useState } from 'react'; import { useFixtureSelect } from 'react-cosmos/client'; diff --git a/apps/tlon-mobile/src/fixtures/PostReference.fixture.tsx b/apps/tlon-mobile/src/fixtures/PostReference.fixture.tsx index 2eb5df7b55..52cc468dca 100644 --- a/apps/tlon-mobile/src/fixtures/PostReference.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/PostReference.fixture.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { View } from '@tloncorp/ui'; import { GroupReference, diff --git a/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx b/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx index 20c326668e..9262db5c10 100644 --- a/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx +++ b/apps/tlon-mobile/src/fixtures/UserProfileScreen.fixture.tsx @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { AppDataContextProvider, UserProfileScreenView, diff --git a/apps/tlon-mobile/src/fixtures/activityHelpers.tsx b/apps/tlon-mobile/src/fixtures/activityHelpers.tsx index 7d3cca2e35..a46b3e2ea5 100644 --- a/apps/tlon-mobile/src/fixtures/activityHelpers.tsx +++ b/apps/tlon-mobile/src/fixtures/activityHelpers.tsx @@ -1,7 +1,7 @@ -import { PostContent } from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import { ExtendedEventType } from '@tloncorp/shared/dist/urbit'; +import { PostContent } from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import { ExtendedEventType } from '@tloncorp/shared/urbit'; import { exampleContacts, postsByType } from './contentHelpers'; import { group as fakeGroup, tlonLocalIntros } from './fakeData'; diff --git a/apps/tlon-mobile/src/fixtures/contentHelpers.tsx b/apps/tlon-mobile/src/fixtures/contentHelpers.tsx index 4a658ba2e7..3e755d12ef 100644 --- a/apps/tlon-mobile/src/fixtures/contentHelpers.tsx +++ b/apps/tlon-mobile/src/fixtures/contentHelpers.tsx @@ -1,8 +1,8 @@ import { faker } from '@faker-js/faker'; import { useQuery } from '@tanstack/react-query'; -import type { ContentReference, PostContent } from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; -import * as ub from '@tloncorp/shared/dist/urbit'; +import type { ContentReference, PostContent } from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; +import * as ub from '@tloncorp/shared/urbit'; import { createFakePost, diff --git a/apps/tlon-mobile/src/fixtures/fakeData.ts b/apps/tlon-mobile/src/fixtures/fakeData.ts index 27c2967f98..ae87b64dd8 100644 --- a/apps/tlon-mobile/src/fixtures/fakeData.ts +++ b/apps/tlon-mobile/src/fixtures/fakeData.ts @@ -1,6 +1,6 @@ -import * as db from '@tloncorp/shared/dist/db'; -import { getTextContent } from '@tloncorp/shared/dist/urbit'; -import type { Story } from '@tloncorp/shared/dist/urbit/channel'; +import * as db from '@tloncorp/shared/db'; +import { getTextContent } from '@tloncorp/shared/urbit'; +import type { Story } from '@tloncorp/shared/urbit/channel'; import { formatUd, unixToDa } from '@urbit/aura'; import seedrandom from 'seedrandom'; diff --git a/apps/tlon-mobile/src/hooks/analytics.ts b/apps/tlon-mobile/src/hooks/analytics.ts index e432784bc3..7a1874bcfe 100644 --- a/apps/tlon-mobile/src/hooks/analytics.ts +++ b/apps/tlon-mobile/src/hooks/analytics.ts @@ -1,5 +1,5 @@ import { useLureMetadata } from '@tloncorp/app/contexts/branch'; -import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared'; import { useEffect } from 'react'; import { checkLatestVersion } from '../lib/lifecycleEvents'; diff --git a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts index 3bb798bcae..24e5c715b5 100644 --- a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts +++ b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts @@ -3,8 +3,8 @@ import { useBranch, useSignupParams } from '@tloncorp/app/contexts/branch'; import { useShip } from '@tloncorp/app/contexts/ship'; import { inviteShipWithLure } from '@tloncorp/app/lib/hostingApi'; import { trackError } from '@tloncorp/app/utils/posthog'; -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as store from '@tloncorp/shared/store'; import { useEffect, useRef } from 'react'; import { RootStackParamList } from '../types'; diff --git a/apps/tlon-mobile/src/hooks/useNotificationListener.ts b/apps/tlon-mobile/src/hooks/useNotificationListener.ts index 45bcce56b8..7932adecce 100644 --- a/apps/tlon-mobile/src/hooks/useNotificationListener.ts +++ b/apps/tlon-mobile/src/hooks/useNotificationListener.ts @@ -5,11 +5,11 @@ import { useFeatureFlag } from '@tloncorp/app/lib/featureFlags'; import { connectNotifications } from '@tloncorp/app/lib/notifications'; import * as posthog from '@tloncorp/app/utils/posthog'; import { syncDms, syncGroups } from '@tloncorp/shared'; -import { markChatRead } from '@tloncorp/shared/dist/api'; -import * as api from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; -import { whomIsDm, whomIsMultiDm } from '@tloncorp/shared/dist/urbit'; +import { markChatRead } from '@tloncorp/shared/api'; +import * as api from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; +import { whomIsDm, whomIsMultiDm } from '@tloncorp/shared/urbit'; import { Notification, addNotificationResponseReceivedListener, diff --git a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts index 44904dd682..d0c10d480b 100644 --- a/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts +++ b/apps/tlon-mobile/src/hooks/useReviveSavedOnboarding.ts @@ -1,12 +1,12 @@ import { NavigationProp, useNavigation } from '@react-navigation/native'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; import { useShip } from '@tloncorp/app/contexts/ship'; -import { useSignupContext } from '../lib/signupContext'; -import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; -import { SignupParams, signupData } from '@tloncorp/shared/dist/db'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared'; +import { SignupParams, signupData } from '@tloncorp/shared/db'; import { useCallback, useEffect } from 'react'; import { useOnboardingContext } from '../lib/OnboardingContext'; +import { useSignupContext } from '../lib/signupContext'; import { OnboardingStackParamList } from '../types'; const logger = createDevLogger('OnboardingRevive', true); diff --git a/apps/tlon-mobile/src/lib/OnboardingContext.tsx b/apps/tlon-mobile/src/lib/OnboardingContext.tsx index 790d5c028c..12e934521c 100644 --- a/apps/tlon-mobile/src/lib/OnboardingContext.tsx +++ b/apps/tlon-mobile/src/lib/OnboardingContext.tsx @@ -4,7 +4,7 @@ import { initClient, } from '@google-cloud/recaptcha-enterprise-react-native'; import * as hostingApi from '@tloncorp/app/lib/hostingApi'; -import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/api'; import { createContext, useContext } from 'react'; interface OnboardingContextValue { diff --git a/apps/tlon-mobile/src/lib/lifecycleEvents.ts b/apps/tlon-mobile/src/lib/lifecycleEvents.ts index 70061ffe40..75c4511b33 100644 --- a/apps/tlon-mobile/src/lib/lifecycleEvents.ts +++ b/apps/tlon-mobile/src/lib/lifecycleEvents.ts @@ -1,5 +1,5 @@ import { getEasUpdateDisplay } from '@tloncorp/app/lib/platformHelpers'; -import { lastAppVersion } from '@tloncorp/shared/dist/db'; +import { lastAppVersion } from '@tloncorp/shared/db'; import * as Application from 'expo-application'; import * as Updates from 'expo-updates'; diff --git a/apps/tlon-mobile/src/lib/refreshHostingAuth.ts b/apps/tlon-mobile/src/lib/refreshHostingAuth.ts index ef1ca99294..b2e68eee42 100644 --- a/apps/tlon-mobile/src/lib/refreshHostingAuth.ts +++ b/apps/tlon-mobile/src/lib/refreshHostingAuth.ts @@ -5,7 +5,7 @@ import { setHostingAuthExpired, setLastHostingAuthCheck, } from '@tloncorp/app/utils/hosting'; -import { createDevLogger } from '@tloncorp/shared/dist'; +import { createDevLogger } from '@tloncorp/shared'; const logger = createDevLogger('refreshHostingAuth', false); diff --git a/apps/tlon-mobile/src/lib/signupContext.tsx b/apps/tlon-mobile/src/lib/signupContext.tsx index ca6c43930f..c60826c029 100644 --- a/apps/tlon-mobile/src/lib/signupContext.tsx +++ b/apps/tlon-mobile/src/lib/signupContext.tsx @@ -3,10 +3,10 @@ import { useBootSequence } from '@tloncorp/app/hooks/useBootSequence'; import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers'; import { connectNotifyProvider } from '@tloncorp/app/lib/notificationsApi'; -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as api from '@tloncorp/shared/dist/api'; -import { SignupParams, didSignUp, signupData } from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as api from '@tloncorp/shared/api'; +import { SignupParams, didSignUp, signupData } from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { createContext, useCallback, useContext, useEffect } from 'react'; const logger = createDevLogger('signup', true); diff --git a/apps/tlon-mobile/src/screens/Onboarding/PasteInviteLinkScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/PasteInviteLinkScreen.tsx index e72dd8222a..51a8ab2bf4 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/PasteInviteLinkScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/PasteInviteLinkScreen.tsx @@ -12,7 +12,7 @@ import { createInviteLinkRegex, extractNormalizedInviteLink, getMetadaFromInviteLink, -} from '@tloncorp/shared/dist'; +} from '@tloncorp/shared'; import { Field, ScreenHeader, diff --git a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx index 817a4b6a02..a12c6858fb 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/ShipLoginScreen.tsx @@ -8,9 +8,9 @@ import { useShip } from '@tloncorp/app/contexts/ship'; import { setEulaAgreed } from '@tloncorp/app/utils/eula'; import { getShipFromCookie } from '@tloncorp/app/utils/ship'; import { transformShipURL } from '@tloncorp/app/utils/string'; -import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; -import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; -import { didSignUp } from '@tloncorp/shared/dist/db'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/api'; +import { didSignUp } from '@tloncorp/shared/db'; import { Field, KeyboardAvoidingView, diff --git a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx index 0c2cb7da56..ae58908ab7 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/TlonLoginScreen.tsx @@ -13,9 +13,9 @@ import { } from '@tloncorp/app/lib/hostingApi'; import { isEulaAgreed, setEulaAgreed } from '@tloncorp/app/utils/eula'; import { getShipUrl } from '@tloncorp/app/utils/ship'; -import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; -import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; -import { didSignUp } from '@tloncorp/shared/dist/db'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/api'; +import { didSignUp } from '@tloncorp/shared/db'; import { Field, KeyboardAvoidingView, diff --git a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx index 349df0d7b9..ecd5ed23e2 100644 --- a/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx +++ b/apps/tlon-mobile/src/screens/Onboarding/WelcomeScreen.tsx @@ -1,8 +1,8 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useLureMetadata } from '@tloncorp/app/contexts/branch'; import { trackOnboardingAction } from '@tloncorp/app/utils/posthog'; -import { setDidShowBenefitsSheet } from '@tloncorp/shared/dist/db'; -import { useDidShowBenefitsSheet } from '@tloncorp/shared/dist/store'; +import { setDidShowBenefitsSheet } from '@tloncorp/shared/db'; +import { useDidShowBenefitsSheet } from '@tloncorp/shared/store'; import { ActionSheet, Button, diff --git a/apps/tlon-mobile/src/types.ts b/apps/tlon-mobile/src/types.ts index 0568c60990..1ab59f89db 100644 --- a/apps/tlon-mobile/src/types.ts +++ b/apps/tlon-mobile/src/types.ts @@ -1,5 +1,5 @@ import type { NavigatorScreenParams } from '@react-navigation/native'; -import type * as db from '@tloncorp/shared/dist/db'; +import type * as db from '@tloncorp/shared/db'; export type SignUpExtras = { nickname?: string; diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index d606469e88..a4e8831be0 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -14,7 +14,7 @@ import { RootStack } from '@tloncorp/app/navigation/RootStack'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { sync } from '@tloncorp/shared'; -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import cookies from 'browser-cookies'; import { usePostHog } from 'posthog-js/react'; import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react'; diff --git a/apps/tlon-web-new/src/logic/analytics.ts b/apps/tlon-web-new/src/logic/analytics.ts index 96a832fe66..83bfdc0c90 100644 --- a/apps/tlon-web-new/src/logic/analytics.ts +++ b/apps/tlon-web-new/src/logic/analytics.ts @@ -1,4 +1,4 @@ -import { PrivacyType } from '@tloncorp/shared/dist/urbit/groups'; +import { PrivacyType } from '@tloncorp/shared/urbit/groups'; import posthog, { Properties } from 'posthog-js'; import { log } from './utils'; diff --git a/apps/tlon-web-new/src/logic/utils.ts b/apps/tlon-web-new/src/logic/utils.ts index efa38ec865..12dfc54395 100644 --- a/apps/tlon-web-new/src/logic/utils.ts +++ b/apps/tlon-web-new/src/logic/utils.ts @@ -1,4 +1,4 @@ -import { MessageKey } from '@tloncorp/shared/dist/urbit/activity'; +import { MessageKey } from '@tloncorp/shared/urbit/activity'; import { CacheId, ChatStory, @@ -9,13 +9,13 @@ import { Verse, VerseBlock, VerseInline, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { Bold, Inline, Italics, Strikethrough, -} from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/content'; import { Cabals, ChannelPrivacyType, @@ -27,7 +27,7 @@ import { PrivacyType, Rank, Saga, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import { BigIntOrderedMap, Docket, diff --git a/apps/tlon-web-new/src/mocks/chat.ts b/apps/tlon-web-new/src/mocks/chat.ts index 1b50f5b779..26e0766dc9 100644 --- a/apps/tlon-web-new/src/mocks/chat.ts +++ b/apps/tlon-web-new/src/mocks/chat.ts @@ -1,11 +1,11 @@ import { faker } from '@faker-js/faker'; -import { Activity } from '@tloncorp/shared/dist/urbit/activity'; +import { Activity } from '@tloncorp/shared/urbit/activity'; import { Post, Posts, Story, storyFromChatStory, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { decToUd, unixToDa } from '@urbit/api'; import { subDays, subMinutes } from 'date-fns'; import _ from 'lodash'; diff --git a/apps/tlon-web-new/src/mocks/groups.ts b/apps/tlon-web-new/src/mocks/groups.ts index 43ab5ad138..0e42255ca5 100644 --- a/apps/tlon-web-new/src/mocks/groups.ts +++ b/apps/tlon-web-new/src/mocks/groups.ts @@ -8,7 +8,7 @@ import { GroupPreview, PrivacyType, Vessel, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import { AUTHORS } from '@/constants'; import { randomElement } from '@/logic/utils'; diff --git a/apps/tlon-web-new/src/mocks/handlers.ts b/apps/tlon-web-new/src/mocks/handlers.ts index eef5db1aa2..d518ab3acc 100644 --- a/apps/tlon-web-new/src/mocks/handlers.ts +++ b/apps/tlon-web-new/src/mocks/handlers.ts @@ -16,8 +16,8 @@ import { DMWhom, DmRsvp, WritDiff, -} from '@tloncorp/shared/dist/urbit/dms'; -import { GroupAction } from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/dms'; +import { GroupAction } from '@tloncorp/shared/urbit/groups'; import { decToUd, udToDec, unixToDa } from '@urbit/api'; import bigInt from 'big-integer'; import _ from 'lodash'; diff --git a/apps/tlon-web-new/src/mocks/heaps.ts b/apps/tlon-web-new/src/mocks/heaps.ts index 75ca19ea08..f4c94a4ff2 100644 --- a/apps/tlon-web-new/src/mocks/heaps.ts +++ b/apps/tlon-web-new/src/mocks/heaps.ts @@ -3,7 +3,7 @@ import { ScryHandler, SubscriptionHandler, } from '@tloncorp/mock-http-api'; -import { Channels, Perm, Posts } from '@tloncorp/shared/dist/urbit/channel'; +import { Channels, Perm, Posts } from '@tloncorp/shared/urbit/channel'; import { subMinutes } from 'date-fns'; const unixTime = subMinutes(new Date(), 1).getTime(); diff --git a/apps/tlon-web-new/src/state/settings.ts b/apps/tlon-web-new/src/state/settings.ts index daf1133961..339e10dda6 100644 --- a/apps/tlon-web-new/src/state/settings.ts +++ b/apps/tlon-web-new/src/state/settings.ts @@ -1,5 +1,5 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { DisplayMode, SortMode } from '@tloncorp/shared/dist/urbit/channel'; +import { DisplayMode, SortMode } from '@tloncorp/shared/urbit/channel'; import { DelBucket, DelEntry, PutBucket, Value } from '@urbit/api'; import cookies from 'browser-cookies'; import produce from 'immer'; diff --git a/apps/tlon-web-new/src/window.ts b/apps/tlon-web-new/src/window.ts index 4cce54e71d..bed0bf3bd6 100644 --- a/apps/tlon-web-new/src/window.ts +++ b/apps/tlon-web-new/src/window.ts @@ -1,5 +1,5 @@ import type { NativeWebViewOptions } from '@tloncorp/shared'; -import { Rope } from '@tloncorp/shared/dist/urbit/hark'; +import { Rope } from '@tloncorp/shared/urbit/hark'; declare global { interface Window { diff --git a/apps/tlon-web-new/tsconfig.json b/apps/tlon-web-new/tsconfig.json index 08771a1a4a..5cf4c43d64 100644 --- a/apps/tlon-web-new/tsconfig.json +++ b/apps/tlon-web-new/tsconfig.json @@ -4,7 +4,6 @@ "lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"], "experimentalDecorators": true, "module": "ESNext", - "moduleResolution": "Node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, diff --git a/apps/tlon-web/src/channels/ChannelActions.tsx b/apps/tlon-web/src/channels/ChannelActions.tsx index 886d80113a..ffd1f00596 100644 --- a/apps/tlon-web/src/channels/ChannelActions.tsx +++ b/apps/tlon-web/src/channels/ChannelActions.tsx @@ -1,5 +1,5 @@ -import { GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; -import { getPrettyAppName } from '@tloncorp/shared/src/logic/utils'; +import { getPrettyAppName } from '@tloncorp/shared/logic/utils'; +import { GroupChannel } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { PropsWithChildren, useCallback, useState } from 'react'; diff --git a/apps/tlon-web/src/channels/ChannelSortSelector.tsx b/apps/tlon-web/src/channels/ChannelSortSelector.tsx index 147df00706..be807cd9c2 100644 --- a/apps/tlon-web/src/channels/ChannelSortSelector.tsx +++ b/apps/tlon-web/src/channels/ChannelSortSelector.tsx @@ -1,4 +1,4 @@ -import { ChannelFormSchema } from '@tloncorp/shared/dist/urbit/groups'; +import { ChannelFormSchema } from '@tloncorp/shared/urbit/groups'; import { useFormContext } from 'react-hook-form'; interface SortSettingRowProps { diff --git a/apps/tlon-web/src/channels/ChannelTypeSelector.tsx b/apps/tlon-web/src/channels/ChannelTypeSelector.tsx index 9b0d76e89d..3920f4d965 100644 --- a/apps/tlon-web/src/channels/ChannelTypeSelector.tsx +++ b/apps/tlon-web/src/channels/ChannelTypeSelector.tsx @@ -1,7 +1,7 @@ import { ChannelType, NewChannelFormSchema, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React from 'react'; import { useFormContext } from 'react-hook-form'; diff --git a/apps/tlon-web/src/channels/ChannelViewSelector.tsx b/apps/tlon-web/src/channels/ChannelViewSelector.tsx index 6166a91986..923483cb8e 100644 --- a/apps/tlon-web/src/channels/ChannelViewSelector.tsx +++ b/apps/tlon-web/src/channels/ChannelViewSelector.tsx @@ -1,4 +1,4 @@ -import { ChannelFormSchema } from '@tloncorp/shared/dist/urbit/groups'; +import { ChannelFormSchema } from '@tloncorp/shared/urbit/groups'; import { useFormContext } from 'react-hook-form'; interface ViewSettingRowProps { diff --git a/apps/tlon-web/src/channels/ChannelVolumeDialog.tsx b/apps/tlon-web/src/channels/ChannelVolumeDialog.tsx index 4246ca1d8e..2b7ca718b4 100644 --- a/apps/tlon-web/src/channels/ChannelVolumeDialog.tsx +++ b/apps/tlon-web/src/channels/ChannelVolumeDialog.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { Helmet } from 'react-helmet'; import { useParams } from 'react-router'; diff --git a/apps/tlon-web/src/channels/DisplayDropdown.tsx b/apps/tlon-web/src/channels/DisplayDropdown.tsx index 88652e5d11..f1405747be 100644 --- a/apps/tlon-web/src/channels/DisplayDropdown.tsx +++ b/apps/tlon-web/src/channels/DisplayDropdown.tsx @@ -1,5 +1,5 @@ import * as Dropdown from '@radix-ui/react-dropdown-menu'; -import { DisplayMode } from '@tloncorp/shared/dist/urbit/channel'; +import { DisplayMode } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import GridIcon from '@/components/icons/GridIcon'; diff --git a/apps/tlon-web/src/channels/EditChannelForm.tsx b/apps/tlon-web/src/channels/EditChannelForm.tsx index 2d5f8c1856..c5c3232751 100644 --- a/apps/tlon-web/src/channels/EditChannelForm.tsx +++ b/apps/tlon-web/src/channels/EditChannelForm.tsx @@ -1,9 +1,6 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'; -import { SortMode } from '@tloncorp/shared/dist/urbit/channel'; -import { - ChannelFormSchema, - GroupChannel, -} from '@tloncorp/shared/dist/urbit/groups'; +import { SortMode } from '@tloncorp/shared/urbit/channel'; +import { ChannelFormSchema, GroupChannel } from '@tloncorp/shared/urbit/groups'; import _ from 'lodash'; import React, { useCallback } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; diff --git a/apps/tlon-web/src/channels/NewChannel/NewChannelForm.tsx b/apps/tlon-web/src/channels/NewChannel/NewChannelForm.tsx index a5d8daf8e1..3a1cb5d383 100644 --- a/apps/tlon-web/src/channels/NewChannel/NewChannelForm.tsx +++ b/apps/tlon-web/src/channels/NewChannel/NewChannelForm.tsx @@ -1,5 +1,5 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'; -import { NewChannelFormSchema } from '@tloncorp/shared/dist/urbit/groups'; +import { NewChannelFormSchema } from '@tloncorp/shared/urbit/groups'; import { useCallback } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate, useParams } from 'react-router'; diff --git a/apps/tlon-web/src/channels/ThreadVolumeDialog.tsx b/apps/tlon-web/src/channels/ThreadVolumeDialog.tsx index 8b491f63d6..2eefd28d8f 100644 --- a/apps/tlon-web/src/channels/ThreadVolumeDialog.tsx +++ b/apps/tlon-web/src/channels/ThreadVolumeDialog.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { Helmet } from 'react-helmet'; import { useParams } from 'react-router'; diff --git a/apps/tlon-web/src/chat/ChatChannel.tsx b/apps/tlon-web/src/chat/ChatChannel.tsx index a5c92238a8..c3be280a35 100644 --- a/apps/tlon-web/src/chat/ChatChannel.tsx +++ b/apps/tlon-web/src/chat/ChatChannel.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { useMemo, useRef } from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/chat/ChatContent/ChatContent.tsx b/apps/tlon-web/src/chat/ChatContent/ChatContent.tsx index 791dfd7ec1..1909259de2 100644 --- a/apps/tlon-web/src/chat/ChatContent/ChatContent.tsx +++ b/apps/tlon-web/src/chat/ChatContent/ChatContent.tsx @@ -4,7 +4,7 @@ import { VerseBlock, VerseInline, isImage, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { Inline, isBlockCode, @@ -16,7 +16,7 @@ import { isLink, isShip, isStrikethrough, -} from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/content'; import cn from 'classnames'; import { findLastIndex } from 'lodash'; import React, { useEffect } from 'react'; diff --git a/apps/tlon-web/src/chat/ChatInput/ChatInput.tsx b/apps/tlon-web/src/chat/ChatInput/ChatInput.tsx index 3fb7875b0d..40c5c3434f 100644 --- a/apps/tlon-web/src/chat/ChatInput/ChatInput.tsx +++ b/apps/tlon-web/src/chat/ChatInput/ChatInput.tsx @@ -1,6 +1,6 @@ import * as Popover from '@radix-ui/react-popover'; import { Editor } from '@tiptap/react'; -import { getKey, getThreadKey } from '@tloncorp/shared/dist/urbit/activity'; +import { getKey, getThreadKey } from '@tloncorp/shared/urbit/activity'; import { CacheId, Cite, @@ -12,8 +12,8 @@ import { Reply, ReplyTuple, Writ, -} from '@tloncorp/shared/dist/urbit/channel'; -import { WritTuple } from '@tloncorp/shared/dist/urbit/dms'; +} from '@tloncorp/shared/urbit/channel'; +import { WritTuple } from '@tloncorp/shared/urbit/dms'; import cn from 'classnames'; import _, { debounce } from 'lodash'; import React, { diff --git a/apps/tlon-web/src/chat/ChatMessage/ChatMessage.tsx b/apps/tlon-web/src/chat/ChatMessage/ChatMessage.tsx index 9f754869f9..b28938a4b8 100644 --- a/apps/tlon-web/src/chat/ChatMessage/ChatMessage.tsx +++ b/apps/tlon-web/src/chat/ChatMessage/ChatMessage.tsx @@ -6,13 +6,13 @@ import { getDmSource, getKey, getThreadKey, -} from '@tloncorp/shared/dist/urbit/activity'; +} from '@tloncorp/shared/urbit/activity'; import { Post, Story, VerseBlock, constructStory, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { daToUnix } from '@urbit/api'; import { formatUd } from '@urbit/aura'; import { BigInteger } from 'big-integer'; diff --git a/apps/tlon-web/src/chat/ChatMessage/ChatMessageOptions.tsx b/apps/tlon-web/src/chat/ChatMessage/ChatMessageOptions.tsx index 0fed574eae..52c3aac29a 100644 --- a/apps/tlon-web/src/chat/ChatMessage/ChatMessageOptions.tsx +++ b/apps/tlon-web/src/chat/ChatMessage/ChatMessageOptions.tsx @@ -1,4 +1,4 @@ -import { Post, emptyPost } from '@tloncorp/shared/dist/urbit/channel'; +import { Post, emptyPost } from '@tloncorp/shared/urbit/channel'; import { decToUd } from '@urbit/api'; import cn from 'classnames'; import React, { diff --git a/apps/tlon-web/src/chat/ChatMessage/DeletedChatMessage.tsx b/apps/tlon-web/src/chat/ChatMessage/DeletedChatMessage.tsx index 3a8a27d04e..e27bd90985 100644 --- a/apps/tlon-web/src/chat/ChatMessage/DeletedChatMessage.tsx +++ b/apps/tlon-web/src/chat/ChatMessage/DeletedChatMessage.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-unused-prop-types */ -import { getKey } from '@tloncorp/shared/dist/urbit/activity'; +import { getKey } from '@tloncorp/shared/urbit/activity'; import { daToUnix } from '@urbit/api'; import { BigInteger } from 'big-integer'; import cn from 'classnames'; diff --git a/apps/tlon-web/src/chat/ChatMessage/DeletedChatReply.tsx b/apps/tlon-web/src/chat/ChatMessage/DeletedChatReply.tsx index 6ea9987ce2..d3f00d49e0 100644 --- a/apps/tlon-web/src/chat/ChatMessage/DeletedChatReply.tsx +++ b/apps/tlon-web/src/chat/ChatMessage/DeletedChatReply.tsx @@ -4,7 +4,7 @@ import { getChannelSource, getDmSource, getThreadKey, -} from '@tloncorp/shared/dist/urbit/activity'; +} from '@tloncorp/shared/urbit/activity'; import { daToUnix } from '@urbit/api'; import { BigInteger } from 'big-integer'; import cn from 'classnames'; diff --git a/apps/tlon-web/src/chat/ChatNotice.tsx b/apps/tlon-web/src/chat/ChatNotice.tsx index b5bbbbd35d..5599c478b0 100644 --- a/apps/tlon-web/src/chat/ChatNotice.tsx +++ b/apps/tlon-web/src/chat/ChatNotice.tsx @@ -1,4 +1,4 @@ -import { Post } from '@tloncorp/shared/dist/urbit/channel'; +import { Post } from '@tloncorp/shared/urbit/channel'; import React from 'react'; import AddPersonIcon from '@/components/icons/AddPersonIcon'; diff --git a/apps/tlon-web/src/chat/ChatReactions/ChatReaction.tsx b/apps/tlon-web/src/chat/ChatReactions/ChatReaction.tsx index b3c8b67f6b..4a619a5a1e 100644 --- a/apps/tlon-web/src/chat/ChatReactions/ChatReaction.tsx +++ b/apps/tlon-web/src/chat/ChatReactions/ChatReaction.tsx @@ -1,5 +1,5 @@ import * as Tooltip from '@radix-ui/react-tooltip'; -import { PostSeal, ReplySeal } from '@tloncorp/shared/dist/urbit/channel'; +import { PostSeal, ReplySeal } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import React, { useCallback, useEffect } from 'react'; diff --git a/apps/tlon-web/src/chat/ChatReactions/ChatReactions.tsx b/apps/tlon-web/src/chat/ChatReactions/ChatReactions.tsx index e7eda1561e..e4549a7019 100644 --- a/apps/tlon-web/src/chat/ChatReactions/ChatReactions.tsx +++ b/apps/tlon-web/src/chat/ChatReactions/ChatReactions.tsx @@ -1,4 +1,4 @@ -import { PostSeal } from '@tloncorp/shared/dist/urbit/channel'; +import { PostSeal } from '@tloncorp/shared/urbit/channel'; import _ from 'lodash'; import { useCallback, useState } from 'react'; import { useLocation, useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/chat/ChatScroller/ChatScroller.tsx b/apps/tlon-web/src/chat/ChatScroller/ChatScroller.tsx index c51466a39c..656861b5c2 100644 --- a/apps/tlon-web/src/chat/ChatScroller/ChatScroller.tsx +++ b/apps/tlon-web/src/chat/ChatScroller/ChatScroller.tsx @@ -1,7 +1,7 @@ import { Virtualizer, useVirtualizer } from '@tanstack/react-virtual'; -import { MessageKey } from '@tloncorp/shared/dist/urbit/activity'; -import { PostTuple, ReplyTuple } from '@tloncorp/shared/dist/urbit/channel'; -import { WritTuple } from '@tloncorp/shared/dist/urbit/dms'; +import { MessageKey } from '@tloncorp/shared/urbit/activity'; +import { PostTuple, ReplyTuple } from '@tloncorp/shared/urbit/channel'; +import { WritTuple } from '@tloncorp/shared/urbit/dms'; import { BigInteger } from 'big-integer'; import React, { PropsWithChildren, diff --git a/apps/tlon-web/src/chat/ChatSearch/ChatSearch.tsx b/apps/tlon-web/src/chat/ChatSearch/ChatSearch.tsx index 4b90f7869a..9dd92b9e32 100644 --- a/apps/tlon-web/src/chat/ChatSearch/ChatSearch.tsx +++ b/apps/tlon-web/src/chat/ChatSearch/ChatSearch.tsx @@ -1,4 +1,4 @@ -import { ChatMap } from '@tloncorp/shared/dist/urbit/channel'; +import { ChatMap } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import React, { PropsWithChildren, useCallback, useRef } from 'react'; import { useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/chat/ChatSearch/ChatSearchResult.tsx b/apps/tlon-web/src/chat/ChatSearch/ChatSearchResult.tsx index 8495ecee0e..88b69e5c25 100644 --- a/apps/tlon-web/src/chat/ChatSearch/ChatSearchResult.tsx +++ b/apps/tlon-web/src/chat/ChatSearch/ChatSearchResult.tsx @@ -1,5 +1,5 @@ -import { Post, Reply } from '@tloncorp/shared/dist/urbit/channel'; -import { Writ } from '@tloncorp/shared/dist/urbit/dms'; +import { Post, Reply } from '@tloncorp/shared/urbit/channel'; +import { Writ } from '@tloncorp/shared/urbit/dms'; import { daToUnix } from '@urbit/api'; import { BigInteger } from 'big-integer'; import cn from 'classnames'; diff --git a/apps/tlon-web/src/chat/ChatSearch/ChatSearchResults.tsx b/apps/tlon-web/src/chat/ChatSearch/ChatSearchResults.tsx index f3cd05ff8b..c215dab3c6 100644 --- a/apps/tlon-web/src/chat/ChatSearch/ChatSearchResults.tsx +++ b/apps/tlon-web/src/chat/ChatSearch/ChatSearchResults.tsx @@ -1,5 +1,5 @@ -import { ChatMap, Post, Reply } from '@tloncorp/shared/dist/urbit/channel'; -import { Writ } from '@tloncorp/shared/dist/urbit/dms'; +import { ChatMap, Post, Reply } from '@tloncorp/shared/urbit/channel'; +import { Writ } from '@tloncorp/shared/urbit/dms'; import { BigInteger } from 'big-integer'; import React, { useMemo } from 'react'; import { Virtuoso, VirtuosoHandle } from 'react-virtuoso'; diff --git a/apps/tlon-web/src/chat/ChatSearch/useChatSearchInput.tsx b/apps/tlon-web/src/chat/ChatSearch/useChatSearchInput.tsx index 62574c2f1a..cc77472439 100644 --- a/apps/tlon-web/src/chat/ChatSearch/useChatSearchInput.tsx +++ b/apps/tlon-web/src/chat/ChatSearch/useChatSearchInput.tsx @@ -1,4 +1,4 @@ -import { ChatMap } from '@tloncorp/shared/dist/urbit/channel'; +import { ChatMap } from '@tloncorp/shared/urbit/channel'; import bigInt from 'big-integer'; import { ChangeEvent, KeyboardEvent, useCallback, useState } from 'react'; import { useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/chat/ChatThread/ChatThread.tsx b/apps/tlon-web/src/chat/ChatThread/ChatThread.tsx index f4ebf3f940..f4579b0ccc 100644 --- a/apps/tlon-web/src/chat/ChatThread/ChatThread.tsx +++ b/apps/tlon-web/src/chat/ChatThread/ChatThread.tsx @@ -1,4 +1,4 @@ -import { ReplyTuple } from '@tloncorp/shared/dist/urbit/channel'; +import { ReplyTuple } from '@tloncorp/shared/urbit/channel'; import { formatUd } from '@urbit/aura'; import bigInt from 'big-integer'; import cn from 'classnames'; diff --git a/apps/tlon-web/src/chat/ChatWindow.tsx b/apps/tlon-web/src/chat/ChatWindow.tsx index 395aec9e5b..8910999cf8 100644 --- a/apps/tlon-web/src/chat/ChatWindow.tsx +++ b/apps/tlon-web/src/chat/ChatWindow.tsx @@ -1,4 +1,4 @@ -import { sourceToString } from '@tloncorp/shared/dist/urbit/activity'; +import { sourceToString } from '@tloncorp/shared/urbit/activity'; import bigInt from 'big-integer'; import React, { ReactElement, diff --git a/apps/tlon-web/src/chat/UnreadAlerts.tsx b/apps/tlon-web/src/chat/UnreadAlerts.tsx index 7b79e5c6d4..867753cb0f 100644 --- a/apps/tlon-web/src/chat/UnreadAlerts.tsx +++ b/apps/tlon-web/src/chat/UnreadAlerts.tsx @@ -1,4 +1,4 @@ -import { getKey } from '@tloncorp/shared/dist/urbit/activity'; +import { getKey } from '@tloncorp/shared/urbit/activity'; import { daToUnix } from '@urbit/api'; import bigInt from 'big-integer'; import { format, isToday } from 'date-fns'; diff --git a/apps/tlon-web/src/chat/useChatStore.ts b/apps/tlon-web/src/chat/useChatStore.ts index 36d42ed4a0..9686720337 100644 --- a/apps/tlon-web/src/chat/useChatStore.ts +++ b/apps/tlon-web/src/chat/useChatStore.ts @@ -1,8 +1,5 @@ -import { - ActivitySummary, - MessageKey, -} from '@tloncorp/shared/dist/urbit/activity'; -import { Block } from '@tloncorp/shared/dist/urbit/channel'; +import { ActivitySummary, MessageKey } from '@tloncorp/shared/urbit/activity'; +import { Block } from '@tloncorp/shared/urbit/channel'; import produce from 'immer'; import { useCallback } from 'react'; import create from 'zustand'; diff --git a/apps/tlon-web/src/components/About/AboutView.tsx b/apps/tlon-web/src/components/About/AboutView.tsx index bfc7f93f28..25875f23a0 100644 --- a/apps/tlon-web/src/components/About/AboutView.tsx +++ b/apps/tlon-web/src/components/About/AboutView.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { Helmet } from 'react-helmet'; import { useBottomPadding } from '@/logic/position'; diff --git a/apps/tlon-web/src/components/Avatar.tsx b/apps/tlon-web/src/components/Avatar.tsx index 91cece39f5..b313115778 100644 --- a/apps/tlon-web/src/components/Avatar.tsx +++ b/apps/tlon-web/src/components/Avatar.tsx @@ -1,4 +1,4 @@ -import { SigilProps } from '@tloncorp/shared/dist/urbit/sigil'; +import { SigilProps } from '@tloncorp/shared/urbit/sigil'; import { Contact, cite } from '@urbit/api'; import '@urbit/sigil-js'; import classNames from 'classnames'; diff --git a/apps/tlon-web/src/components/ClubName.tsx b/apps/tlon-web/src/components/ClubName.tsx index 5e5ca2f43f..2c0a28db86 100644 --- a/apps/tlon-web/src/components/ClubName.tsx +++ b/apps/tlon-web/src/components/ClubName.tsx @@ -1,4 +1,4 @@ -import type { Club } from '@tloncorp/shared/dist/urbit/dms'; +import type { Club } from '@tloncorp/shared/urbit/dms'; import ShipName from './ShipName'; diff --git a/apps/tlon-web/src/components/DevLog/DevLogView.tsx b/apps/tlon-web/src/components/DevLog/DevLogView.tsx index c70f11897f..03a081bc40 100644 --- a/apps/tlon-web/src/components/DevLog/DevLogView.tsx +++ b/apps/tlon-web/src/components/DevLog/DevLogView.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/components/Leap/useLeap.tsx b/apps/tlon-web/src/components/Leap/useLeap.tsx index e873178ed4..d6a838354b 100644 --- a/apps/tlon-web/src/components/Leap/useLeap.tsx +++ b/apps/tlon-web/src/components/Leap/useLeap.tsx @@ -1,6 +1,6 @@ -import { Contact } from '@tloncorp/shared/dist/urbit/contact'; -import { Club } from '@tloncorp/shared/dist/urbit/dms'; -import { Group, GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; +import { Contact } from '@tloncorp/shared/urbit/contact'; +import { Club } from '@tloncorp/shared/urbit/dms'; +import { Group, GroupChannel } from '@tloncorp/shared/urbit/groups'; import { cite, deSig, preSig } from '@urbit/api'; import fuzzy from 'fuzzy'; import { uniqBy } from 'lodash'; diff --git a/apps/tlon-web/src/components/MessageEditor.tsx b/apps/tlon-web/src/components/MessageEditor.tsx index f7747f7072..f2af69cd4a 100644 --- a/apps/tlon-web/src/components/MessageEditor.tsx +++ b/apps/tlon-web/src/components/MessageEditor.tsx @@ -15,7 +15,7 @@ import Text from '@tiptap/extension-text'; import { Slice } from '@tiptap/pm/model'; import { EditorView } from '@tiptap/pm/view'; import { Editor, EditorContent, JSONContent, useEditor } from '@tiptap/react'; -import { Cite } from '@tloncorp/shared/dist/urbit/channel'; +import { Cite } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import React, { useCallback, useMemo } from 'react'; diff --git a/apps/tlon-web/src/components/References/ContentReference.tsx b/apps/tlon-web/src/components/References/ContentReference.tsx index 95dca7a73e..2f08af6579 100644 --- a/apps/tlon-web/src/components/References/ContentReference.tsx +++ b/apps/tlon-web/src/components/References/ContentReference.tsx @@ -1,4 +1,4 @@ -import { Cite } from '@tloncorp/shared/dist/urbit/channel'; +import { Cite } from '@tloncorp/shared/urbit/channel'; import { udToDec } from '@urbit/api'; import React from 'react'; diff --git a/apps/tlon-web/src/components/References/CurioReference.tsx b/apps/tlon-web/src/components/References/CurioReference.tsx index acef232e42..b75753ae1a 100644 --- a/apps/tlon-web/src/components/References/CurioReference.tsx +++ b/apps/tlon-web/src/components/References/CurioReference.tsx @@ -1,4 +1,4 @@ -import { imageUrlFromContent } from '@tloncorp/shared/dist/urbit/channel'; +import { imageUrlFromContent } from '@tloncorp/shared/urbit/channel'; import bigInt from 'big-integer'; import React, { useMemo } from 'react'; import { useLocation, useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/components/References/UnavailableReference.tsx b/apps/tlon-web/src/components/References/UnavailableReference.tsx index 315e2ded47..958a10cba2 100644 --- a/apps/tlon-web/src/components/References/UnavailableReference.tsx +++ b/apps/tlon-web/src/components/References/UnavailableReference.tsx @@ -1,4 +1,4 @@ -import { ChannelPreview } from '@tloncorp/shared/dist/urbit/groups'; +import { ChannelPreview } from '@tloncorp/shared/urbit/groups'; import bigInt from 'big-integer'; import React from 'react'; diff --git a/apps/tlon-web/src/components/References/WritBaseReference.tsx b/apps/tlon-web/src/components/References/WritBaseReference.tsx index 6cbc23bb38..9ea8db142d 100644 --- a/apps/tlon-web/src/components/References/WritBaseReference.tsx +++ b/apps/tlon-web/src/components/References/WritBaseReference.tsx @@ -1,4 +1,4 @@ -import { ReferenceResponse } from '@tloncorp/shared/dist/urbit/channel'; +import { ReferenceResponse } from '@tloncorp/shared/urbit/channel'; import bigInt from 'big-integer'; import cn from 'classnames'; import React, { useMemo } from 'react'; diff --git a/apps/tlon-web/src/components/Settings/BlockedUsersView.tsx b/apps/tlon-web/src/components/Settings/BlockedUsersView.tsx index ebf7b8cfee..f3ca149cca 100644 --- a/apps/tlon-web/src/components/Settings/BlockedUsersView.tsx +++ b/apps/tlon-web/src/components/Settings/BlockedUsersView.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/components/Settings/Settings.tsx b/apps/tlon-web/src/components/Settings/Settings.tsx index 16c2a17795..3cda7f346b 100644 --- a/apps/tlon-web/src/components/Settings/Settings.tsx +++ b/apps/tlon-web/src/components/Settings/Settings.tsx @@ -1,5 +1,5 @@ import { useMutation } from '@tanstack/react-query'; -import { ActivityAction, ActivityUpdate } from '@tloncorp/shared/dist/urbit'; +import { ActivityAction, ActivityUpdate } from '@tloncorp/shared/urbit'; import cn from 'classnames'; import { useCallback } from 'react'; import { Link, useLocation } from 'react-router-dom'; diff --git a/apps/tlon-web/src/components/Settings/SettingsView.tsx b/apps/tlon-web/src/components/Settings/SettingsView.tsx index 48ea2c6834..6acef22d94 100644 --- a/apps/tlon-web/src/components/Settings/SettingsView.tsx +++ b/apps/tlon-web/src/components/Settings/SettingsView.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { Helmet } from 'react-helmet'; import { useBottomPadding } from '@/logic/position'; diff --git a/apps/tlon-web/src/components/Sidebar/GroupList.tsx b/apps/tlon-web/src/components/Sidebar/GroupList.tsx index 00eaf50671..ff148a2b3e 100644 --- a/apps/tlon-web/src/components/Sidebar/GroupList.tsx +++ b/apps/tlon-web/src/components/Sidebar/GroupList.tsx @@ -1,4 +1,4 @@ -import { Group } from '@tloncorp/shared/dist/urbit/groups'; +import { Group } from '@tloncorp/shared/urbit/groups'; import React, { ReactNode, useEffect, useMemo, useRef } from 'react'; import { StateSnapshot, Virtuoso, VirtuosoHandle } from 'react-virtuoso'; diff --git a/apps/tlon-web/src/components/Sidebar/Sidebar.test.tsx b/apps/tlon-web/src/components/Sidebar/Sidebar.test.tsx index 34db86d435..02db91f372 100644 --- a/apps/tlon-web/src/components/Sidebar/Sidebar.test.tsx +++ b/apps/tlon-web/src/components/Sidebar/Sidebar.test.tsx @@ -1,4 +1,4 @@ -import { Group } from '@tloncorp/shared/dist/urbit/groups'; +import { Group } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { describe, expect, it } from 'vitest'; diff --git a/apps/tlon-web/src/components/Sidebar/useSearchFilter.ts b/apps/tlon-web/src/components/Sidebar/useSearchFilter.ts index e665bf14f2..ffdd16f779 100644 --- a/apps/tlon-web/src/components/Sidebar/useSearchFilter.ts +++ b/apps/tlon-web/src/components/Sidebar/useSearchFilter.ts @@ -1,4 +1,4 @@ -import { Gangs, Groups } from '@tloncorp/shared/dist/urbit/groups'; +import { Gangs, Groups } from '@tloncorp/shared/urbit/groups'; import { deSig } from '@urbit/api'; import fuzzy from 'fuzzy'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/components/VolumeSetting.tsx b/apps/tlon-web/src/components/VolumeSetting.tsx index 35b59dbadf..923ce633e3 100644 --- a/apps/tlon-web/src/components/VolumeSetting.tsx +++ b/apps/tlon-web/src/components/VolumeSetting.tsx @@ -7,7 +7,7 @@ import { getUnreadsFromVolumeMap, getVolumeMap, sourceToString, -} from '@tloncorp/shared/dist/urbit/activity'; +} from '@tloncorp/shared/urbit/activity'; import React, { useCallback } from 'react'; import { useVolumeAdjustMutation, useVolumeSettings } from '@/state/activity'; diff --git a/apps/tlon-web/src/diary/DiaryChannel.tsx b/apps/tlon-web/src/diary/DiaryChannel.tsx index c5d1ac5b7f..dac4bac14d 100644 --- a/apps/tlon-web/src/diary/DiaryChannel.tsx +++ b/apps/tlon-web/src/diary/DiaryChannel.tsx @@ -2,8 +2,8 @@ import * as Toast from '@radix-ui/react-toast'; import { ChannelsSubscribeResponse, PostTuple, -} from '@tloncorp/shared/dist/urbit/channel'; -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/channel'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import React, { useCallback, useEffect, useRef } from 'react'; import { Helmet } from 'react-helmet'; import { Outlet, useLocation, useNavigate, useParams } from 'react-router'; diff --git a/apps/tlon-web/src/diary/DiaryCommentField.tsx b/apps/tlon-web/src/diary/DiaryCommentField.tsx index dece26125b..9a2f4e84cd 100644 --- a/apps/tlon-web/src/diary/DiaryCommentField.tsx +++ b/apps/tlon-web/src/diary/DiaryCommentField.tsx @@ -1,6 +1,6 @@ import { Editor } from '@tiptap/react'; -import { Cite, Kind, Story } from '@tloncorp/shared/dist/urbit/channel'; -import { Inline } from '@tloncorp/shared/dist/urbit/content'; +import { Cite, Kind, Story } from '@tloncorp/shared/urbit/channel'; +import { Inline } from '@tloncorp/shared/urbit/content'; import cn from 'classnames'; import { useCallback, useEffect, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; diff --git a/apps/tlon-web/src/diary/DiaryContent/DiaryContent.test.tsx b/apps/tlon-web/src/diary/DiaryContent/DiaryContent.test.tsx index 9006ac44f5..048d3348dd 100644 --- a/apps/tlon-web/src/diary/DiaryContent/DiaryContent.test.tsx +++ b/apps/tlon-web/src/diary/DiaryContent/DiaryContent.test.tsx @@ -1,4 +1,4 @@ -import { Inline } from '@tloncorp/shared/dist/urbit/content'; +import { Inline } from '@tloncorp/shared/urbit/content'; import { describe, expect, it } from 'vitest'; import { groupByParagraph } from './DiaryContent'; diff --git a/apps/tlon-web/src/diary/DiaryContent/DiaryContent.tsx b/apps/tlon-web/src/diary/DiaryContent/DiaryContent.tsx index a40be1614b..0fd0351124 100644 --- a/apps/tlon-web/src/diary/DiaryContent/DiaryContent.tsx +++ b/apps/tlon-web/src/diary/DiaryContent/DiaryContent.tsx @@ -5,7 +5,7 @@ import { Story, isCite, isImage, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { Inline, isBlockCode, @@ -16,7 +16,7 @@ import { isItalics, isLink, isStrikethrough, -} from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/content'; import cn from 'classnames'; import { toH } from 'hast-to-hyperscript'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/diary/DiaryHeader.tsx b/apps/tlon-web/src/diary/DiaryHeader.tsx index c773b27793..210118f934 100644 --- a/apps/tlon-web/src/diary/DiaryHeader.tsx +++ b/apps/tlon-web/src/diary/DiaryHeader.tsx @@ -1,4 +1,4 @@ -import { DisplayMode } from '@tloncorp/shared/dist/urbit/channel'; +import { DisplayMode } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import React, { useState } from 'react'; import { Link } from 'react-router-dom'; diff --git a/apps/tlon-web/src/diary/DiaryList/DiaryGridItem.tsx b/apps/tlon-web/src/diary/DiaryList/DiaryGridItem.tsx index ce55a83d10..0a33e059b1 100644 --- a/apps/tlon-web/src/diary/DiaryList/DiaryGridItem.tsx +++ b/apps/tlon-web/src/diary/DiaryList/DiaryGridItem.tsx @@ -1,4 +1,4 @@ -import { Post } from '@tloncorp/shared/dist/urbit/channel'; +import { Post } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import { useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/diary/DiaryList/DiaryGridView.tsx b/apps/tlon-web/src/diary/DiaryList/DiaryGridView.tsx index df7e732e1d..d9223025af 100644 --- a/apps/tlon-web/src/diary/DiaryList/DiaryGridView.tsx +++ b/apps/tlon-web/src/diary/DiaryList/DiaryGridView.tsx @@ -1,4 +1,4 @@ -import { Post, PostTuple } from '@tloncorp/shared/dist/urbit/channel'; +import { Post, PostTuple } from '@tloncorp/shared/urbit/channel'; import { RenderComponentProps, useInfiniteLoader, diff --git a/apps/tlon-web/src/diary/DiaryList/DiaryListItem.tsx b/apps/tlon-web/src/diary/DiaryList/DiaryListItem.tsx index 9ab1c23723..06dde1b0a5 100644 --- a/apps/tlon-web/src/diary/DiaryList/DiaryListItem.tsx +++ b/apps/tlon-web/src/diary/DiaryList/DiaryListItem.tsx @@ -1,4 +1,4 @@ -import { Post } from '@tloncorp/shared/dist/urbit/channel'; +import { Post } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import { useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/diary/DiaryMarkdownEditor.tsx b/apps/tlon-web/src/diary/DiaryMarkdownEditor.tsx index e2bdf27d17..9ed732725c 100644 --- a/apps/tlon-web/src/diary/DiaryMarkdownEditor.tsx +++ b/apps/tlon-web/src/diary/DiaryMarkdownEditor.tsx @@ -1,7 +1,7 @@ // currently importing from tiptap, but this could be imported directly from // prosemirror when/if we ditch tiptap import { Node, DOMParser as PMDomParser, Schema } from '@tiptap/pm/model'; -import { JSONContent } from '@tloncorp/shared/dist/urbit/content'; +import { JSONContent } from '@tloncorp/shared/urbit/content'; import { deSig, preSig } from '@urbit/api'; import { marked } from 'marked'; import { diff --git a/apps/tlon-web/src/diary/DiaryNote.tsx b/apps/tlon-web/src/diary/DiaryNote.tsx index 9799bedc06..06a55131bc 100644 --- a/apps/tlon-web/src/diary/DiaryNote.tsx +++ b/apps/tlon-web/src/diary/DiaryNote.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { udToDec } from '@urbit/api'; import bigInt from 'big-integer'; import { useCallback, useEffect, useMemo } from 'react'; diff --git a/apps/tlon-web/src/diary/DiaryNoteHeadline.tsx b/apps/tlon-web/src/diary/DiaryNoteHeadline.tsx index 93157a3cb8..87c6dfc5cb 100644 --- a/apps/tlon-web/src/diary/DiaryNoteHeadline.tsx +++ b/apps/tlon-web/src/diary/DiaryNoteHeadline.tsx @@ -1,4 +1,4 @@ -import { PostEssay } from '@tloncorp/shared/dist/urbit/channel'; +import { PostEssay } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import { format } from 'date-fns'; import { useNavigate } from 'react-router-dom'; diff --git a/apps/tlon-web/src/diary/DiaryVerse.tsx b/apps/tlon-web/src/diary/DiaryVerse.tsx index 1b6a0faad9..d55da95640 100644 --- a/apps/tlon-web/src/diary/DiaryVerse.tsx +++ b/apps/tlon-web/src/diary/DiaryVerse.tsx @@ -1,4 +1,4 @@ -import { Verse } from '@tloncorp/shared/dist/urbit/channel'; +import { Verse } from '@tloncorp/shared/urbit/channel'; import { InlineContent } from '@/chat/ChatContent/ChatContent'; diff --git a/apps/tlon-web/src/diary/NoteReactions/NoteReactions.tsx b/apps/tlon-web/src/diary/NoteReactions/NoteReactions.tsx index 171df48c19..66614d86b2 100644 --- a/apps/tlon-web/src/diary/NoteReactions/NoteReactions.tsx +++ b/apps/tlon-web/src/diary/NoteReactions/NoteReactions.tsx @@ -1,4 +1,4 @@ -import { PostSeal } from '@tloncorp/shared/dist/urbit/channel'; +import { PostSeal } from '@tloncorp/shared/urbit/channel'; import _ from 'lodash'; import { useCallback, useState } from 'react'; diff --git a/apps/tlon-web/src/diary/diary-add-note.tsx b/apps/tlon-web/src/diary/diary-add-note.tsx index d58058111d..e2607b0691 100644 --- a/apps/tlon-web/src/diary/diary-add-note.tsx +++ b/apps/tlon-web/src/diary/diary-add-note.tsx @@ -1,5 +1,5 @@ -import { constructStory } from '@tloncorp/shared/dist/urbit/channel'; -import { JSONContent } from '@tloncorp/shared/dist/urbit/content'; +import { constructStory } from '@tloncorp/shared/urbit/channel'; +import { JSONContent } from '@tloncorp/shared/urbit/content'; import cn from 'classnames'; import { useCallback, useEffect, useRef, useState } from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/dms/BroadcastHero.tsx b/apps/tlon-web/src/dms/BroadcastHero.tsx index cc4723a932..7030026fcb 100644 --- a/apps/tlon-web/src/dms/BroadcastHero.tsx +++ b/apps/tlon-web/src/dms/BroadcastHero.tsx @@ -1,4 +1,4 @@ -import { Club } from '@tloncorp/shared/dist/urbit/dms'; +import { Club } from '@tloncorp/shared/urbit/dms'; import cn from 'classnames'; import React from 'react'; diff --git a/apps/tlon-web/src/dms/BroadcastWindow.tsx b/apps/tlon-web/src/dms/BroadcastWindow.tsx index ee39b3940e..2c73394c04 100644 --- a/apps/tlon-web/src/dms/BroadcastWindow.tsx +++ b/apps/tlon-web/src/dms/BroadcastWindow.tsx @@ -1,4 +1,4 @@ -import { WritTuple } from '@tloncorp/shared/dist/urbit/dms'; +import { WritTuple } from '@tloncorp/shared/urbit/dms'; import { ReactElement, useMemo, useRef } from 'react'; import { VirtuosoHandle } from 'react-virtuoso'; diff --git a/apps/tlon-web/src/dms/DMHero.tsx b/apps/tlon-web/src/dms/DMHero.tsx index b5df7e35e4..085c0fb85b 100644 --- a/apps/tlon-web/src/dms/DMHero.tsx +++ b/apps/tlon-web/src/dms/DMHero.tsx @@ -1,4 +1,4 @@ -import { Contact } from '@tloncorp/shared/dist/urbit/contact'; +import { Contact } from '@tloncorp/shared/urbit/contact'; import { Patp } from '@urbit/api'; import { useLocation } from 'react-router'; diff --git a/apps/tlon-web/src/dms/DMOptions.tsx b/apps/tlon-web/src/dms/DMOptions.tsx index c8fab8dcb3..025656684d 100644 --- a/apps/tlon-web/src/dms/DMOptions.tsx +++ b/apps/tlon-web/src/dms/DMOptions.tsx @@ -1,4 +1,4 @@ -import { getKey } from '@tloncorp/shared/dist/urbit/activity'; +import { getKey } from '@tloncorp/shared/urbit/activity'; import cn from 'classnames'; import React, { PropsWithChildren, diff --git a/apps/tlon-web/src/dms/DMThread.tsx b/apps/tlon-web/src/dms/DMThread.tsx index 121d33e76b..74e8a12af6 100644 --- a/apps/tlon-web/src/dms/DMThread.tsx +++ b/apps/tlon-web/src/dms/DMThread.tsx @@ -1,5 +1,5 @@ -import { MessageKey } from '@tloncorp/shared/dist/urbit/activity'; -import { ReplyTuple } from '@tloncorp/shared/dist/urbit/channel'; +import { MessageKey } from '@tloncorp/shared/urbit/activity'; +import { ReplyTuple } from '@tloncorp/shared/urbit/channel'; import { formatUd } from '@urbit/aura'; import bigInt from 'big-integer'; import cn from 'classnames'; diff --git a/apps/tlon-web/src/dms/Dm.tsx b/apps/tlon-web/src/dms/Dm.tsx index c6f821a8f0..cb7626fd23 100644 --- a/apps/tlon-web/src/dms/Dm.tsx +++ b/apps/tlon-web/src/dms/Dm.tsx @@ -1,4 +1,4 @@ -import { Contact } from '@tloncorp/shared/dist/urbit/contact'; +import { Contact } from '@tloncorp/shared/urbit/contact'; import cn from 'classnames'; import { useCallback, useMemo, useRef } from 'react'; import { diff --git a/apps/tlon-web/src/dms/DmWindow.tsx b/apps/tlon-web/src/dms/DmWindow.tsx index 66d023e771..57d1f07e86 100644 --- a/apps/tlon-web/src/dms/DmWindow.tsx +++ b/apps/tlon-web/src/dms/DmWindow.tsx @@ -1,4 +1,4 @@ -import { WritTuple } from '@tloncorp/shared/dist/urbit/dms'; +import { WritTuple } from '@tloncorp/shared/urbit/dms'; import { udToDec } from '@urbit/api'; import bigInt from 'big-integer'; import { ReactElement, useCallback, useEffect, useMemo, useRef } from 'react'; diff --git a/apps/tlon-web/src/dms/MessagesList.tsx b/apps/tlon-web/src/dms/MessagesList.tsx index 1063e27523..ce5524dd81 100644 --- a/apps/tlon-web/src/dms/MessagesList.tsx +++ b/apps/tlon-web/src/dms/MessagesList.tsx @@ -1,7 +1,7 @@ import { ActivitySummary, stripSourcePrefix, -} from '@tloncorp/shared/src/urbit/activity'; +} from '@tloncorp/shared/urbit/activity'; import fuzzy from 'fuzzy'; import { PropsWithChildren, useEffect, useMemo, useRef } from 'react'; import { StateSnapshot, Virtuoso, VirtuosoHandle } from 'react-virtuoso'; diff --git a/apps/tlon-web/src/dms/MultiDMInfoForm.tsx b/apps/tlon-web/src/dms/MultiDMInfoForm.tsx index 1f39422f36..e473b4489a 100644 --- a/apps/tlon-web/src/dms/MultiDMInfoForm.tsx +++ b/apps/tlon-web/src/dms/MultiDMInfoForm.tsx @@ -1,5 +1,5 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'; -import { GroupMeta } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupMeta } from '@tloncorp/shared/urbit/groups'; import React, { useCallback, useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useParams } from 'react-router-dom'; diff --git a/apps/tlon-web/src/dms/MultiDm.tsx b/apps/tlon-web/src/dms/MultiDm.tsx index e0b6619b57..083e723325 100644 --- a/apps/tlon-web/src/dms/MultiDm.tsx +++ b/apps/tlon-web/src/dms/MultiDm.tsx @@ -1,4 +1,4 @@ -import { Club } from '@tloncorp/shared/dist/urbit/dms'; +import { Club } from '@tloncorp/shared/urbit/dms'; import cn from 'classnames'; import React, { useCallback, useRef } from 'react'; import { diff --git a/apps/tlon-web/src/dms/MultiDmHero.tsx b/apps/tlon-web/src/dms/MultiDmHero.tsx index 5dc2b2490d..d9edc45899 100644 --- a/apps/tlon-web/src/dms/MultiDmHero.tsx +++ b/apps/tlon-web/src/dms/MultiDmHero.tsx @@ -1,4 +1,4 @@ -import { Club } from '@tloncorp/shared/dist/urbit/dms'; +import { Club } from '@tloncorp/shared/urbit/dms'; import cn from 'classnames'; import React from 'react'; diff --git a/apps/tlon-web/src/groups/AddGroup/SearchResults.tsx b/apps/tlon-web/src/groups/AddGroup/SearchResults.tsx index ac45373db9..a448c35917 100644 --- a/apps/tlon-web/src/groups/AddGroup/SearchResults.tsx +++ b/apps/tlon-web/src/groups/AddGroup/SearchResults.tsx @@ -1,4 +1,4 @@ -import { Gang } from '@tloncorp/shared/dist/urbit/groups'; +import { Gang } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import Avatar from '@/components/Avatar'; diff --git a/apps/tlon-web/src/groups/ChannelsList/ChannelJoinSelector.tsx b/apps/tlon-web/src/groups/ChannelsList/ChannelJoinSelector.tsx index e24ea3190d..b25e05ce6e 100644 --- a/apps/tlon-web/src/groups/ChannelsList/ChannelJoinSelector.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/ChannelJoinSelector.tsx @@ -1,4 +1,4 @@ -import { ChannelFormSchema } from '@tloncorp/shared/dist/urbit/groups'; +import { ChannelFormSchema } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { useFormContext } from 'react-hook-form'; diff --git a/apps/tlon-web/src/groups/ChannelsList/ChannelPermsSelector.tsx b/apps/tlon-web/src/groups/ChannelsList/ChannelPermsSelector.tsx index 44c46d4336..bbb3125811 100644 --- a/apps/tlon-web/src/groups/ChannelsList/ChannelPermsSelector.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/ChannelPermsSelector.tsx @@ -2,7 +2,7 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { ChannelFormSchema, ChannelPrivacyType, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import { AnimatePresence, motion } from 'framer-motion'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/groups/ChannelsList/ChannelsListItem.tsx b/apps/tlon-web/src/groups/ChannelsList/ChannelsListItem.tsx index 282267f0de..a0a9bc9660 100644 --- a/apps/tlon-web/src/groups/ChannelsList/ChannelsListItem.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/ChannelsListItem.tsx @@ -1,4 +1,4 @@ -import { GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupChannel } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { useCallback, useState } from 'react'; import { DraggableProvided, DraggableStateSnapshot } from 'react-beautiful-dnd'; diff --git a/apps/tlon-web/src/groups/ChannelsList/DeleteChannelModal.tsx b/apps/tlon-web/src/groups/ChannelsList/DeleteChannelModal.tsx index 7a8259f26a..c8fe57d2fa 100644 --- a/apps/tlon-web/src/groups/ChannelsList/DeleteChannelModal.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/DeleteChannelModal.tsx @@ -1,4 +1,4 @@ -import { GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupChannel } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import Dialog from '@/components/Dialog'; diff --git a/apps/tlon-web/src/groups/ChannelsList/EditChannelModal.tsx b/apps/tlon-web/src/groups/ChannelsList/EditChannelModal.tsx index d5396bc9fe..0fe64fa967 100644 --- a/apps/tlon-web/src/groups/ChannelsList/EditChannelModal.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/EditChannelModal.tsx @@ -1,4 +1,4 @@ -import { GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupChannel } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import EditChannelForm from '@/channels/EditChannelForm'; diff --git a/apps/tlon-web/src/groups/ChannelsList/GroupChannelManager.tsx b/apps/tlon-web/src/groups/ChannelsList/GroupChannelManager.tsx index 1acf840e41..822847b769 100644 --- a/apps/tlon-web/src/groups/ChannelsList/GroupChannelManager.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/GroupChannelManager.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { Helmet } from 'react-helmet'; import MobileHeader from '@/components/MobileHeader'; diff --git a/apps/tlon-web/src/groups/ChannelsList/SectionNameEditInput.tsx b/apps/tlon-web/src/groups/ChannelsList/SectionNameEditInput.tsx index 346a5ba448..907ce5cf26 100644 --- a/apps/tlon-web/src/groups/ChannelsList/SectionNameEditInput.tsx +++ b/apps/tlon-web/src/groups/ChannelsList/SectionNameEditInput.tsx @@ -1,4 +1,4 @@ -import { GroupMeta } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupMeta } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { useForm } from 'react-hook-form'; diff --git a/apps/tlon-web/src/groups/ChannelsList/types.ts b/apps/tlon-web/src/groups/ChannelsList/types.ts index 66c43b5a26..42b8c2533b 100644 --- a/apps/tlon-web/src/groups/ChannelsList/types.ts +++ b/apps/tlon-web/src/groups/ChannelsList/types.ts @@ -1,4 +1,4 @@ -import { GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupChannel } from '@tloncorp/shared/urbit/groups'; export interface SectionMap { [key: string]: SectionListItem; diff --git a/apps/tlon-web/src/groups/FindGroups.tsx b/apps/tlon-web/src/groups/FindGroups.tsx index 5f0084349e..fc20ee49d0 100644 --- a/apps/tlon-web/src/groups/FindGroups.tsx +++ b/apps/tlon-web/src/groups/FindGroups.tsx @@ -1,4 +1,4 @@ -import { Gangs, ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { Gangs, ViewProps } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { useEffect, useState } from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/groups/GangPreview/GangPreview.tsx b/apps/tlon-web/src/groups/GangPreview/GangPreview.tsx index 902679d5b2..504e6bfdc7 100644 --- a/apps/tlon-web/src/groups/GangPreview/GangPreview.tsx +++ b/apps/tlon-web/src/groups/GangPreview/GangPreview.tsx @@ -1,4 +1,4 @@ -import { GroupPreview } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupPreview } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import GroupAvatar from '../GroupAvatar'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/GroupInfo.tsx b/apps/tlon-web/src/groups/GroupAdmin/GroupInfo.tsx index 2db5ec74d9..ef02408f24 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/GroupInfo.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/GroupInfo.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/GroupInfoEditor.tsx b/apps/tlon-web/src/groups/GroupAdmin/GroupInfoEditor.tsx index 0b669c0973..545762fb5e 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/GroupInfoEditor.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/GroupInfoEditor.tsx @@ -3,7 +3,7 @@ import { GroupMeta, PrivacyType, ViewProps, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import React, { useCallback } from 'react'; import { Helmet } from 'react-helmet'; import { FormProvider, useForm } from 'react-hook-form'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/GroupInfoFields.tsx b/apps/tlon-web/src/groups/GroupAdmin/GroupInfoFields.tsx index 1f7d1b2760..72b310887c 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/GroupInfoFields.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/GroupInfoFields.tsx @@ -1,4 +1,4 @@ -import { GroupMeta } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupMeta } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/GroupInvitesPrivacy.tsx b/apps/tlon-web/src/groups/GroupAdmin/GroupInvitesPrivacy.tsx index 77584d7d88..3a826f877c 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/GroupInvitesPrivacy.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/GroupInvitesPrivacy.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/GroupMemberItem.tsx b/apps/tlon-web/src/groups/GroupAdmin/GroupMemberItem.tsx index 161a85fc5e..cbca9d9593 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/GroupMemberItem.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/GroupMemberItem.tsx @@ -1,5 +1,5 @@ import * as Dropdown from '@radix-ui/react-dropdown-menu'; -import { Vessel } from '@tloncorp/shared/dist/urbit/groups'; +import { Vessel } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import _ from 'lodash'; import React, { useCallback, useRef, useState } from 'react'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/GroupMembers.tsx b/apps/tlon-web/src/groups/GroupAdmin/GroupMembers.tsx index 54ead7d199..4a0e903963 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/GroupMembers.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/GroupMembers.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/groups/GroupAdmin/PrivacySelector.tsx b/apps/tlon-web/src/groups/GroupAdmin/PrivacySelector.tsx index 353d2ce96e..b644189f2f 100644 --- a/apps/tlon-web/src/groups/GroupAdmin/PrivacySelector.tsx +++ b/apps/tlon-web/src/groups/GroupAdmin/PrivacySelector.tsx @@ -2,7 +2,7 @@ import { GroupFormSchema, GroupMeta, PrivacyType, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { useCallback } from 'react'; import { FormProvider, useForm, useFormContext } from 'react-hook-form'; diff --git a/apps/tlon-web/src/groups/GroupJoinList.tsx b/apps/tlon-web/src/groups/GroupJoinList.tsx index 0b950580c8..1459dc2f29 100644 --- a/apps/tlon-web/src/groups/GroupJoinList.tsx +++ b/apps/tlon-web/src/groups/GroupJoinList.tsx @@ -1,4 +1,4 @@ -import { Gang, Gangs } from '@tloncorp/shared/dist/urbit/groups'; +import { Gang, Gangs } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import LoadingSpinner from '@/components/LoadingSpinner/LoadingSpinner'; diff --git a/apps/tlon-web/src/groups/GroupSidebar/ChannelList.test.tsx b/apps/tlon-web/src/groups/GroupSidebar/ChannelList.test.tsx index e6893cb531..25b2b50da2 100644 --- a/apps/tlon-web/src/groups/GroupSidebar/ChannelList.test.tsx +++ b/apps/tlon-web/src/groups/GroupSidebar/ChannelList.test.tsx @@ -1,4 +1,4 @@ -import { Group } from '@tloncorp/shared/dist/urbit/groups'; +import { Group } from '@tloncorp/shared/urbit/groups'; import React from 'react'; import { describe, expect, it } from 'vitest'; diff --git a/apps/tlon-web/src/groups/GroupSidebar/ChannelList.tsx b/apps/tlon-web/src/groups/GroupSidebar/ChannelList.tsx index 630ce3946e..9be1639f36 100644 --- a/apps/tlon-web/src/groups/GroupSidebar/ChannelList.tsx +++ b/apps/tlon-web/src/groups/GroupSidebar/ChannelList.tsx @@ -1,4 +1,4 @@ -import { GroupChannel } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupChannel } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { useCallback, diff --git a/apps/tlon-web/src/groups/GroupSummary.tsx b/apps/tlon-web/src/groups/GroupSummary.tsx index a6bbfe4c12..403744c84e 100644 --- a/apps/tlon-web/src/groups/GroupSummary.tsx +++ b/apps/tlon-web/src/groups/GroupSummary.tsx @@ -1,4 +1,4 @@ -import { GroupPreview } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupPreview } from '@tloncorp/shared/urbit/groups'; import LoadingSpinner from '@/components/LoadingSpinner/LoadingSpinner'; import ShipConnection from '@/components/ShipConnection'; diff --git a/apps/tlon-web/src/groups/GroupVolumeDialog.tsx b/apps/tlon-web/src/groups/GroupVolumeDialog.tsx index c051365587..aac0d9c996 100644 --- a/apps/tlon-web/src/groups/GroupVolumeDialog.tsx +++ b/apps/tlon-web/src/groups/GroupVolumeDialog.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { Helmet } from 'react-helmet'; import Dialog from '@/components/Dialog'; diff --git a/apps/tlon-web/src/groups/LureAutojoiner.tsx b/apps/tlon-web/src/groups/LureAutojoiner.tsx index 103f57a46b..43766fc103 100644 --- a/apps/tlon-web/src/groups/LureAutojoiner.tsx +++ b/apps/tlon-web/src/groups/LureAutojoiner.tsx @@ -1,4 +1,4 @@ -import { Gangs } from '@tloncorp/shared/dist/urbit/groups'; +import { Gangs } from '@tloncorp/shared/urbit/groups'; import cookies from 'browser-cookies'; import { useCallback, useEffect } from 'react'; import { useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/groups/LureInviteBlock.tsx b/apps/tlon-web/src/groups/LureInviteBlock.tsx index aad9d2b429..e56821b640 100644 --- a/apps/tlon-web/src/groups/LureInviteBlock.tsx +++ b/apps/tlon-web/src/groups/LureInviteBlock.tsx @@ -1,4 +1,4 @@ -import { Group } from '@tloncorp/shared/dist/urbit/groups'; +import { Group } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import { useEffect } from 'react'; diff --git a/apps/tlon-web/src/groups/NewGroup/NewGroup.tsx b/apps/tlon-web/src/groups/NewGroup/NewGroup.tsx index 9d984ea7e4..404965937d 100644 --- a/apps/tlon-web/src/groups/NewGroup/NewGroup.tsx +++ b/apps/tlon-web/src/groups/NewGroup/NewGroup.tsx @@ -1,4 +1,4 @@ -import { Cordon, GroupFormSchema } from '@tloncorp/shared/dist/urbit/groups'; +import { Cordon, GroupFormSchema } from '@tloncorp/shared/urbit/groups'; import { ReactElement, useCallback, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/groups/NewGroup/NewGroupInvite.tsx b/apps/tlon-web/src/groups/NewGroup/NewGroupInvite.tsx index d01f4a4797..eae2fd6aaa 100644 --- a/apps/tlon-web/src/groups/NewGroup/NewGroupInvite.tsx +++ b/apps/tlon-web/src/groups/NewGroup/NewGroupInvite.tsx @@ -1,5 +1,5 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; -import { PrivacyType } from '@tloncorp/shared/dist/urbit/groups'; +import { PrivacyType } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import _ from 'lodash'; import React, { useCallback, useState } from 'react'; diff --git a/apps/tlon-web/src/groups/RoleInput/RoleSelector.tsx b/apps/tlon-web/src/groups/RoleInput/RoleSelector.tsx index b4060a82eb..a35b6cf2aa 100644 --- a/apps/tlon-web/src/groups/RoleInput/RoleSelector.tsx +++ b/apps/tlon-web/src/groups/RoleInput/RoleSelector.tsx @@ -1,4 +1,4 @@ -import { Vessel } from '@tloncorp/shared/dist/urbit/groups'; +import { Vessel } from '@tloncorp/shared/urbit/groups'; import { MouseEvent, useCallback, useState } from 'react'; import LoadingSpinner from '@/components/LoadingSpinner/LoadingSpinner'; diff --git a/apps/tlon-web/src/groups/useGroupJoin.ts b/apps/tlon-web/src/groups/useGroupJoin.ts index b622f1ed25..1afbdc6eb2 100644 --- a/apps/tlon-web/src/groups/useGroupJoin.ts +++ b/apps/tlon-web/src/groups/useGroupJoin.ts @@ -1,4 +1,4 @@ -import { Gang, Group, PrivacyType } from '@tloncorp/shared/dist/urbit/groups'; +import { Gang, Group, PrivacyType } from '@tloncorp/shared/urbit/groups'; import { useCallback, useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router'; diff --git a/apps/tlon-web/src/heap/EditCurioForm.tsx b/apps/tlon-web/src/heap/EditCurioForm.tsx index 62f8d5acbf..c53e6ead41 100644 --- a/apps/tlon-web/src/heap/EditCurioForm.tsx +++ b/apps/tlon-web/src/heap/EditCurioForm.tsx @@ -3,8 +3,8 @@ import { JSONContent } from '@tiptap/core'; import { chatStoryFromStory, storyFromChatStory, -} from '@tloncorp/shared/dist/urbit/channel'; -import { Inline } from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/channel'; +import { Inline } from '@tloncorp/shared/urbit/content'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useNavigate, useParams } from 'react-router'; diff --git a/apps/tlon-web/src/heap/HeapBlock.tsx b/apps/tlon-web/src/heap/HeapBlock.tsx index 339fd3d967..faa240343b 100644 --- a/apps/tlon-web/src/heap/HeapBlock.tsx +++ b/apps/tlon-web/src/heap/HeapBlock.tsx @@ -3,7 +3,7 @@ import { Story, imageUrlFromContent, isCite, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import { formatDistanceToNow } from 'date-fns'; import React, { useCallback, useEffect, useState } from 'react'; diff --git a/apps/tlon-web/src/heap/HeapChannel.tsx b/apps/tlon-web/src/heap/HeapChannel.tsx index 38fa8be454..d4ac61d370 100644 --- a/apps/tlon-web/src/heap/HeapChannel.tsx +++ b/apps/tlon-web/src/heap/HeapChannel.tsx @@ -1,6 +1,6 @@ import * as Toast from '@radix-ui/react-toast'; -import { Post, PostTuple } from '@tloncorp/shared/dist/urbit/channel'; -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { Post, PostTuple } from '@tloncorp/shared/urbit/channel'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import bigInt from 'big-integer'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/heap/HeapContent.tsx b/apps/tlon-web/src/heap/HeapContent.tsx index 339d5dfe0c..829a49d978 100644 --- a/apps/tlon-web/src/heap/HeapContent.tsx +++ b/apps/tlon-web/src/heap/HeapContent.tsx @@ -1,8 +1,4 @@ -import { - Story, - VerseBlock, - VerseInline, -} from '@tloncorp/shared/dist/urbit/channel'; +import { Story, VerseBlock, VerseInline } from '@tloncorp/shared/urbit/channel'; import { Inline, isBlockCode, @@ -14,7 +10,7 @@ import { isLink, isShip, isStrikethrough, -} from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/content'; import { ShipMention } from '@/chat/ChatContent/ChatContent'; import ContentReference from '@/components/References/ContentReference'; diff --git a/apps/tlon-web/src/heap/HeapDetail.tsx b/apps/tlon-web/src/heap/HeapDetail.tsx index 329cf6b0dc..a246a92ee2 100644 --- a/apps/tlon-web/src/heap/HeapDetail.tsx +++ b/apps/tlon-web/src/heap/HeapDetail.tsx @@ -1,5 +1,5 @@ -import { Post } from '@tloncorp/shared/dist/urbit/channel'; -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { Post } from '@tloncorp/shared/urbit/channel'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import bigInt from 'big-integer'; import cn from 'classnames'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/heap/HeapDetail/HeapDetailBody.tsx b/apps/tlon-web/src/heap/HeapDetail/HeapDetailBody.tsx index f6a584efe5..2a57a033e3 100644 --- a/apps/tlon-web/src/heap/HeapDetail/HeapDetailBody.tsx +++ b/apps/tlon-web/src/heap/HeapDetail/HeapDetailBody.tsx @@ -3,7 +3,7 @@ import { VerseBlock, imageUrlFromContent, isCite, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { useEffect } from 'react'; import LoadingSpinner from '@/components/LoadingSpinner/LoadingSpinner'; diff --git a/apps/tlon-web/src/heap/HeapDetail/HeapDetailHeader.tsx b/apps/tlon-web/src/heap/HeapDetail/HeapDetailHeader.tsx index 7cde6e480e..299296ad7f 100644 --- a/apps/tlon-web/src/heap/HeapDetail/HeapDetailHeader.tsx +++ b/apps/tlon-web/src/heap/HeapDetail/HeapDetailHeader.tsx @@ -1,8 +1,5 @@ -import { - PostEssay, - chatStoryFromStory, -} from '@tloncorp/shared/dist/urbit/channel'; -import { isLink } from '@tloncorp/shared/dist/urbit/content'; +import { PostEssay, chatStoryFromStory } from '@tloncorp/shared/urbit/channel'; +import { isLink } from '@tloncorp/shared/urbit/content'; import cn from 'classnames'; import { Link } from 'react-router-dom'; diff --git a/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailComments.tsx b/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailComments.tsx index 71aee5937e..2fae1ceb3f 100644 --- a/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailComments.tsx +++ b/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailComments.tsx @@ -1,5 +1,5 @@ -import { MessageKey } from '@tloncorp/shared/dist/urbit/activity'; -import { ReplyTuple } from '@tloncorp/shared/dist/urbit/channel'; +import { MessageKey } from '@tloncorp/shared/urbit/activity'; +import { ReplyTuple } from '@tloncorp/shared/urbit/channel'; import bigInt from 'big-integer'; import { useMemo } from 'react'; import { useLocation } from 'react-router-dom'; diff --git a/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailSidebarInfo.tsx b/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailSidebarInfo.tsx index b4f882db9c..6f10d6c4dc 100644 --- a/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailSidebarInfo.tsx +++ b/apps/tlon-web/src/heap/HeapDetail/HeapDetailSidebar/HeapDetailSidebarInfo.tsx @@ -1,4 +1,4 @@ -import { PostEssay } from '@tloncorp/shared/dist/urbit/channel'; +import { PostEssay } from '@tloncorp/shared/urbit/channel'; import Author from '@/chat/ChatMessage/Author'; import getKindDataFromEssay from '@/logic/getKindData'; diff --git a/apps/tlon-web/src/heap/HeapHeader.tsx b/apps/tlon-web/src/heap/HeapHeader.tsx index f6d0893f15..fdd009a15a 100644 --- a/apps/tlon-web/src/heap/HeapHeader.tsx +++ b/apps/tlon-web/src/heap/HeapHeader.tsx @@ -1,5 +1,5 @@ import * as Dropdown from '@radix-ui/react-dropdown-menu'; -import { DisplayMode, SortMode } from '@tloncorp/shared/dist/urbit/channel'; +import { DisplayMode, SortMode } from '@tloncorp/shared/urbit/channel'; import cn from 'classnames'; import React, { useEffect, useState } from 'react'; diff --git a/apps/tlon-web/src/heap/HeapRow.tsx b/apps/tlon-web/src/heap/HeapRow.tsx index 0878ae75c9..244904e2ae 100644 --- a/apps/tlon-web/src/heap/HeapRow.tsx +++ b/apps/tlon-web/src/heap/HeapRow.tsx @@ -3,7 +3,7 @@ import { Story, VerseBlock, imageUrlFromContent, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { daToUnix } from '@urbit/api'; import bigInt from 'big-integer'; import cn from 'classnames'; diff --git a/apps/tlon-web/src/heap/HeapTextInput.tsx b/apps/tlon-web/src/heap/HeapTextInput.tsx index 3d1711746a..cf6ac4f98c 100644 --- a/apps/tlon-web/src/heap/HeapTextInput.tsx +++ b/apps/tlon-web/src/heap/HeapTextInput.tsx @@ -1,6 +1,6 @@ import { Editor, JSONContent } from '@tiptap/react'; -import { PostEssay, constructStory } from '@tloncorp/shared/dist/urbit/channel'; -import { Inline, InlineKey } from '@tloncorp/shared/dist/urbit/content'; +import { PostEssay, constructStory } from '@tloncorp/shared/urbit/channel'; +import { Inline, InlineKey } from '@tloncorp/shared/urbit/content'; import cn from 'classnames'; import { reduce } from 'lodash'; import React, { useCallback, useEffect } from 'react'; diff --git a/apps/tlon-web/src/logic/analytics.ts b/apps/tlon-web/src/logic/analytics.ts index 22c74b4d49..35cf405f91 100644 --- a/apps/tlon-web/src/logic/analytics.ts +++ b/apps/tlon-web/src/logic/analytics.ts @@ -1,4 +1,4 @@ -import { PrivacyType } from '@tloncorp/shared/dist/urbit/groups'; +import { PrivacyType } from '@tloncorp/shared/urbit/groups'; import posthog, { Properties } from 'posthog-js'; import { isNativeApp } from './native'; diff --git a/apps/tlon-web/src/logic/channel.ts b/apps/tlon-web/src/logic/channel.ts index 8453acd3cc..bd7d314d37 100644 --- a/apps/tlon-web/src/logic/channel.ts +++ b/apps/tlon-web/src/logic/channel.ts @@ -1,17 +1,13 @@ -import { - Activity, - MessageKey, - Source, -} from '@tloncorp/shared/dist/urbit/activity'; -import { Perm, Story } from '@tloncorp/shared/dist/urbit/channel'; -import { isLink } from '@tloncorp/shared/dist/urbit/content'; +import { Activity, MessageKey, Source } from '@tloncorp/shared/urbit/activity'; +import { Perm, Story } from '@tloncorp/shared/urbit/channel'; +import { isLink } from '@tloncorp/shared/urbit/content'; import { Channels, Group, GroupChannel, Vessel, Zone, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import _, { get, groupBy } from 'lodash'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router'; diff --git a/apps/tlon-web/src/logic/getKindData.ts b/apps/tlon-web/src/logic/getKindData.ts index 6a8548d611..e7455488b5 100644 --- a/apps/tlon-web/src/logic/getKindData.ts +++ b/apps/tlon-web/src/logic/getKindData.ts @@ -1,4 +1,4 @@ -import { PostEssay } from '@tloncorp/shared/dist/urbit/channel'; +import { PostEssay } from '@tloncorp/shared/urbit/channel'; export default function getKindDataFromEssay(essay: PostEssay | undefined): { title: string; diff --git a/apps/tlon-web/src/logic/heap.ts b/apps/tlon-web/src/logic/heap.ts index 2b4833a75b..d0d931e528 100644 --- a/apps/tlon-web/src/logic/heap.ts +++ b/apps/tlon-web/src/logic/heap.ts @@ -1,11 +1,8 @@ /* eslint-disable */ import { JSONContent } from '@tiptap/core'; -import { - PostEssay, - storyFromChatStory, -} from '@tloncorp/shared/dist/urbit/channel'; -import { ChatStory } from '@tloncorp/shared/dist/urbit/channel'; -import { Inline, InlineKey } from '@tloncorp/shared/dist/urbit/content'; +import { PostEssay, storyFromChatStory } from '@tloncorp/shared/urbit/channel'; +import { ChatStory } from '@tloncorp/shared/urbit/channel'; +import { Inline, InlineKey } from '@tloncorp/shared/urbit/content'; import { reduce } from 'lodash'; import isURL from 'validator/lib/isURL'; diff --git a/apps/tlon-web/src/logic/messageSender.ts b/apps/tlon-web/src/logic/messageSender.ts index 5d8aea68e0..233d81c04c 100644 --- a/apps/tlon-web/src/logic/messageSender.ts +++ b/apps/tlon-web/src/logic/messageSender.ts @@ -7,7 +7,7 @@ import { Nest, PostEssay, constructStory, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { SendMessageVariables, SendReplyVariables } from '@/state/chat'; import { buildAddDelta, createMessage } from '@/state/chat/utils'; diff --git a/apps/tlon-web/src/logic/tiptap.test.ts b/apps/tlon-web/src/logic/tiptap.test.ts index b7516b3900..98c9d86eff 100644 --- a/apps/tlon-web/src/logic/tiptap.test.ts +++ b/apps/tlon-web/src/logic/tiptap.test.ts @@ -1,6 +1,6 @@ import { JSONContent } from '@tiptap/react'; -import { Block } from '@tloncorp/shared/dist/urbit/channel'; -import { Inline } from '@tloncorp/shared/dist/urbit/content'; +import { Block } from '@tloncorp/shared/urbit/channel'; +import { Inline } from '@tloncorp/shared/urbit/content'; import { describe, expect, it } from 'vitest'; import { diff --git a/apps/tlon-web/src/logic/tiptap.ts b/apps/tlon-web/src/logic/tiptap.ts index df09824fab..50a1e82e1d 100644 --- a/apps/tlon-web/src/logic/tiptap.ts +++ b/apps/tlon-web/src/logic/tiptap.ts @@ -11,7 +11,7 @@ import { HeaderLevel, Listing, Story, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { Inline, InlineKey, @@ -24,7 +24,7 @@ import { isLink, isShip, isStrikethrough, -} from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/content'; import { deSig } from '@urbit/api'; import { isEqual, reduce } from 'lodash'; diff --git a/apps/tlon-web/src/logic/useGroupSort.ts b/apps/tlon-web/src/logic/useGroupSort.ts index 651cb4793d..0db93fe6e6 100644 --- a/apps/tlon-web/src/logic/useGroupSort.ts +++ b/apps/tlon-web/src/logic/useGroupSort.ts @@ -1,4 +1,4 @@ -import { Group, Groups } from '@tloncorp/shared/dist/urbit/groups'; +import { Group, Groups } from '@tloncorp/shared/urbit/groups'; import { get } from 'lodash'; import { useCallback, useMemo } from 'react'; diff --git a/apps/tlon-web/src/logic/useIsGroupUnread.ts b/apps/tlon-web/src/logic/useIsGroupUnread.ts index a1cfd1bf76..fc5ca53c18 100644 --- a/apps/tlon-web/src/logic/useIsGroupUnread.ts +++ b/apps/tlon-web/src/logic/useIsGroupUnread.ts @@ -1,4 +1,4 @@ -import { ActivitySummary } from '@tloncorp/shared/dist/urbit'; +import { ActivitySummary } from '@tloncorp/shared/urbit'; import { useCallback } from 'react'; import { emptySummary, useActivity } from '@/state/activity'; diff --git a/apps/tlon-web/src/logic/useMessageSort.ts b/apps/tlon-web/src/logic/useMessageSort.ts index 2e1c2a8b2a..2d24901f12 100644 --- a/apps/tlon-web/src/logic/useMessageSort.ts +++ b/apps/tlon-web/src/logic/useMessageSort.ts @@ -1,4 +1,4 @@ -import { ActivitySummary } from '@tloncorp/shared/dist/urbit'; +import { ActivitySummary } from '@tloncorp/shared/urbit'; import { RECENT_SORT } from '@/constants'; diff --git a/apps/tlon-web/src/logic/useScrollerMessages.ts b/apps/tlon-web/src/logic/useScrollerMessages.ts index 7dd27b216b..c07d832cb9 100644 --- a/apps/tlon-web/src/logic/useScrollerMessages.ts +++ b/apps/tlon-web/src/logic/useScrollerMessages.ts @@ -1,6 +1,6 @@ -import { MessageKey } from '@tloncorp/shared/dist/urbit/activity'; -import { Post, Reply } from '@tloncorp/shared/dist/urbit/channel'; -import { Writ } from '@tloncorp/shared/dist/urbit/dms'; +import { MessageKey } from '@tloncorp/shared/urbit/activity'; +import { Post, Reply } from '@tloncorp/shared/urbit/channel'; +import { Writ } from '@tloncorp/shared/urbit/dms'; import { daToUnix } from '@urbit/api'; import bigInt, { BigInteger } from 'big-integer'; import { useMemo, useRef } from 'react'; diff --git a/apps/tlon-web/src/logic/useStickyUnread.ts b/apps/tlon-web/src/logic/useStickyUnread.ts index cb65268f76..d982f47d51 100644 --- a/apps/tlon-web/src/logic/useStickyUnread.ts +++ b/apps/tlon-web/src/logic/useStickyUnread.ts @@ -1,4 +1,4 @@ -import { ActivitySummary } from '@tloncorp/shared/dist/urbit'; +import { ActivitySummary } from '@tloncorp/shared/urbit'; import { useEffect, useRef, useState } from 'react'; const READ_DELAY = 15_000; // 15 seconds diff --git a/apps/tlon-web/src/logic/utils.ts b/apps/tlon-web/src/logic/utils.ts index a4d3a7bf0c..431f82519c 100644 --- a/apps/tlon-web/src/logic/utils.ts +++ b/apps/tlon-web/src/logic/utils.ts @@ -1,4 +1,4 @@ -import { MessageKey } from '@tloncorp/shared/dist/urbit/activity'; +import { MessageKey } from '@tloncorp/shared/urbit/activity'; import { CacheId, ChatStory, @@ -9,13 +9,13 @@ import { Verse, VerseBlock, VerseInline, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { Bold, Inline, Italics, Strikethrough, -} from '@tloncorp/shared/dist/urbit/content'; +} from '@tloncorp/shared/urbit/content'; import { Cabals, ChannelPrivacyType, @@ -27,7 +27,7 @@ import { PrivacyType, Rank, Saga, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import { BigIntOrderedMap, Docket, diff --git a/apps/tlon-web/src/mocks/chat.ts b/apps/tlon-web/src/mocks/chat.ts index 1b50f5b779..26e0766dc9 100644 --- a/apps/tlon-web/src/mocks/chat.ts +++ b/apps/tlon-web/src/mocks/chat.ts @@ -1,11 +1,11 @@ import { faker } from '@faker-js/faker'; -import { Activity } from '@tloncorp/shared/dist/urbit/activity'; +import { Activity } from '@tloncorp/shared/urbit/activity'; import { Post, Posts, Story, storyFromChatStory, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { decToUd, unixToDa } from '@urbit/api'; import { subDays, subMinutes } from 'date-fns'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/mocks/groups.ts b/apps/tlon-web/src/mocks/groups.ts index 43ab5ad138..0e42255ca5 100644 --- a/apps/tlon-web/src/mocks/groups.ts +++ b/apps/tlon-web/src/mocks/groups.ts @@ -8,7 +8,7 @@ import { GroupPreview, PrivacyType, Vessel, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import { AUTHORS } from '@/constants'; import { randomElement } from '@/logic/utils'; diff --git a/apps/tlon-web/src/mocks/handlers.ts b/apps/tlon-web/src/mocks/handlers.ts index eef5db1aa2..d518ab3acc 100644 --- a/apps/tlon-web/src/mocks/handlers.ts +++ b/apps/tlon-web/src/mocks/handlers.ts @@ -16,8 +16,8 @@ import { DMWhom, DmRsvp, WritDiff, -} from '@tloncorp/shared/dist/urbit/dms'; -import { GroupAction } from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/dms'; +import { GroupAction } from '@tloncorp/shared/urbit/groups'; import { decToUd, udToDec, unixToDa } from '@urbit/api'; import bigInt from 'big-integer'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/mocks/heaps.ts b/apps/tlon-web/src/mocks/heaps.ts index 75ca19ea08..f4c94a4ff2 100644 --- a/apps/tlon-web/src/mocks/heaps.ts +++ b/apps/tlon-web/src/mocks/heaps.ts @@ -3,7 +3,7 @@ import { ScryHandler, SubscriptionHandler, } from '@tloncorp/mock-http-api'; -import { Channels, Perm, Posts } from '@tloncorp/shared/dist/urbit/channel'; +import { Channels, Perm, Posts } from '@tloncorp/shared/urbit/channel'; import { subMinutes } from 'date-fns'; const unixTime = subMinutes(new Date(), 1).getTime(); diff --git a/apps/tlon-web/src/notifications/ActivitySummary.tsx b/apps/tlon-web/src/notifications/ActivitySummary.tsx index a8da6937b8..80972411ee 100644 --- a/apps/tlon-web/src/notifications/ActivitySummary.tsx +++ b/apps/tlon-web/src/notifications/ActivitySummary.tsx @@ -4,7 +4,7 @@ import { ActivityRelevancy, getAuthor, getChannelKind, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import React, { PropsWithChildren, useMemo } from 'react'; import ShipName from '@/components/ShipName'; diff --git a/apps/tlon-web/src/notifications/DMNotification.tsx b/apps/tlon-web/src/notifications/DMNotification.tsx index 7517e87d89..66fa628923 100644 --- a/apps/tlon-web/src/notifications/DMNotification.tsx +++ b/apps/tlon-web/src/notifications/DMNotification.tsx @@ -1,10 +1,10 @@ -import { makePrettyTime } from '@tloncorp/shared/dist'; +import { makePrettyTime } from '@tloncorp/shared'; import { ActivityBundle, ActivityEvent, ActivityRelevancy, Story, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import React from 'react'; import { Link } from 'react-router-dom'; diff --git a/apps/tlon-web/src/notifications/GroupNotification.tsx b/apps/tlon-web/src/notifications/GroupNotification.tsx index 73f8b153fd..31f2a0912b 100644 --- a/apps/tlon-web/src/notifications/GroupNotification.tsx +++ b/apps/tlon-web/src/notifications/GroupNotification.tsx @@ -1,4 +1,4 @@ -import { makePrettyTime } from '@tloncorp/shared/dist'; +import { makePrettyTime } from '@tloncorp/shared'; import { ActivityBundle, ActivityEvent, @@ -11,7 +11,7 @@ import { isJoin, isLeave, isRoleChange, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import React from 'react'; import { Link } from 'react-router-dom'; diff --git a/apps/tlon-web/src/notifications/Notification.tsx b/apps/tlon-web/src/notifications/Notification.tsx index eafa3ce254..44b5f0a135 100644 --- a/apps/tlon-web/src/notifications/Notification.tsx +++ b/apps/tlon-web/src/notifications/Notification.tsx @@ -9,7 +9,7 @@ import { getSource, getTop, nestToFlag, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import { daToUnix, parseUd } from '@urbit/aura'; import _ from 'lodash'; import React, { useCallback } from 'react'; diff --git a/apps/tlon-web/src/notifications/Notifications.tsx b/apps/tlon-web/src/notifications/Notifications.tsx index a08cfafd8e..bc770070e0 100644 --- a/apps/tlon-web/src/notifications/Notifications.tsx +++ b/apps/tlon-web/src/notifications/Notifications.tsx @@ -1,5 +1,5 @@ -import { ActivityBundle, ActivitySummary } from '@tloncorp/shared/dist/urbit'; -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ActivityBundle, ActivitySummary } from '@tloncorp/shared/urbit'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import { PropsWithChildren, useCallback, useEffect } from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/profiles/EditProfile/EditProfile.tsx b/apps/tlon-web/src/profiles/EditProfile/EditProfile.tsx index 143409c1c8..9ab7f80170 100644 --- a/apps/tlon-web/src/profiles/EditProfile/EditProfile.tsx +++ b/apps/tlon-web/src/profiles/EditProfile/EditProfile.tsx @@ -3,8 +3,8 @@ import { ContactAddGroup, ContactDelGroup, ContactEditField, -} from '@tloncorp/shared/dist/urbit/contact'; -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/contact'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import _ from 'lodash'; import React, { useCallback, useEffect, useState } from 'react'; diff --git a/apps/tlon-web/src/profiles/Profile.tsx b/apps/tlon-web/src/profiles/Profile.tsx index 5882785fb2..7a92578c78 100644 --- a/apps/tlon-web/src/profiles/Profile.tsx +++ b/apps/tlon-web/src/profiles/Profile.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import { Helmet } from 'react-helmet'; import { Outlet } from 'react-router-dom'; diff --git a/apps/tlon-web/src/profiles/ShareDMLure.tsx b/apps/tlon-web/src/profiles/ShareDMLure.tsx index fd8c25291b..09fc9e817f 100644 --- a/apps/tlon-web/src/profiles/ShareDMLure.tsx +++ b/apps/tlon-web/src/profiles/ShareDMLure.tsx @@ -1,4 +1,4 @@ -import { ViewProps } from '@tloncorp/shared/dist/urbit/groups'; +import { ViewProps } from '@tloncorp/shared/urbit/groups'; import { useEffect, useState } from 'react'; import { Helmet } from 'react-helmet'; diff --git a/apps/tlon-web/src/replies/ReplyMessage.tsx b/apps/tlon-web/src/replies/ReplyMessage.tsx index d111aaf4d8..e5e11d1ff5 100644 --- a/apps/tlon-web/src/replies/ReplyMessage.tsx +++ b/apps/tlon-web/src/replies/ReplyMessage.tsx @@ -1,16 +1,16 @@ import { Editor } from '@tiptap/core'; -import { MessageKey } from '@tloncorp/shared/dist/urbit'; +import { MessageKey } from '@tloncorp/shared/urbit'; import { getChannelSource, getDmSource, getThreadKey, -} from '@tloncorp/shared/dist/urbit/activity'; +} from '@tloncorp/shared/urbit/activity'; import { Reply, Story, constructStory, emptyReply, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { daToUnix } from '@urbit/api'; import { formatUd } from '@urbit/aura'; import bigInt, { BigInteger } from 'big-integer'; diff --git a/apps/tlon-web/src/replies/ReplyMessageOptions.tsx b/apps/tlon-web/src/replies/ReplyMessageOptions.tsx index f5dfebb725..10624b86fa 100644 --- a/apps/tlon-web/src/replies/ReplyMessageOptions.tsx +++ b/apps/tlon-web/src/replies/ReplyMessageOptions.tsx @@ -1,4 +1,4 @@ -import { Reply, emptyReply } from '@tloncorp/shared/dist/urbit/channel'; +import { Reply, emptyReply } from '@tloncorp/shared/urbit/channel'; import { decToUd } from '@urbit/api'; import cn from 'classnames'; import { useCallback, useEffect, useMemo } from 'react'; diff --git a/apps/tlon-web/src/replies/ReplyReactions/ReplyReactions.tsx b/apps/tlon-web/src/replies/ReplyReactions/ReplyReactions.tsx index 81a8d090eb..abaac3dd78 100644 --- a/apps/tlon-web/src/replies/ReplyReactions/ReplyReactions.tsx +++ b/apps/tlon-web/src/replies/ReplyReactions/ReplyReactions.tsx @@ -1,4 +1,4 @@ -import { ReplySeal } from '@tloncorp/shared/dist/urbit/channel'; +import { ReplySeal } from '@tloncorp/shared/urbit/channel'; import _ from 'lodash'; import { useCallback, useState } from 'react'; diff --git a/apps/tlon-web/src/replies/replies.ts b/apps/tlon-web/src/replies/replies.ts index 655a3f11fe..b2c8446129 100644 --- a/apps/tlon-web/src/replies/replies.ts +++ b/apps/tlon-web/src/replies/replies.ts @@ -1,8 +1,5 @@ -import { - ActivitySummary, - MessageKey, -} from '@tloncorp/shared/dist/urbit/activity'; -import { Kind, Reply, ReplyTuple } from '@tloncorp/shared/dist/urbit/channel'; +import { ActivitySummary, MessageKey } from '@tloncorp/shared/urbit/activity'; +import { Kind, Reply, ReplyTuple } from '@tloncorp/shared/urbit/channel'; import { daToUnix, parseUd } from '@urbit/aura'; import bigInt, { BigInteger } from 'big-integer'; import { isSameDay } from 'date-fns'; diff --git a/apps/tlon-web/src/state/activity.ts b/apps/tlon-web/src/state/activity.ts index dd692b8645..1db0c1b878 100644 --- a/apps/tlon-web/src/state/activity.ts +++ b/apps/tlon-web/src/state/activity.ts @@ -19,7 +19,7 @@ import { getThreadKey, sourceToString, stripSourcePrefix, -} from '@tloncorp/shared/dist/urbit/activity'; +} from '@tloncorp/shared/urbit/activity'; import _ from 'lodash'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; diff --git a/apps/tlon-web/src/state/bootstrap.ts b/apps/tlon-web/src/state/bootstrap.ts index 46adf7906e..53eb65b5d0 100644 --- a/apps/tlon-web/src/state/bootstrap.ts +++ b/apps/tlon-web/src/state/bootstrap.ts @@ -1,4 +1,4 @@ -import { GroupsInit4 } from '@tloncorp/shared/dist/urbit/ui'; +import { GroupsInit4 } from '@tloncorp/shared/urbit/ui'; import Urbit from '@urbit/http-api'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/state/broadcasts.ts b/apps/tlon-web/src/state/broadcasts.ts index e06de3f99d..7401d37ca2 100644 --- a/apps/tlon-web/src/state/broadcasts.ts +++ b/apps/tlon-web/src/state/broadcasts.ts @@ -4,8 +4,8 @@ import { Inline, Story, WritEssay, -} from '@tloncorp/shared/dist/urbit'; -import { WritTuple } from '@tloncorp/shared/dist/urbit/dms'; +} from '@tloncorp/shared/urbit'; +import { WritTuple } from '@tloncorp/shared/urbit/dms'; import { daToDate, unixToDa } from '@urbit/api'; import api from '@/api'; diff --git a/apps/tlon-web/src/state/channel/channel.ts b/apps/tlon-web/src/state/channel/channel.ts index bdd2217026..1df4054c90 100644 --- a/apps/tlon-web/src/state/channel/channel.ts +++ b/apps/tlon-web/src/state/channel/channel.ts @@ -33,9 +33,9 @@ import { TogglePost, newChatMap, newPostTupleArray, -} from '@tloncorp/shared/dist/urbit/channel'; -import { PagedWrits, Writ } from '@tloncorp/shared/dist/urbit/dms'; -import { Flag } from '@tloncorp/shared/dist/urbit/hark'; +} from '@tloncorp/shared/urbit/channel'; +import { PagedWrits, Writ } from '@tloncorp/shared/urbit/dms'; +import { Flag } from '@tloncorp/shared/urbit/hark'; import { daToUnix, decToUd, udToDec, unixToDa } from '@urbit/api'; import { formatUd } from '@urbit/aura'; import { Poke } from '@urbit/http-api'; diff --git a/apps/tlon-web/src/state/channel/util.ts b/apps/tlon-web/src/state/channel/util.ts index 137ff366a3..6f1a747b2f 100644 --- a/apps/tlon-web/src/state/channel/util.ts +++ b/apps/tlon-web/src/state/channel/util.ts @@ -1,4 +1,4 @@ -import { PagedPosts } from '@tloncorp/shared/dist/urbit/channel'; +import { PagedPosts } from '@tloncorp/shared/urbit/channel'; type QueryData = { pages: PagedPosts[]; diff --git a/apps/tlon-web/src/state/chat/chat.ts b/apps/tlon-web/src/state/chat/chat.ts index 2398808ac6..af0f3233f2 100644 --- a/apps/tlon-web/src/state/chat/chat.ts +++ b/apps/tlon-web/src/state/chat/chat.ts @@ -1,16 +1,12 @@ import { QueryKey, useInfiniteQuery, useMutation } from '@tanstack/react-query'; -import { - MessageKey, - Source, - getKey, -} from '@tloncorp/shared/dist/urbit/activity'; +import { MessageKey, Source, getKey } from '@tloncorp/shared/urbit/activity'; import { CacheId, ChannelsAction, Replies, Reply, ReplyTuple, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { BlockedByShips, BlockedShips, @@ -36,8 +32,8 @@ import { WritSeal, Writs, newWritTupleArray, -} from '@tloncorp/shared/dist/urbit/dms'; -import { GroupMeta } from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/dms'; +import { GroupMeta } from '@tloncorp/shared/urbit/groups'; import { decToUd, udToDec } from '@urbit/api'; import { formatUd, unixToDa } from '@urbit/aura'; import { Poke } from '@urbit/http-api'; diff --git a/apps/tlon-web/src/state/chat/search.ts b/apps/tlon-web/src/state/chat/search.ts index af7f0cbd4b..6d4aee130c 100644 --- a/apps/tlon-web/src/state/chat/search.ts +++ b/apps/tlon-web/src/state/chat/search.ts @@ -3,7 +3,7 @@ import { ChatMap, ReplyTuple, newChatMap, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { ChatScam, ChatScan, @@ -11,7 +11,7 @@ import { Writ, WritTuple, newWritMap, -} from '@tloncorp/shared/dist/urbit/dms'; +} from '@tloncorp/shared/urbit/dms'; import { decToUd } from '@urbit/api'; import { daToUnix } from '@urbit/aura'; import bigInt from 'big-integer'; diff --git a/apps/tlon-web/src/state/chat/utils.ts b/apps/tlon-web/src/state/chat/utils.ts index 4f8466e1f0..421fe5ab51 100644 --- a/apps/tlon-web/src/state/chat/utils.ts +++ b/apps/tlon-web/src/state/chat/utils.ts @@ -6,7 +6,7 @@ import { Reply, ReplyMeta, ReplyTuple, -} from '@tloncorp/shared/dist/urbit/channel'; +} from '@tloncorp/shared/urbit/channel'; import { Club, DMUnreads, @@ -17,7 +17,7 @@ import { WritInCache, WritMemo, WritSeal, -} from '@tloncorp/shared/dist/urbit/dms'; +} from '@tloncorp/shared/urbit/dms'; import { udToDec } from '@urbit/api'; import { formatUd, unixToDa } from '@urbit/aura'; import bigInt from 'big-integer'; diff --git a/apps/tlon-web/src/state/contact.ts b/apps/tlon-web/src/state/contact.ts index e83eabe36b..3a244b374e 100644 --- a/apps/tlon-web/src/state/contact.ts +++ b/apps/tlon-web/src/state/contact.ts @@ -6,7 +6,7 @@ import { ContactHeed, ContactNews, ContactRolodex, -} from '@tloncorp/shared/dist/urbit/contact'; +} from '@tloncorp/shared/urbit/contact'; import { Patp, preSig } from '@urbit/api'; import produce from 'immer'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/state/groups/groups.ts b/apps/tlon-web/src/state/groups/groups.ts index 99e989478e..c6dc8720eb 100644 --- a/apps/tlon-web/src/state/groups/groups.ts +++ b/apps/tlon-web/src/state/groups/groups.ts @@ -4,7 +4,7 @@ import { useMutation, useQueryClient, } from '@tanstack/react-query'; -import { BaitCite, Post, Reply } from '@tloncorp/shared/dist/urbit/channel'; +import { BaitCite, Post, Reply } from '@tloncorp/shared/urbit/channel'; import { ChannelPreview, Cordon, @@ -23,8 +23,8 @@ import { PrivacyType, Vessel, isGroup, -} from '@tloncorp/shared/dist/urbit/groups'; -import { Scope, VolumeValue } from '@tloncorp/shared/dist/urbit/volume'; +} from '@tloncorp/shared/urbit/groups'; +import { Scope, VolumeValue } from '@tloncorp/shared/urbit/volume'; import { decToUd } from '@urbit/api'; import { Poke } from '@urbit/http-api'; import _ from 'lodash'; diff --git a/apps/tlon-web/src/state/groups/groupsReducer.ts b/apps/tlon-web/src/state/groups/groupsReducer.ts index 26ba4a3291..39ba679685 100644 --- a/apps/tlon-web/src/state/groups/groupsReducer.ts +++ b/apps/tlon-web/src/state/groups/groupsReducer.ts @@ -5,7 +5,7 @@ import { Group, GroupDiff, GroupUpdate, -} from '@tloncorp/shared/dist/urbit/groups'; +} from '@tloncorp/shared/urbit/groups'; import { GroupState } from './type'; diff --git a/apps/tlon-web/src/state/groups/type.ts b/apps/tlon-web/src/state/groups/type.ts index f12fd572a2..717d608045 100644 --- a/apps/tlon-web/src/state/groups/type.ts +++ b/apps/tlon-web/src/state/groups/type.ts @@ -1,4 +1,4 @@ -import { BaitCite } from '@tloncorp/shared/dist/urbit/channel'; +import { BaitCite } from '@tloncorp/shared/urbit/channel'; import { ChannelPreview, Cordon, @@ -8,8 +8,8 @@ import { GroupIndex, GroupMeta, Rank, -} from '@tloncorp/shared/dist/urbit/groups'; -import { GroupsInit } from '@tloncorp/shared/dist/urbit/ui'; +} from '@tloncorp/shared/urbit/groups'; +import { GroupsInit } from '@tloncorp/shared/urbit/ui'; export interface GroupState { set: (fn: (sta: GroupState) => void) => void; diff --git a/apps/tlon-web/src/state/hark.ts b/apps/tlon-web/src/state/hark.ts index c11837c51e..e648fe5dd5 100644 --- a/apps/tlon-web/src/state/hark.ts +++ b/apps/tlon-web/src/state/hark.ts @@ -10,7 +10,7 @@ import { Seam, Skein, Yarn, -} from '@tloncorp/shared/dist/urbit/hark'; +} from '@tloncorp/shared/urbit/hark'; import { decToUd } from '@urbit/api'; import api from '@/api'; diff --git a/apps/tlon-web/src/state/lure/lure.ts b/apps/tlon-web/src/state/lure/lure.ts index 3141e79241..9a062381ce 100644 --- a/apps/tlon-web/src/state/lure/lure.ts +++ b/apps/tlon-web/src/state/lure/lure.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; -import { GroupMeta } from '@tloncorp/shared/dist/urbit/groups'; +import { GroupMeta } from '@tloncorp/shared/urbit/groups'; import produce from 'immer'; -import { Contact } from 'packages/shared/dist/urbit'; +import { Contact } from 'packages/shared/urbit'; import { useCallback, useEffect, useMemo, useRef } from 'react'; import create from 'zustand'; import { persist } from 'zustand/middleware'; diff --git a/apps/tlon-web/src/state/negotiation.ts b/apps/tlon-web/src/state/negotiation.ts index 9b3eaf1134..12085475c4 100644 --- a/apps/tlon-web/src/state/negotiation.ts +++ b/apps/tlon-web/src/state/negotiation.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'; import { MatchingEvent, MatchingResponse, -} from '@tloncorp/shared/dist/urbit/negotiation'; +} from '@tloncorp/shared/urbit/negotiation'; import { debounce } from 'lodash'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; diff --git a/apps/tlon-web/src/state/pins.ts b/apps/tlon-web/src/state/pins.ts index 78bf20d617..a5e4904159 100644 --- a/apps/tlon-web/src/state/pins.ts +++ b/apps/tlon-web/src/state/pins.ts @@ -1,5 +1,5 @@ import { useMutation } from '@tanstack/react-query'; -import { Nest } from '@tloncorp/shared/dist/urbit/channel'; +import { Nest } from '@tloncorp/shared/urbit/channel'; import _ from 'lodash'; import { useMemo } from 'react'; diff --git a/apps/tlon-web/src/state/settings.ts b/apps/tlon-web/src/state/settings.ts index 14bf0b5956..472f1ba072 100644 --- a/apps/tlon-web/src/state/settings.ts +++ b/apps/tlon-web/src/state/settings.ts @@ -1,5 +1,5 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { DisplayMode, SortMode } from '@tloncorp/shared/dist/urbit/channel'; +import { DisplayMode, SortMode } from '@tloncorp/shared/urbit/channel'; import { DelBucket, DelEntry, PutBucket, Value } from '@urbit/api'; import cookies from 'browser-cookies'; import produce from 'immer'; diff --git a/apps/tlon-web/src/window.ts b/apps/tlon-web/src/window.ts index 05952c2228..5a950dc1a4 100644 --- a/apps/tlon-web/src/window.ts +++ b/apps/tlon-web/src/window.ts @@ -1,5 +1,5 @@ import type { NativeWebViewOptions } from '@tloncorp/shared'; -import { Rope } from '@tloncorp/shared/dist/urbit/hark'; +import { Rope } from '@tloncorp/shared/urbit/hark'; declare global { interface Window { diff --git a/apps/tlon-web/tsconfig.json b/apps/tlon-web/tsconfig.json index 516d8fd4b8..f47c19042b 100644 --- a/apps/tlon-web/tsconfig.json +++ b/apps/tlon-web/tsconfig.json @@ -5,7 +5,7 @@ "experimentalDecorators": true, "strict": true, "module": "ESNext", - "moduleResolution": "Node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, diff --git a/packages/app/contexts/branch.tsx b/packages/app/contexts/branch.tsx index b77e49c902..51d6589eeb 100644 --- a/packages/app/contexts/branch.tsx +++ b/packages/app/contexts/branch.tsx @@ -1,5 +1,5 @@ -import { DeepLinkMetadata, createDevLogger } from '@tloncorp/shared/dist'; -import { DeepLinkData, extractLureMetadata } from '@tloncorp/shared/src/logic'; +import { DeepLinkMetadata, createDevLogger } from '@tloncorp/shared'; +import { DeepLinkData, extractLureMetadata } from '@tloncorp/shared/logic'; import { type ReactNode, createContext, diff --git a/packages/app/features/channels/ChannelMembersScreen.tsx b/packages/app/features/channels/ChannelMembersScreen.tsx index fcb6167844..baef4a6fbd 100644 --- a/packages/app/features/channels/ChannelMembersScreen.tsx +++ b/packages/app/features/channels/ChannelMembersScreen.tsx @@ -1,5 +1,5 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import { ChannelMembersScreenView } from '@tloncorp/ui'; import { RootStackParamList } from '../../navigation/types'; diff --git a/packages/app/features/channels/ChannelMetaScreen.tsx b/packages/app/features/channels/ChannelMetaScreen.tsx index a4fde4abd5..ab38e40f6d 100644 --- a/packages/app/features/channels/ChannelMetaScreen.tsx +++ b/packages/app/features/channels/ChannelMetaScreen.tsx @@ -1,7 +1,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; -import { uploadAsset, useCanUpload } from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; +import { uploadAsset, useCanUpload } from '@tloncorp/shared/store'; import { AttachmentProvider, MetaEditorScreenView } from '@tloncorp/ui'; import { useCallback } from 'react'; diff --git a/packages/app/features/groups/EditChannelScreen.tsx b/packages/app/features/groups/EditChannelScreen.tsx index aef376d1cf..66338b6646 100644 --- a/packages/app/features/groups/EditChannelScreen.tsx +++ b/packages/app/features/groups/EditChannelScreen.tsx @@ -1,5 +1,5 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import { EditChannelScreenView } from '@tloncorp/ui'; import { useCallback } from 'react'; diff --git a/packages/app/features/groups/GroupMembersScreen.tsx b/packages/app/features/groups/GroupMembersScreen.tsx index 78ebf50a86..1efc5e324a 100644 --- a/packages/app/features/groups/GroupMembersScreen.tsx +++ b/packages/app/features/groups/GroupMembersScreen.tsx @@ -1,6 +1,6 @@ import { CommonActions } from '@react-navigation/native'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import { GroupMembersScreenView } from '@tloncorp/ui'; import { useCallback } from 'react'; diff --git a/packages/app/features/groups/GroupMetaScreen.tsx b/packages/app/features/groups/GroupMetaScreen.tsx index e6c0d6e6ec..95966b3f4a 100644 --- a/packages/app/features/groups/GroupMetaScreen.tsx +++ b/packages/app/features/groups/GroupMetaScreen.tsx @@ -1,7 +1,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; -import { uploadAsset, useCanUpload } from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; +import { uploadAsset, useCanUpload } from '@tloncorp/shared/store'; import { AttachmentProvider, Button, diff --git a/packages/app/features/groups/GroupPrivacyScreen.tsx b/packages/app/features/groups/GroupPrivacyScreen.tsx index 29f4886ffe..5343ea5808 100644 --- a/packages/app/features/groups/GroupPrivacyScreen.tsx +++ b/packages/app/features/groups/GroupPrivacyScreen.tsx @@ -1,6 +1,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { GroupPrivacy } from '@tloncorp/shared/dist/db/schema'; -import * as store from '@tloncorp/shared/dist/store'; +import { GroupPrivacy } from '@tloncorp/shared/db/schema'; +import * as store from '@tloncorp/shared/store'; import { GroupPrivacySelector, ScreenHeader, diff --git a/packages/app/features/settings/AppInfoScreen.tsx b/packages/app/features/settings/AppInfoScreen.tsx index 34c905ef98..e1a04b635e 100644 --- a/packages/app/features/settings/AppInfoScreen.tsx +++ b/packages/app/features/settings/AppInfoScreen.tsx @@ -1,7 +1,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useDebugStore } from '@tloncorp/shared'; -import { getCurrentUserId } from '@tloncorp/shared/dist/api'; -import * as store from '@tloncorp/shared/dist/store'; +import { getCurrentUserId } from '@tloncorp/shared/api'; +import * as store from '@tloncorp/shared/store'; import { AppSetting, Button, diff --git a/packages/app/features/settings/BlockedUsersScreen.tsx b/packages/app/features/settings/BlockedUsersScreen.tsx index a49cdedf87..cdec57e7de 100644 --- a/packages/app/features/settings/BlockedUsersScreen.tsx +++ b/packages/app/features/settings/BlockedUsersScreen.tsx @@ -1,6 +1,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { BlockedContactsWidget, ScreenHeader, View } from '@tloncorp/ui'; import { useCallback } from 'react'; import { Alert } from 'react-native'; diff --git a/packages/app/features/settings/EditProfileScreen.tsx b/packages/app/features/settings/EditProfileScreen.tsx index 804af84fa9..744b227175 100644 --- a/packages/app/features/settings/EditProfileScreen.tsx +++ b/packages/app/features/settings/EditProfileScreen.tsx @@ -1,6 +1,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as api from '@tloncorp/shared/dist/api'; -import * as store from '@tloncorp/shared/dist/store'; +import * as api from '@tloncorp/shared/api'; +import * as store from '@tloncorp/shared/store'; import { AttachmentProvider, EditProfileScreenView, diff --git a/packages/app/features/settings/PushNotificationSettingsScreen.tsx b/packages/app/features/settings/PushNotificationSettingsScreen.tsx index 5ab1b1f003..3b1aeaa75e 100644 --- a/packages/app/features/settings/PushNotificationSettingsScreen.tsx +++ b/packages/app/features/settings/PushNotificationSettingsScreen.tsx @@ -1,8 +1,8 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; -import * as ub from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; +import * as ub from '@tloncorp/shared/urbit'; import { ChannelListItem, GroupListItem, diff --git a/packages/app/features/top/ActivityScreen.tsx b/packages/app/features/top/ActivityScreen.tsx index 140beb334a..050a01c954 100644 --- a/packages/app/features/top/ActivityScreen.tsx +++ b/packages/app/features/top/ActivityScreen.tsx @@ -1,12 +1,12 @@ +import { useIsFocused } from '@react-navigation/native'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { ActivityScreenView, NavBarView, View } from '@tloncorp/ui'; import { useCallback, useMemo } from 'react'; // import ErrorBoundary from '../../ErrorBoundary'; import { useCurrentUserId } from '../../hooks/useCurrentUser'; -import { useIsFocused } from '@react-navigation/native'; import { RootStackParamList } from '../../navigation/types'; type Props = NativeStackScreenProps; diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index 887666dcbe..2d7ea16700 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -1,17 +1,17 @@ import { useFocusEffect } from '@react-navigation/native'; import { useIsFocused } from '@react-navigation/native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCanUpload, useChannel, useGroupPreview, usePostReference, usePostWithRelations, -} from '@tloncorp/shared/dist/store'; -import { Story } from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/store'; +import { Story } from '@tloncorp/shared/urbit'; import { Channel, ChannelSwitcherSheet, diff --git a/packages/app/features/top/ChannelSearchScreen.tsx b/packages/app/features/top/ChannelSearchScreen.tsx index 4d62e81bdb..8b547394be 100644 --- a/packages/app/features/top/ChannelSearchScreen.tsx +++ b/packages/app/features/top/ChannelSearchScreen.tsx @@ -1,6 +1,6 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { useChannelSearch } from '@tloncorp/shared/dist'; -import type * as db from '@tloncorp/shared/dist/db'; +import { useChannelSearch } from '@tloncorp/shared'; +import type * as db from '@tloncorp/shared/db'; import { Button, SearchBar, SearchResults, XStack, YStack } from '@tloncorp/ui'; import { useCallback, useState } from 'react'; import { SafeAreaView } from 'react-native-safe-area-context'; diff --git a/packages/app/features/top/ChatListScreen.tsx b/packages/app/features/top/ChatListScreen.tsx index 57023bfc8f..d72f759af5 100644 --- a/packages/app/features/top/ChatListScreen.tsx +++ b/packages/app/features/top/ChatListScreen.tsx @@ -1,9 +1,9 @@ import { useIsFocused } from '@react-navigation/native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; import { AddGroupSheet, ChatList, diff --git a/packages/app/features/top/ContactHostedGroupsScreen.tsx b/packages/app/features/top/ContactHostedGroupsScreen.tsx index a9964d5913..17d549d3a8 100644 --- a/packages/app/features/top/ContactHostedGroupsScreen.tsx +++ b/packages/app/features/top/ContactHostedGroupsScreen.tsx @@ -1,5 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { GroupPreviewAction, GroupPreviewSheet, diff --git a/packages/app/features/top/CreateGroupScreen.tsx b/packages/app/features/top/CreateGroupScreen.tsx index b951ca0740..b5fd762ac9 100644 --- a/packages/app/features/top/CreateGroupScreen.tsx +++ b/packages/app/features/top/CreateGroupScreen.tsx @@ -1,5 +1,5 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import type * as db from '@tloncorp/shared/dist/db'; +import type * as db from '@tloncorp/shared/db'; import { CreateGroupView } from '@tloncorp/ui'; import { useCallback } from 'react'; diff --git a/packages/app/features/top/GroupChannelsScreen.tsx b/packages/app/features/top/GroupChannelsScreen.tsx index 376ba7eb50..e2c711eda3 100644 --- a/packages/app/features/top/GroupChannelsScreen.tsx +++ b/packages/app/features/top/GroupChannelsScreen.tsx @@ -1,7 +1,7 @@ import { useIsFocused } from '@react-navigation/native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { ChatOptionsProvider, GroupChannelsScreenView, diff --git a/packages/app/features/top/PostScreen.tsx b/packages/app/features/top/PostScreen.tsx index 3dfaef0370..98a3a18a57 100644 --- a/packages/app/features/top/PostScreen.tsx +++ b/packages/app/features/top/PostScreen.tsx @@ -1,7 +1,7 @@ import type { NativeStackScreenProps } from '@react-navigation/native-stack'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; -import * as urbit from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; +import * as urbit from '@tloncorp/shared/urbit'; import { PostScreenView, useCurrentUserId } from '@tloncorp/ui'; import { useCallback, useEffect, useMemo, useState } from 'react'; diff --git a/packages/app/features/top/UserProfileScreen.tsx b/packages/app/features/top/UserProfileScreen.tsx index ae92cfb193..179b1f1755 100644 --- a/packages/app/features/top/UserProfileScreen.tsx +++ b/packages/app/features/top/UserProfileScreen.tsx @@ -1,7 +1,7 @@ import { CommonActions } from '@react-navigation/native'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import type * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import type * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { AppDataContextProvider, GroupPreviewSheet, diff --git a/packages/app/features/top/useConnectionStatus.tsx b/packages/app/features/top/useConnectionStatus.tsx index 5a4c842ac1..5bb25618ac 100644 --- a/packages/app/features/top/useConnectionStatus.tsx +++ b/packages/app/features/top/useConnectionStatus.tsx @@ -1,5 +1,5 @@ -import * as api from '@tloncorp/shared/dist/api'; -import { ConnectionStatus } from '@tloncorp/shared/dist/api'; +import * as api from '@tloncorp/shared/api'; +import { ConnectionStatus } from '@tloncorp/shared/api'; import { useCurrentUserId } from '@tloncorp/ui'; import { debounce } from 'lodash'; import { useEffect, useState } from 'react'; diff --git a/packages/app/hooks/useBootSequence.ts b/packages/app/hooks/useBootSequence.ts index f716f4c803..3f8bcd1d7c 100644 --- a/packages/app/hooks/useBootSequence.ts +++ b/packages/app/hooks/useBootSequence.ts @@ -1,5 +1,5 @@ -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as store from '@tloncorp/shared/store'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useLureMetadata } from '../contexts/branch'; diff --git a/packages/app/hooks/useBranchLink.ts b/packages/app/hooks/useBranchLink.ts index 15741a3298..b649e57341 100644 --- a/packages/app/hooks/useBranchLink.ts +++ b/packages/app/hooks/useBranchLink.ts @@ -1,4 +1,4 @@ -import { getDmLink } from '@tloncorp/shared/dist/logic'; +import { getDmLink } from '@tloncorp/shared/logic'; import { useEffect, useState } from 'react'; import { BRANCH_DOMAIN, BRANCH_KEY } from '../constants'; diff --git a/packages/app/hooks/useCalmSettings.ts b/packages/app/hooks/useCalmSettings.ts index 8f9941634e..76ece79f04 100644 --- a/packages/app/hooks/useCalmSettings.ts +++ b/packages/app/hooks/useCalmSettings.ts @@ -1,4 +1,4 @@ -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import { useCurrentUserId } from '../hooks/useCurrentUser'; diff --git a/packages/app/hooks/useChannelContext.ts b/packages/app/hooks/useChannelContext.ts index 6c2add7dbc..a5c8bd5016 100644 --- a/packages/app/hooks/useChannelContext.ts +++ b/packages/app/hooks/useChannelContext.ts @@ -1,7 +1,7 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; -import * as urbit from '@tloncorp/shared/dist/urbit'; -import { JSONContent } from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; +import * as urbit from '@tloncorp/shared/urbit'; +import { JSONContent } from '@tloncorp/shared/urbit'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useFeatureFlag } from '../lib/featureFlags'; diff --git a/packages/app/hooks/useChannelNavigation.ts b/packages/app/hooks/useChannelNavigation.ts index 922f5189f5..da574f4216 100644 --- a/packages/app/hooks/useChannelNavigation.ts +++ b/packages/app/hooks/useChannelNavigation.ts @@ -1,6 +1,6 @@ import { useNavigation } from '@react-navigation/native'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; export const useChannelNavigation = ({ channelId }: { channelId: string }) => { diff --git a/packages/app/hooks/useConfigureUrbitClient.ts b/packages/app/hooks/useConfigureUrbitClient.ts index 589e077958..40bd71ee89 100644 --- a/packages/app/hooks/useConfigureUrbitClient.ts +++ b/packages/app/hooks/useConfigureUrbitClient.ts @@ -1,6 +1,6 @@ -import { createDevLogger, sync } from '@tloncorp/shared/dist'; -import { ClientParams } from '@tloncorp/shared/dist/api'; -import { configureClient } from '@tloncorp/shared/dist/store'; +import { createDevLogger, sync } from '@tloncorp/shared'; +import { ClientParams } from '@tloncorp/shared/api'; +import { configureClient } from '@tloncorp/shared/store'; import { useCallback } from 'react'; import { ENABLED_LOGGERS } from '../constants'; diff --git a/packages/app/hooks/useCurrentUser.native.ts b/packages/app/hooks/useCurrentUser.native.ts index 2810125a46..21ce359bcb 100644 --- a/packages/app/hooks/useCurrentUser.native.ts +++ b/packages/app/hooks/useCurrentUser.native.ts @@ -1,4 +1,4 @@ -import * as urbit from '@tloncorp/shared/dist/urbit'; +import * as urbit from '@tloncorp/shared/urbit'; import { useShip } from '../contexts/ship'; diff --git a/packages/app/hooks/useGroupActions.tsx b/packages/app/hooks/useGroupActions.tsx index 9a5b2ffdbd..fa97703023 100644 --- a/packages/app/hooks/useGroupActions.tsx +++ b/packages/app/hooks/useGroupActions.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { GroupPreviewAction } from '@tloncorp/ui'; import { useCallback } from 'react'; diff --git a/packages/app/hooks/useGroupContext.ts b/packages/app/hooks/useGroupContext.ts index 59415bc1b8..f525426ba1 100644 --- a/packages/app/hooks/useGroupContext.ts +++ b/packages/app/hooks/useGroupContext.ts @@ -1,6 +1,6 @@ import { sync, useCreateChannel } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback, useEffect, useMemo } from 'react'; import { useCurrentUserId } from './useCurrentUser'; diff --git a/packages/app/hooks/useGroupNavigation.ts b/packages/app/hooks/useGroupNavigation.ts index 3068f1bd3d..b4ae89a656 100644 --- a/packages/app/hooks/useGroupNavigation.ts +++ b/packages/app/hooks/useGroupNavigation.ts @@ -1,5 +1,5 @@ import { useNavigation } from '@react-navigation/native'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback } from 'react'; export const useGroupNavigation = () => { diff --git a/packages/app/hooks/useHandleLogout.native.ts b/packages/app/hooks/useHandleLogout.native.ts index def9429f4d..34a89f85af 100644 --- a/packages/app/hooks/useHandleLogout.native.ts +++ b/packages/app/hooks/useHandleLogout.native.ts @@ -1,6 +1,6 @@ -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as api from '@tloncorp/shared/dist/api'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as api from '@tloncorp/shared/api'; +import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; import { useBranch } from '../contexts/branch'; diff --git a/packages/app/hooks/useHandleLogout.ts b/packages/app/hooks/useHandleLogout.ts index 89ac06200b..54a52b374d 100644 --- a/packages/app/hooks/useHandleLogout.ts +++ b/packages/app/hooks/useHandleLogout.ts @@ -2,9 +2,9 @@ // Branch context and methods removed here because a) it's not used and // b) it breaks the web build because it relies on react-native-branch, // which isn't made for web. -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as api from '@tloncorp/shared/dist/api'; -import * as store from '@tloncorp/shared/dist/store'; +import { createDevLogger } from '@tloncorp/shared'; +import * as api from '@tloncorp/shared/api'; +import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; import { clearShipInfo, useShip } from '../contexts/ship'; diff --git a/packages/app/hooks/useNavigationLogger.ts b/packages/app/hooks/useNavigationLogger.ts index 051ea2cf3e..3569b4e464 100644 --- a/packages/app/hooks/useNavigationLogger.ts +++ b/packages/app/hooks/useNavigationLogger.ts @@ -1,5 +1,5 @@ import { useNavigation } from '@react-navigation/native'; -import { createDevLogger } from '@tloncorp/shared/dist'; +import { createDevLogger } from '@tloncorp/shared'; import { useEffect, useRef } from 'react'; const logger = createDevLogger('navigation', false); diff --git a/packages/app/hooks/useNetworkLogger.ts b/packages/app/hooks/useNetworkLogger.ts index de20ba9223..2f74ebf015 100644 --- a/packages/app/hooks/useNetworkLogger.ts +++ b/packages/app/hooks/useNetworkLogger.ts @@ -1,5 +1,5 @@ import NetInfo from '@react-native-community/netinfo'; -import { createDevLogger } from '@tloncorp/shared/dist'; +import { createDevLogger } from '@tloncorp/shared'; import { useEffect, useState } from 'react'; import { toNetworkTypeDisplay } from '../lib/platformHelpers'; diff --git a/packages/app/lib/betterSqlite3Connection.ts b/packages/app/lib/betterSqlite3Connection.ts index 034a6a1a27..62dffa9aaa 100644 --- a/packages/app/lib/betterSqlite3Connection.ts +++ b/packages/app/lib/betterSqlite3Connection.ts @@ -1,6 +1,6 @@ -import type { Schema } from '@tloncorp/shared/dist/db'; -import type { AnySqliteDatabase } from '@tloncorp/shared/dist/db/client'; -import { migrations } from '@tloncorp/shared/dist/db/migrations'; +import type { Schema } from '@tloncorp/shared/db'; +import type { AnySqliteDatabase } from '@tloncorp/shared/db/client'; +import { migrations } from '@tloncorp/shared/db/migrations'; import type { Database } from 'better-sqlite3'; import type { DrizzleConfig } from 'drizzle-orm'; import { drizzle } from 'drizzle-orm/better-sqlite3'; diff --git a/packages/app/lib/bootHelpers.ts b/packages/app/lib/bootHelpers.ts index 60866871c9..f10126e889 100644 --- a/packages/app/lib/bootHelpers.ts +++ b/packages/app/lib/bootHelpers.ts @@ -1,5 +1,5 @@ -import { getLandscapeAuthCookie } from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; +import { getLandscapeAuthCookie } from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; import { LureData } from '../contexts/branch'; import * as hostingApi from '../lib/hostingApi'; diff --git a/packages/app/lib/devMenuItems.ts b/packages/app/lib/devMenuItems.ts index 700ac63649..1bcbdfa7ca 100644 --- a/packages/app/lib/devMenuItems.ts +++ b/packages/app/lib/devMenuItems.ts @@ -1,4 +1,4 @@ -import * as api from '@tloncorp/shared/dist/api'; +import * as api from '@tloncorp/shared/api'; import { registerDevMenuItems } from 'expo-dev-menu'; import { Alert, DevSettings, NativeModules } from 'react-native'; import * as DeviceInfo from 'react-native-device-info'; diff --git a/packages/app/lib/hostingApi.ts b/packages/app/lib/hostingApi.ts index 2cd614b1fa..e43d13839f 100644 --- a/packages/app/lib/hostingApi.ts +++ b/packages/app/lib/hostingApi.ts @@ -1,4 +1,4 @@ -import * as logic from '@tloncorp/shared/dist/logic'; +import * as logic from '@tloncorp/shared/logic'; import { Buffer } from 'buffer'; import { Platform } from 'react-native'; diff --git a/packages/app/lib/nativeDb.ts b/packages/app/lib/nativeDb.ts index 659f3e4512..b4900e4cd5 100644 --- a/packages/app/lib/nativeDb.ts +++ b/packages/app/lib/nativeDb.ts @@ -1,7 +1,7 @@ import { open } from '@op-engineering/op-sqlite'; import { createDevLogger, escapeLog } from '@tloncorp/shared'; -import { handleChange, schema, setClient } from '@tloncorp/shared/dist/db'; -import { AnySqliteDatabase } from '@tloncorp/shared/dist/db/client'; +import { handleChange, schema, setClient } from '@tloncorp/shared/db'; +import { AnySqliteDatabase } from '@tloncorp/shared/db/client'; import { useEffect, useMemo, useState } from 'react'; import { OPSQLite$SQLiteConnection } from './opsqliteConnection'; diff --git a/packages/app/lib/notificationsApi.ts b/packages/app/lib/notificationsApi.ts index 8c4d277287..61f43c0f77 100644 --- a/packages/app/lib/notificationsApi.ts +++ b/packages/app/lib/notificationsApi.ts @@ -1,4 +1,4 @@ -import { poke } from '@tloncorp/shared/dist/api'; +import { poke } from '@tloncorp/shared/api'; import { Platform } from 'react-native'; import { NOTIFY_PROVIDER, NOTIFY_SERVICE } from '../constants'; diff --git a/packages/app/lib/opsqliteConnection.ts b/packages/app/lib/opsqliteConnection.ts index 74380d804f..8c8232afac 100644 --- a/packages/app/lib/opsqliteConnection.ts +++ b/packages/app/lib/opsqliteConnection.ts @@ -1,6 +1,6 @@ import { OPSQLiteConnection } from '@op-engineering/op-sqlite'; -import { migrations } from '@tloncorp/shared/dist/db/migrations'; -import { Schema } from '@tloncorp/shared/dist/db/types'; +import { migrations } from '@tloncorp/shared/db/migrations'; +import { Schema } from '@tloncorp/shared/db/types'; import { DrizzleConfig } from 'drizzle-orm'; import type { OPSQLiteDatabase } from 'drizzle-orm/op-sqlite'; import { drizzle } from 'drizzle-orm/op-sqlite'; diff --git a/packages/app/lib/sqliteConnection.ts b/packages/app/lib/sqliteConnection.ts index 23667f62c9..24d8542116 100644 --- a/packages/app/lib/sqliteConnection.ts +++ b/packages/app/lib/sqliteConnection.ts @@ -1,5 +1,5 @@ -import { AnySqliteDatabase } from '@tloncorp/shared/dist/db/client'; -import { Schema } from '@tloncorp/shared/dist/db/types'; +import { AnySqliteDatabase } from '@tloncorp/shared/db/client'; +import { Schema } from '@tloncorp/shared/db/types'; import type { DrizzleConfig } from 'drizzle-orm/utils'; /** diff --git a/packages/app/lib/webDb.ts b/packages/app/lib/webDb.ts index 70dd89ebd7..44b86f0cf1 100644 --- a/packages/app/lib/webDb.ts +++ b/packages/app/lib/webDb.ts @@ -1,7 +1,7 @@ import { createDevLogger } from '@tloncorp/shared'; -import type { Schema } from '@tloncorp/shared/dist/db'; -import { handleChange, schema, setClient } from '@tloncorp/shared/dist/db'; -import { migrations } from '@tloncorp/shared/dist/db/migrations'; +import type { Schema } from '@tloncorp/shared/db'; +import { handleChange, schema, setClient } from '@tloncorp/shared/db'; +import { migrations } from '@tloncorp/shared/db/migrations'; import { sql } from 'drizzle-orm'; import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; import { drizzle } from 'drizzle-orm/sqlite-proxy'; diff --git a/packages/app/lib/webMigrator.ts b/packages/app/lib/webMigrator.ts index 21e057a7f2..8c1730ea12 100644 --- a/packages/app/lib/webMigrator.ts +++ b/packages/app/lib/webMigrator.ts @@ -1,5 +1,5 @@ import { createDevLogger } from '@tloncorp/shared'; -import { migrations as sharedMigrations } from '@tloncorp/shared/dist/db/migrations'; +import { migrations as sharedMigrations } from '@tloncorp/shared/db/migrations'; import { sql } from 'drizzle-orm'; import type { SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy'; import { SQLocalDrizzle } from 'sqlocal/drizzle'; diff --git a/packages/app/navigation/types.ts b/packages/app/navigation/types.ts index c37b3d9427..86a4e1ef7a 100644 --- a/packages/app/navigation/types.ts +++ b/packages/app/navigation/types.ts @@ -1,5 +1,5 @@ import type { NavigatorScreenParams } from '@react-navigation/native'; -import type * as db from '@tloncorp/shared/dist/db'; +import type * as db from '@tloncorp/shared/db'; export type SignUpExtras = { nickname?: string; diff --git a/packages/app/provider/AppDataProvider.tsx b/packages/app/provider/AppDataProvider.tsx index e1d551d104..e51b7c79c5 100644 --- a/packages/app/provider/AppDataProvider.tsx +++ b/packages/app/provider/AppDataProvider.tsx @@ -1,4 +1,4 @@ -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import { AppDataContextProvider } from '@tloncorp/ui'; import { PropsWithChildren } from 'react'; diff --git a/packages/app/utils/images.ts b/packages/app/utils/images.ts index 17b6a78c12..959fe3888c 100644 --- a/packages/app/utils/images.ts +++ b/packages/app/utils/images.ts @@ -1,4 +1,4 @@ -import { SizedImage, createDevLogger } from '@tloncorp/shared/dist'; +import { SizedImage, createDevLogger } from '@tloncorp/shared'; import { manipulateAsync } from 'expo-image-manipulator'; import { Image } from 'react-native'; diff --git a/packages/app/utils/perf.tsx b/packages/app/utils/perf.tsx index 0c41c9b868..508c63d683 100644 --- a/packages/app/utils/perf.tsx +++ b/packages/app/utils/perf.tsx @@ -1,6 +1,6 @@ import { firebase } from '@react-native-firebase/perf'; -import { InstrumentationProvider } from '@tloncorp/shared/dist'; -import { PerformanceMonitoringEndpoint } from '@tloncorp/shared/dist/perf'; +import { InstrumentationProvider } from '@tloncorp/shared'; +import { PerformanceMonitoringEndpoint } from '@tloncorp/shared/perf'; import { useMemo } from 'react'; import { useFeatureFlag } from '../lib/featureFlags'; diff --git a/packages/app/utils/posthog.ts b/packages/app/utils/posthog.ts index f67d6473fe..f4f59de862 100644 --- a/packages/app/utils/posthog.ts +++ b/packages/app/utils/posthog.ts @@ -1,6 +1,6 @@ import crashlytics from '@react-native-firebase/crashlytics'; import { useDebugStore } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import PostHog from 'posthog-react-native'; import { POST_HOG_API_KEY } from '../constants'; diff --git a/packages/editor/global.d.ts b/packages/editor/global.d.ts index 0bd68af050..63e7a97975 100644 --- a/packages/editor/global.d.ts +++ b/packages/editor/global.d.ts @@ -1,4 +1,4 @@ -import { Clubs, ContactRolodex, Group } from '@tloncorp/shared/dist/urbit'; +import { Clubs, ContactRolodex, Group } from '@tloncorp/shared/urbit'; declare global { interface Window { diff --git a/packages/shared/package.json b/packages/shared/package.json index 2af676ad16..fe835bfd92 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -10,6 +10,7 @@ "./client": "./src/client/index.ts", "./db": "./src/db/index.ts", "./logic": "./src/logic/index.ts", + "./perf": "./src/perf.ts", "./store": "./src/store/index.ts", "./urbit": "./src/urbit/index.ts" }, diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index 2a3eb1c9d7..2df0608c72 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../../tsconfig", "compilerOptions": { "strict": true, - "moduleResolution": "node", "allowSyntheticDefaultImports": true, "declaration": true, "declarationMap": true, diff --git a/packages/ui/src/components/Activity/ActivityHeader.tsx b/packages/ui/src/components/Activity/ActivityHeader.tsx index 7099ea98a8..380c1779cc 100644 --- a/packages/ui/src/components/Activity/ActivityHeader.tsx +++ b/packages/ui/src/components/Activity/ActivityHeader.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import React from 'react'; import { View } from 'tamagui'; diff --git a/packages/ui/src/components/Activity/ActivityListItem.tsx b/packages/ui/src/components/Activity/ActivityListItem.tsx index 4cf4f50225..e6b8693488 100644 --- a/packages/ui/src/components/Activity/ActivityListItem.tsx +++ b/packages/ui/src/components/Activity/ActivityListItem.tsx @@ -1,6 +1,6 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; import React, { PropsWithChildren, useCallback, useMemo } from 'react'; import { View, XStack, YStack, styled } from 'tamagui'; @@ -61,10 +61,10 @@ export function ActivityListItemContent({ const channel: db.Channel | undefined = newestPost.channel ?? undefined; const modelUnread = summary.type === 'post' - ? (newestPost.channel?.unread ?? null) + ? newestPost.channel?.unread ?? null : summary.type === 'group-ask' - ? (newestPost.group?.unread ?? null) - : (newestPost.parent?.threadUnread ?? null); + ? newestPost.group?.unread ?? null + : newestPost.parent?.threadUnread ?? null; const { data: unread } = store.useLiveUnread(modelUnread); const unreadCount = useMemo(() => { return (isGroupUnread(unread) ? unread.notifyCount : unread?.count) ?? 0; diff --git a/packages/ui/src/components/Activity/ActivityScreenView.tsx b/packages/ui/src/components/Activity/ActivityScreenView.tsx index 9789c204f0..5ed8297dd5 100644 --- a/packages/ui/src/components/Activity/ActivityScreenView.tsx +++ b/packages/ui/src/components/Activity/ActivityScreenView.tsx @@ -1,6 +1,6 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { FlatList, RefreshControl, StyleProp, ViewStyle } from 'react-native'; import { View, useStyle } from 'tamagui'; diff --git a/packages/ui/src/components/Activity/ActivitySourceContent.tsx b/packages/ui/src/components/Activity/ActivitySourceContent.tsx index d7d5529f2d..0f48714972 100644 --- a/packages/ui/src/components/Activity/ActivitySourceContent.tsx +++ b/packages/ui/src/components/Activity/ActivitySourceContent.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import { useMemo } from 'react'; import { ScrollView, styled } from 'tamagui'; diff --git a/packages/ui/src/components/Activity/ActivitySummaryMessage.tsx b/packages/ui/src/components/Activity/ActivitySummaryMessage.tsx index ffd3f34120..f12b7153c9 100644 --- a/packages/ui/src/components/Activity/ActivitySummaryMessage.tsx +++ b/packages/ui/src/components/Activity/ActivitySummaryMessage.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import React, { Fragment, useMemo } from 'react'; import { styled } from 'tamagui'; diff --git a/packages/ui/src/components/AddChats/CreateGroupWidget.tsx b/packages/ui/src/components/AddChats/CreateGroupWidget.tsx index 9301364a1b..6a31c38ee8 100644 --- a/packages/ui/src/components/AddChats/CreateGroupWidget.tsx +++ b/packages/ui/src/components/AddChats/CreateGroupWidget.tsx @@ -1,6 +1,6 @@ -import { createShortCodeFromTitle } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import { createShortCodeFromTitle } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback, useState } from 'react'; import { YStack } from 'tamagui'; diff --git a/packages/ui/src/components/AddChats/ViewUserGroupsWidget.tsx b/packages/ui/src/components/AddChats/ViewUserGroupsWidget.tsx index 3ca08de14a..ead6c655dd 100644 --- a/packages/ui/src/components/AddChats/ViewUserGroupsWidget.tsx +++ b/packages/ui/src/components/AddChats/ViewUserGroupsWidget.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback, useMemo, useRef } from 'react'; import { NativeScrollEvent, NativeSyntheticEvent } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; diff --git a/packages/ui/src/components/AttachmentSheet.tsx b/packages/ui/src/components/AttachmentSheet.tsx index bf992c4250..5757e3a216 100644 --- a/packages/ui/src/components/AttachmentSheet.tsx +++ b/packages/ui/src/components/AttachmentSheet.tsx @@ -1,5 +1,5 @@ -import { createDevLogger } from '@tloncorp/shared/dist'; -import { MessageAttachments } from '@tloncorp/shared/dist/api'; +import { createDevLogger } from '@tloncorp/shared'; +import { MessageAttachments } from '@tloncorp/shared/api'; import * as ImagePicker from 'expo-image-picker'; import { useCallback, useEffect, useMemo } from 'react'; diff --git a/packages/ui/src/components/AuthorRow.tsx b/packages/ui/src/components/AuthorRow.tsx index 505b951bc4..919122a204 100644 --- a/packages/ui/src/components/AuthorRow.tsx +++ b/packages/ui/src/components/AuthorRow.tsx @@ -1,5 +1,5 @@ import { utils } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ComponentProps, useMemo } from 'react'; import { ColorTokens, View, XStack } from 'tamagui'; diff --git a/packages/ui/src/components/Avatar.tsx b/packages/ui/src/components/Avatar.tsx index f45bea82be..f02a0698ba 100644 --- a/packages/ui/src/components/Avatar.tsx +++ b/packages/ui/src/components/Avatar.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ComponentProps, useCallback, useMemo, useState } from 'react'; import React from 'react'; import { diff --git a/packages/ui/src/components/BareChatInput/helpers.ts b/packages/ui/src/components/BareChatInput/helpers.ts index cd4babc1bf..ed54ef8c2f 100644 --- a/packages/ui/src/components/BareChatInput/helpers.ts +++ b/packages/ui/src/components/BareChatInput/helpers.ts @@ -1,5 +1,5 @@ import { makeMention, makeParagraph, makeText } from '@tloncorp/shared'; -import { JSONContent } from '@tloncorp/shared/dist/urbit'; +import { JSONContent } from '@tloncorp/shared/urbit'; import { Mention } from './useMentions'; diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index abd4520ce8..11ea982226 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -8,15 +8,15 @@ import { import { contentReferenceToCite, toContentReference, -} from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; +} from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; import { Block, Story, citeToPath, constructStory, pathToCite, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Keyboard, Platform, TextInput } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; diff --git a/packages/ui/src/components/BareChatInput/useMentions.tsx b/packages/ui/src/components/BareChatInput/useMentions.tsx index 0a0fc6e73f..e4d54fe9db 100644 --- a/packages/ui/src/components/BareChatInput/useMentions.tsx +++ b/packages/ui/src/components/BareChatInput/useMentions.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useState } from 'react'; export interface Mention { diff --git a/packages/ui/src/components/BigInput.native.tsx b/packages/ui/src/components/BigInput.native.tsx index ef87afbaf1..86f3f4aa6e 100644 --- a/packages/ui/src/components/BigInput.native.tsx +++ b/packages/ui/src/components/BigInput.native.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo, useRef, useState } from 'react'; import { Dimensions, KeyboardAvoidingView, Platform } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; diff --git a/packages/ui/src/components/BigInput.tsx b/packages/ui/src/components/BigInput.tsx index 21b58c024e..4d89360235 100644 --- a/packages/ui/src/components/BigInput.tsx +++ b/packages/ui/src/components/BigInput.tsx @@ -1,5 +1,5 @@ // import { EditorBridge } from '@10play/tentap-editor'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo, useRef, useState } from 'react'; import { Dimensions, KeyboardAvoidingView, Platform } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; diff --git a/packages/ui/src/components/BlockedContactsWidget.tsx b/packages/ui/src/components/BlockedContactsWidget.tsx index 7089750ccf..70daa66e80 100644 --- a/packages/ui/src/components/BlockedContactsWidget.tsx +++ b/packages/ui/src/components/BlockedContactsWidget.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { SizableText, XStack } from 'tamagui'; import { Badge } from './Badge'; diff --git a/packages/ui/src/components/Channel/BaubleHeader.tsx b/packages/ui/src/components/Channel/BaubleHeader.tsx index 52603b397d..259df6e6ac 100644 --- a/packages/ui/src/components/Channel/BaubleHeader.tsx +++ b/packages/ui/src/components/Channel/BaubleHeader.tsx @@ -1,5 +1,5 @@ import { LinearGradient } from '@tamagui/linear-gradient'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { BlurView } from 'expo-blur'; import { useCallback, useRef } from 'react'; import { OpaqueColorValue } from 'react-native'; diff --git a/packages/ui/src/components/Channel/ChannelDivider.tsx b/packages/ui/src/components/Channel/ChannelDivider.tsx index d2c32351a2..1c41562404 100644 --- a/packages/ui/src/components/Channel/ChannelDivider.tsx +++ b/packages/ui/src/components/Channel/ChannelDivider.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import { isToday, makePrettyDay } from '@tloncorp/shared/dist/logic'; +import * as db from '@tloncorp/shared/db'; +import { isToday, makePrettyDay } from '@tloncorp/shared/logic'; import { useMemo } from 'react'; import { View, XStack } from 'tamagui'; diff --git a/packages/ui/src/components/Channel/ChannelHeader.tsx b/packages/ui/src/components/Channel/ChannelHeader.tsx index d7f8bbe69b..fb326952f0 100644 --- a/packages/ui/src/components/Channel/ChannelHeader.tsx +++ b/packages/ui/src/components/Channel/ChannelHeader.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { createContext, useCallback, diff --git a/packages/ui/src/components/Channel/DmInviteOptions.tsx b/packages/ui/src/components/Channel/DmInviteOptions.tsx index 12320a3ad6..22e10bd709 100644 --- a/packages/ui/src/components/Channel/DmInviteOptions.tsx +++ b/packages/ui/src/components/Channel/DmInviteOptions.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { YStack } from 'tamagui'; diff --git a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx index fe5e975925..5cf4a05368 100644 --- a/packages/ui/src/components/Channel/EmptyChannelNotice.tsx +++ b/packages/ui/src/components/Channel/EmptyChannelNotice.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo, useState } from 'react'; import { SizableText, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/Channel/Scroller.tsx b/packages/ui/src/components/Channel/Scroller.tsx index 5acaa8244a..7aa0269267 100644 --- a/packages/ui/src/components/Channel/Scroller.tsx +++ b/packages/ui/src/components/Channel/Scroller.tsx @@ -5,9 +5,9 @@ import { layoutTypeFromChannel, useMutableCallback, } from '@tloncorp/shared'; -import { createDevLogger } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import { isSameDay } from '@tloncorp/shared/dist/logic'; +import { createDevLogger } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import { isSameDay } from '@tloncorp/shared/logic'; import { isEqual } from 'lodash'; import React, { PropsWithChildren, diff --git a/packages/ui/src/components/Channel/index.tsx b/packages/ui/src/components/Channel/index.tsx index 86d500121e..529a74e3ba 100644 --- a/packages/ui/src/components/Channel/index.tsx +++ b/packages/ui/src/components/Channel/index.tsx @@ -9,9 +9,9 @@ import { useGroupPreview, usePostReference as usePostReferenceHook, usePostWithRelations, -} from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import { JSONContent, Story } from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import { JSONContent, Story } from '@tloncorp/shared/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FlatList } from 'react-native'; diff --git a/packages/ui/src/components/ChannelMembersScreenView.tsx b/packages/ui/src/components/ChannelMembersScreenView.tsx index 657a1c25f9..ec03fff37d 100644 --- a/packages/ui/src/components/ChannelMembersScreenView.tsx +++ b/packages/ui/src/components/ChannelMembersScreenView.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback } from 'react'; import { FlatList, ListRenderItemInfo } from 'react-native'; import { View, getTokenValue } from 'tamagui'; diff --git a/packages/ui/src/components/ChannelNavSection.tsx b/packages/ui/src/components/ChannelNavSection.tsx index 371c40912e..ce17aa804b 100644 --- a/packages/ui/src/components/ChannelNavSection.tsx +++ b/packages/ui/src/components/ChannelNavSection.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useMemo } from 'react'; import { SizableText, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/ChannelNavSections.tsx b/packages/ui/src/components/ChannelNavSections.tsx index bae77a0580..5e69ed9063 100644 --- a/packages/ui/src/components/ChannelNavSections.tsx +++ b/packages/ui/src/components/ChannelNavSections.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo } from 'react'; import { SizableText, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/ChannelSearch/SearchResults.tsx b/packages/ui/src/components/ChannelSearch/SearchResults.tsx index 80f7659968..8b3a09a8a2 100644 --- a/packages/ui/src/components/ChannelSearch/SearchResults.tsx +++ b/packages/ui/src/components/ChannelSearch/SearchResults.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useMemo } from 'react'; import React from 'react'; import { FlatList, Keyboard } from 'react-native'; diff --git a/packages/ui/src/components/ChannelSearch/SearchStatus.tsx b/packages/ui/src/components/ChannelSearch/SearchStatus.tsx index d8510ccbdd..0789d52211 100644 --- a/packages/ui/src/components/ChannelSearch/SearchStatus.tsx +++ b/packages/ui/src/components/ChannelSearch/SearchStatus.tsx @@ -1,4 +1,4 @@ -import { makePrettyShortDate } from '@tloncorp/shared/src/logic/utils'; +import { makePrettyShortDate } from '@tloncorp/shared/logic/utils'; import { ColorTokens } from 'tamagui'; import { SizableText, View, XStack, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/ChannelSwitcherSheet.tsx b/packages/ui/src/components/ChannelSwitcherSheet.tsx index a11656c9e4..5f0147a325 100644 --- a/packages/ui/src/components/ChannelSwitcherSheet.tsx +++ b/packages/ui/src/components/ChannelSwitcherSheet.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useEffect, useState } from 'react'; import { TouchableOpacity } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; diff --git a/packages/ui/src/components/ChatList.tsx b/packages/ui/src/components/ChatList.tsx index 98960341d4..893152b235 100644 --- a/packages/ui/src/components/ChatList.tsx +++ b/packages/ui/src/components/ChatList.tsx @@ -1,7 +1,7 @@ import { FlashList, ListRenderItem } from '@shopify/flash-list'; -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; import Fuse from 'fuse.js'; import { debounce } from 'lodash'; import React, { diff --git a/packages/ui/src/components/ChatMessage/ChatMessage.tsx b/packages/ui/src/components/ChatMessage/ChatMessage.tsx index e137b94621..cfc4743b46 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessage.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessage.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { isEqual } from 'lodash'; import { ComponentProps, memo, useCallback, useMemo, useState } from 'react'; import { View, XStack, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx index a9f796e14f..6e6654d7a6 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.android.tsx @@ -1,5 +1,5 @@ import { ChannelAction } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import * as Haptics from 'expo-haptics'; import { MotiView } from 'moti'; import { RefObject, useEffect, useState } from 'react'; diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.tsx index ee1cebe02e..ac7fa6e8f5 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/Component.tsx @@ -1,5 +1,5 @@ import { ChannelAction } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import * as Haptics from 'expo-haptics'; import { RefObject, useEffect, useState } from 'react'; import { diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/EmojiToolbar.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/EmojiToolbar.tsx index e1baa15886..2fa853a6c3 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/EmojiToolbar.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/EmojiToolbar.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import * as Haptics from 'expo-haptics'; import { useCallback, useState } from 'react'; import { XStack } from 'tamagui'; diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx index 68cbc1bad2..2075b3c2fa 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageActions.tsx @@ -1,8 +1,8 @@ import Clipboard from '@react-native-clipboard/clipboard'; import { ChannelAction } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; import * as Haptics from 'expo-haptics'; import { useMemo } from 'react'; import { Alert } from 'react-native'; diff --git a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageContainer.tsx b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageContainer.tsx index 9c5abbbcdd..910ac6f1c4 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageContainer.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageActions/MessageContainer.tsx @@ -1,5 +1,5 @@ import { getSize } from '@tamagui/get-token'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { Dimensions } from 'react-native'; import { ScrollView, View } from 'tamagui'; diff --git a/packages/ui/src/components/ChatMessage/ChatMessageDeliveryStatus.tsx b/packages/ui/src/components/ChatMessage/ChatMessageDeliveryStatus.tsx index 3cf5e3273a..3aa1ce8c7f 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageDeliveryStatus.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageDeliveryStatus.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { XStack } from 'tamagui'; import { Icon } from '../Icon'; diff --git a/packages/ui/src/components/ChatMessage/ChatMessageReplySummary.tsx b/packages/ui/src/components/ChatMessage/ChatMessageReplySummary.tsx index 4abfb0811d..fd4711e048 100644 --- a/packages/ui/src/components/ChatMessage/ChatMessageReplySummary.tsx +++ b/packages/ui/src/components/ChatMessage/ChatMessageReplySummary.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import { formatDistanceToNow } from 'date-fns'; import React, { useMemo } from 'react'; import { ColorTokens, View, XStack, styled } from 'tamagui'; diff --git a/packages/ui/src/components/ChatMessage/ReactionsDisplay.tsx b/packages/ui/src/components/ChatMessage/ReactionsDisplay.tsx index 8c62e2cedb..44b802a987 100644 --- a/packages/ui/src/components/ChatMessage/ReactionsDisplay.tsx +++ b/packages/ui/src/components/ChatMessage/ReactionsDisplay.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; import { XStack } from 'tamagui'; diff --git a/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx b/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx index 753d4d4384..1dc691d12b 100644 --- a/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx +++ b/packages/ui/src/components/ChatMessage/ViewReactionsPane.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useMemo, useRef, useState } from 'react'; import { FlatList, diff --git a/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx b/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx index 11d5dba2cd..27c3890203 100644 --- a/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx +++ b/packages/ui/src/components/ChatMessage/ViewReactionsSheet.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo, useState } from 'react'; import { ActionSheet } from '../ActionSheet'; diff --git a/packages/ui/src/components/ChatOptionsSheet.tsx b/packages/ui/src/components/ChatOptionsSheet.tsx index 09476cc27f..41f51cec21 100644 --- a/packages/ui/src/components/ChatOptionsSheet.tsx +++ b/packages/ui/src/components/ChatOptionsSheet.tsx @@ -1,8 +1,8 @@ import { sync } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; -import * as ub from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; +import * as ub from '@tloncorp/shared/urbit'; import React, { ReactElement, useCallback, diff --git a/packages/ui/src/components/ContactBook.tsx b/packages/ui/src/components/ContactBook.tsx index 519c20439a..2e9a27a8bb 100644 --- a/packages/ui/src/components/ContactBook.tsx +++ b/packages/ui/src/components/ContactBook.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useMemo, useRef, useState } from 'react'; import { Insets, diff --git a/packages/ui/src/components/ContactRow.tsx b/packages/ui/src/components/ContactRow.tsx index 7b128982da..f3a16bf51e 100644 --- a/packages/ui/src/components/ContactRow.tsx +++ b/packages/ui/src/components/ContactRow.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import React, { useCallback, useMemo } from 'react'; import { ListItemProps } from 'tamagui'; import { Stack, View, XStack } from 'tamagui'; diff --git a/packages/ui/src/components/ContentReference/ContentReference.tsx b/packages/ui/src/components/ContentReference/ContentReference.tsx index 92e8852dd3..d646f6ffa8 100644 --- a/packages/ui/src/components/ContentReference/ContentReference.tsx +++ b/packages/ui/src/components/ContentReference/ContentReference.tsx @@ -1,7 +1,7 @@ // tamagui-ignore -import { ContentReference } from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; -import { getChannelType } from '@tloncorp/shared/dist/urbit'; +import { ContentReference } from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; +import { getChannelType } from '@tloncorp/shared/urbit'; import React from 'react'; import { ComponentProps, useCallback } from 'react'; import { View, XStack, styled } from 'tamagui'; diff --git a/packages/ui/src/components/CreateGroupView.tsx b/packages/ui/src/components/CreateGroupView.tsx index 5554279f81..5e1cd725e3 100644 --- a/packages/ui/src/components/CreateGroupView.tsx +++ b/packages/ui/src/components/CreateGroupView.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useState } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { View, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/DetailView.tsx b/packages/ui/src/components/DetailView.tsx index 56114e46be..67ca80aa24 100644 --- a/packages/ui/src/components/DetailView.tsx +++ b/packages/ui/src/components/DetailView.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as urbit from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import * as urbit from '@tloncorp/shared/urbit'; import { useEffect, useMemo } from 'react'; import { FlatList } from 'react-native'; import { View, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/EditProfileScreenView.tsx b/packages/ui/src/components/EditProfileScreenView.tsx index 329df348c4..4ce4288071 100644 --- a/packages/ui/src/components/EditProfileScreenView.tsx +++ b/packages/ui/src/components/EditProfileScreenView.tsx @@ -1,5 +1,5 @@ -import * as api from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; +import * as api from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useState } from 'react'; import { useForm } from 'react-hook-form'; import { Alert } from 'react-native'; diff --git a/packages/ui/src/components/EditableProfileImages.tsx b/packages/ui/src/components/EditableProfileImages.tsx index 48ede4e14f..9273d13352 100644 --- a/packages/ui/src/components/EditableProfileImages.tsx +++ b/packages/ui/src/components/EditableProfileImages.tsx @@ -1,5 +1,5 @@ -import * as api from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; +import * as api from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; import { ImageBackground } from 'expo-image'; import { ImagePickerAsset } from 'expo-image-picker'; import { diff --git a/packages/ui/src/components/Embed/AudioEmbed.native.tsx b/packages/ui/src/components/Embed/AudioEmbed.native.tsx index d342a799d5..35554548c0 100644 --- a/packages/ui/src/components/Embed/AudioEmbed.native.tsx +++ b/packages/ui/src/components/Embed/AudioEmbed.native.tsx @@ -1,4 +1,4 @@ -import { makePrettyTimeFromMs } from '@tloncorp/shared/src/logic'; +import { makePrettyTimeFromMs } from '@tloncorp/shared/logic'; import { AVPlaybackStatus, Audio as ExpoAudio, diff --git a/packages/ui/src/components/FavoriteGroupsDisplay.tsx b/packages/ui/src/components/FavoriteGroupsDisplay.tsx index 4d64e463ba..904ff0ad5a 100644 --- a/packages/ui/src/components/FavoriteGroupsDisplay.tsx +++ b/packages/ui/src/components/FavoriteGroupsDisplay.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useMemo, useState } from 'react'; import { SizableText, XStack } from 'tamagui'; diff --git a/packages/ui/src/components/GalleryPost/GalleryPost.tsx b/packages/ui/src/components/GalleryPost/GalleryPost.tsx index e2b2aa29d3..5768046552 100644 --- a/packages/ui/src/components/GalleryPost/GalleryPost.tsx +++ b/packages/ui/src/components/GalleryPost/GalleryPost.tsx @@ -1,5 +1,5 @@ import { makePrettyShortDate } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { truncate } from 'lodash'; import { ComponentProps, useCallback, useMemo, useState } from 'react'; import { PropsWithChildren } from 'react'; diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index 0009935d4c..819e13c604 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ScrollView, View, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/GroupJoinRequestSheet.tsx b/packages/ui/src/components/GroupJoinRequestSheet.tsx index 9ceebdee57..52b9b9f9da 100644 --- a/packages/ui/src/components/GroupJoinRequestSheet.tsx +++ b/packages/ui/src/components/GroupJoinRequestSheet.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo } from 'react'; import { useNavigation } from '../contexts'; diff --git a/packages/ui/src/components/GroupMembersScreenView.tsx b/packages/ui/src/components/GroupMembersScreenView.tsx index eedb375113..c01499e68f 100644 --- a/packages/ui/src/components/GroupMembersScreenView.tsx +++ b/packages/ui/src/components/GroupMembersScreenView.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import { GroupPrivacy } from '@tloncorp/shared/dist/db/schema'; +import * as db from '@tloncorp/shared/db'; +import { GroupPrivacy } from '@tloncorp/shared/db/schema'; import { useCallback, useMemo, useState } from 'react'; import { SectionList } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; diff --git a/packages/ui/src/components/GroupPreviewSheet.tsx b/packages/ui/src/components/GroupPreviewSheet.tsx index 07cce52ea8..b457370a20 100644 --- a/packages/ui/src/components/GroupPreviewSheet.tsx +++ b/packages/ui/src/components/GroupPreviewSheet.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { triggerHaptic } from '../utils'; diff --git a/packages/ui/src/components/GroupPrivacySelector.tsx b/packages/ui/src/components/GroupPrivacySelector.tsx index cd07eaad68..cbf1d831c3 100644 --- a/packages/ui/src/components/GroupPrivacySelector.tsx +++ b/packages/ui/src/components/GroupPrivacySelector.tsx @@ -1,4 +1,4 @@ -import { GroupPrivacy } from '@tloncorp/shared/dist/db/schema'; +import { GroupPrivacy } from '@tloncorp/shared/db/schema'; import React from 'react'; import * as Form from './Form'; diff --git a/packages/ui/src/components/GroupSelectorSheet.tsx b/packages/ui/src/components/GroupSelectorSheet.tsx index 04b2d4ec16..4ba117d2a6 100644 --- a/packages/ui/src/components/GroupSelectorSheet.tsx +++ b/packages/ui/src/components/GroupSelectorSheet.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { NativeScrollEvent, diff --git a/packages/ui/src/components/ImageViewerScreenView.tsx b/packages/ui/src/components/ImageViewerScreenView.tsx index 50be792606..d3732da854 100644 --- a/packages/ui/src/components/ImageViewerScreenView.tsx +++ b/packages/ui/src/components/ImageViewerScreenView.tsx @@ -1,5 +1,5 @@ import { ImageZoom } from '@likashefqet/react-native-image-zoom'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { BlurView } from 'expo-blur'; import * as Haptics from 'expo-haptics'; import { useRef, useState } from 'react'; diff --git a/packages/ui/src/components/InviteFriendsToTlonButton.tsx b/packages/ui/src/components/InviteFriendsToTlonButton.tsx index dd6c2ea229..6a83e3d13f 100644 --- a/packages/ui/src/components/InviteFriendsToTlonButton.tsx +++ b/packages/ui/src/components/InviteFriendsToTlonButton.tsx @@ -1,6 +1,6 @@ -import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import { AnalyticsEvent, createDevLogger } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback, useEffect } from 'react'; import { Share } from 'react-native'; import { Text, View, XStack, isWeb } from 'tamagui'; diff --git a/packages/ui/src/components/InviteUsersSheet.tsx b/packages/ui/src/components/InviteUsersSheet.tsx index e4bbac26c5..bb18c0e367 100644 --- a/packages/ui/src/components/InviteUsersSheet.tsx +++ b/packages/ui/src/components/InviteUsersSheet.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import React, { useRef } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; diff --git a/packages/ui/src/components/InviteUsersWidget.tsx b/packages/ui/src/components/InviteUsersWidget.tsx index a3c3cf0f47..bd51d05dde 100644 --- a/packages/ui/src/components/InviteUsersWidget.tsx +++ b/packages/ui/src/components/InviteUsersWidget.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import React, { useCallback, useMemo, useState } from 'react'; import { ActionSheet } from './ActionSheet'; diff --git a/packages/ui/src/components/ListItem/ChannelListItem.tsx b/packages/ui/src/components/ListItem/ChannelListItem.tsx index 7365ac7d7c..709c0162ff 100644 --- a/packages/ui/src/components/ListItem/ChannelListItem.tsx +++ b/packages/ui/src/components/ListItem/ChannelListItem.tsx @@ -1,5 +1,5 @@ -import type * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import type * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import { useMemo } from 'react'; import * as utils from '../../utils'; diff --git a/packages/ui/src/components/ListItem/ChatListItem.tsx b/packages/ui/src/components/ListItem/ChatListItem.tsx index 7289fff988..5cb2b19ff0 100644 --- a/packages/ui/src/components/ListItem/ChatListItem.tsx +++ b/packages/ui/src/components/ListItem/ChatListItem.tsx @@ -1,5 +1,5 @@ -import type * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import type * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import React, { useMemo } from 'react'; import { Chat } from '../ChatList'; diff --git a/packages/ui/src/components/ListItem/ContactListItem.tsx b/packages/ui/src/components/ListItem/ContactListItem.tsx index c9ef562be3..2c5cc9c363 100644 --- a/packages/ui/src/components/ListItem/ContactListItem.tsx +++ b/packages/ui/src/components/ListItem/ContactListItem.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ComponentProps } from 'react'; import { SizableText } from 'tamagui'; diff --git a/packages/ui/src/components/ListItem/GroupListItem.tsx b/packages/ui/src/components/ListItem/GroupListItem.tsx index fa7a379000..6ce6425ce3 100644 --- a/packages/ui/src/components/ListItem/GroupListItem.tsx +++ b/packages/ui/src/components/ListItem/GroupListItem.tsx @@ -1,5 +1,5 @@ -import type * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import type * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import { Badge } from '../Badge'; import type { ListItemProps } from './ListItem'; diff --git a/packages/ui/src/components/ListItem/InteractableChatListItem.tsx b/packages/ui/src/components/ListItem/InteractableChatListItem.tsx index c05b8bb651..c49d0f28f0 100644 --- a/packages/ui/src/components/ListItem/InteractableChatListItem.tsx +++ b/packages/ui/src/components/ListItem/InteractableChatListItem.tsx @@ -1,6 +1,6 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; import * as Haptics from 'expo-haptics'; import React, { ComponentProps, diff --git a/packages/ui/src/components/ListItem/ListItem.tsx b/packages/ui/src/components/ListItem/ListItem.tsx index 6fa8c7a288..a577bbb385 100644 --- a/packages/ui/src/components/ListItem/ListItem.tsx +++ b/packages/ui/src/components/ListItem/ListItem.tsx @@ -1,5 +1,5 @@ import { utils } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ComponentProps, ReactElement, useMemo } from 'react'; import { isWeb, styled, withStaticProperties } from 'tamagui'; import { SizableText, Stack, View, XStack, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/ListItem/listItemUtils.tsx b/packages/ui/src/components/ListItem/listItemUtils.tsx index f1b3134f53..547c8f5624 100644 --- a/packages/ui/src/components/ListItem/listItemUtils.tsx +++ b/packages/ui/src/components/ListItem/listItemUtils.tsx @@ -1,4 +1,4 @@ -import type * as db from '@tloncorp/shared/dist/db'; +import type * as db from '@tloncorp/shared/db'; import { useCallback } from 'react'; export function useBoundHandler(model: T, handler?: (model: T) => void) { diff --git a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx index 8ee015b8b5..7b4f109fae 100644 --- a/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx +++ b/packages/ui/src/components/ManageChannels/CreateChannelSheet.tsx @@ -5,7 +5,7 @@ import { PostContentRendererId, useCreateChannel, } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ElementRef, forwardRef, diff --git a/packages/ui/src/components/ManageChannels/EditChannelScreenView.tsx b/packages/ui/src/components/ManageChannels/EditChannelScreenView.tsx index 810dd39d26..10df4e7bec 100644 --- a/packages/ui/src/components/ManageChannels/EditChannelScreenView.tsx +++ b/packages/ui/src/components/ManageChannels/EditChannelScreenView.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useCallback, useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { View, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx index 9d3652a5d3..7c85fbc82c 100644 --- a/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx +++ b/packages/ui/src/components/ManageChannels/ManageChannelsScreenView.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { omit } from 'lodash'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { LayoutRectangle } from 'react-native'; diff --git a/packages/ui/src/components/MentionPopup.tsx b/packages/ui/src/components/MentionPopup.tsx index 832bfe7f5b..d0ebca1c8b 100644 --- a/packages/ui/src/components/MentionPopup.tsx +++ b/packages/ui/src/components/MentionPopup.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import { desig } from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import { desig } from '@tloncorp/shared/urbit'; import { useMemo } from 'react'; import { Dimensions } from 'react-native'; diff --git a/packages/ui/src/components/MessageInput/InputMentionPopup.tsx b/packages/ui/src/components/MessageInput/InputMentionPopup.tsx index a12be70a13..defa826768 100644 --- a/packages/ui/src/components/MessageInput/InputMentionPopup.tsx +++ b/packages/ui/src/components/MessageInput/InputMentionPopup.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { View, YStack } from 'tamagui'; import MentionPopup from '../MentionPopup'; diff --git a/packages/ui/src/components/MessageInput/MessageInputBase.tsx b/packages/ui/src/components/MessageInput/MessageInputBase.tsx index d1fe6b936e..7d12dfa812 100644 --- a/packages/ui/src/components/MessageInput/MessageInputBase.tsx +++ b/packages/ui/src/components/MessageInput/MessageInputBase.tsx @@ -1,6 +1,6 @@ import type { EditorBridge } from '@10play/tentap-editor'; -import * as db from '@tloncorp/shared/dist/db'; -import { JSONContent, Story } from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import { JSONContent, Story } from '@tloncorp/shared/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; import { memo } from 'react'; import { PropsWithChildren } from 'react'; diff --git a/packages/ui/src/components/MessageInput/helpers.ts b/packages/ui/src/components/MessageInput/helpers.ts index 854cd917fe..f71dc2d304 100644 --- a/packages/ui/src/components/MessageInput/helpers.ts +++ b/packages/ui/src/components/MessageInput/helpers.ts @@ -1,13 +1,13 @@ import { EditorBridge } from '@10play/tentap-editor'; import { Editor } from '@tiptap/react'; -import { createDevLogger, tiptap } from '@tloncorp/shared/dist'; +import { createDevLogger, tiptap } from '@tloncorp/shared'; import { Block, Inline, JSONContent, constructStory, isInline, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import { Attachment } from '../../contexts'; diff --git a/packages/ui/src/components/MessageInput/index.native.tsx b/packages/ui/src/components/MessageInput/index.native.tsx index f416696daa..385d984541 100644 --- a/packages/ui/src/components/MessageInput/index.native.tsx +++ b/packages/ui/src/components/MessageInput/index.native.tsx @@ -20,12 +20,13 @@ import { createDevLogger, extractContentTypesFromPost, tiptap, -} from '@tloncorp/shared/dist'; +} from '@tloncorp/shared'; import { contentReferenceToCite, toContentReference, -} from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; +} from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import { Block, Inline, @@ -35,8 +36,7 @@ import { constructStory, isInline, pathToCite, -} from '@tloncorp/shared/dist/urbit'; -import * as logic from '@tloncorp/shared/src/logic'; +} from '@tloncorp/shared/urbit'; import { forwardRef, useCallback, diff --git a/packages/ui/src/components/MessageInput/index.tsx b/packages/ui/src/components/MessageInput/index.tsx index 9902540c7e..523c41d1cf 100644 --- a/packages/ui/src/components/MessageInput/index.tsx +++ b/packages/ui/src/components/MessageInput/index.tsx @@ -18,12 +18,12 @@ import { createDevLogger, extractContentTypesFromPost, tiptap, -} from '@tloncorp/shared/dist'; +} from '@tloncorp/shared'; import { contentReferenceToCite, toContentReference, -} from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; +} from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; import { Block, Image, @@ -34,7 +34,7 @@ import { constructStory, isInline, pathToCite, -} from '@tloncorp/shared/dist/urbit'; +} from '@tloncorp/shared/urbit'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { Keyboard } from 'react-native'; import { View, YStack } from 'tamagui'; @@ -317,8 +317,7 @@ export function MessageInput({ .map((inline) => { if (typeof inline === 'string') { const inlineLength = inline.length; - const refLength = - inline.match(REF_REGEX)?.[0].length || 0; + const refLength = inline.match(REF_REGEX)?.[0].length || 0; if (inlineLength === refLength) { return null; diff --git a/packages/ui/src/components/MetaEditorScreenView.tsx b/packages/ui/src/components/MetaEditorScreenView.tsx index ba66c0af9b..1b3955f8e9 100644 --- a/packages/ui/src/components/MetaEditorScreenView.tsx +++ b/packages/ui/src/components/MetaEditorScreenView.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as logic from '@tloncorp/shared/dist/logic'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; import { PropsWithChildren, useCallback, diff --git a/packages/ui/src/components/NavBarView.tsx b/packages/ui/src/components/NavBarView.tsx index 8c24be9958..d07ba83733 100644 --- a/packages/ui/src/components/NavBarView.tsx +++ b/packages/ui/src/components/NavBarView.tsx @@ -1,4 +1,4 @@ -import * as store from '@tloncorp/shared/dist/store'; +import * as store from '@tloncorp/shared/store'; import { AvatarNavIcon, NavBar, NavIcon } from './NavBar'; diff --git a/packages/ui/src/components/NotebookPost/NotebookPost.tsx b/packages/ui/src/components/NotebookPost/NotebookPost.tsx index dfc55e794a..67f09de130 100644 --- a/packages/ui/src/components/NotebookPost/NotebookPost.tsx +++ b/packages/ui/src/components/NotebookPost/NotebookPost.tsx @@ -1,5 +1,5 @@ import { makePrettyShortDate } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ComponentProps, useCallback, useMemo, useState } from 'react'; import { View, diff --git a/packages/ui/src/components/Onboarding/OnboardingInvite.tsx b/packages/ui/src/components/Onboarding/OnboardingInvite.tsx index b926d7f201..f8c50f9d71 100644 --- a/packages/ui/src/components/Onboarding/OnboardingInvite.tsx +++ b/packages/ui/src/components/Onboarding/OnboardingInvite.tsx @@ -1,4 +1,4 @@ -import { DeepLinkMetadata } from '@tloncorp/shared/dist'; +import { DeepLinkMetadata } from '@tloncorp/shared'; import React, { ComponentProps } from 'react'; import { AppDataContextProvider } from '../../contexts'; diff --git a/packages/ui/src/components/PostContent/ContentRenderer.tsx b/packages/ui/src/components/PostContent/ContentRenderer.tsx index fb69a1454d..3f340a97b7 100644 --- a/packages/ui/src/components/PostContent/ContentRenderer.tsx +++ b/packages/ui/src/components/PostContent/ContentRenderer.tsx @@ -1,4 +1,4 @@ -import { Post } from '@tloncorp/shared/dist/db'; +import { Post } from '@tloncorp/shared/db'; import { ComponentProps, useMemo } from 'react'; import React from 'react'; import { YStack, styled } from 'tamagui'; diff --git a/packages/ui/src/components/PostContent/contentUtils.tsx b/packages/ui/src/components/PostContent/contentUtils.tsx index a93584aed4..c2df18d22b 100644 --- a/packages/ui/src/components/PostContent/contentUtils.tsx +++ b/packages/ui/src/components/PostContent/contentUtils.tsx @@ -1,7 +1,7 @@ import { utils } from '@tloncorp/shared'; -import * as api from '@tloncorp/shared/dist/api'; -import { Post } from '@tloncorp/shared/dist/db'; -import * as ub from '@tloncorp/shared/dist/urbit'; +import * as api from '@tloncorp/shared/api'; +import { Post } from '@tloncorp/shared/db'; +import * as ub from '@tloncorp/shared/urbit'; import { useContext, useMemo } from 'react'; import { createStyledContext } from 'tamagui'; diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 19736cbcaa..03098f615b 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -1,7 +1,7 @@ -import { isChatChannel as getIsChatChannel } from '@tloncorp/shared/dist'; -import type * as db from '@tloncorp/shared/dist/db'; -import * as urbit from '@tloncorp/shared/dist/urbit'; -import { Story } from '@tloncorp/shared/dist/urbit'; +import { isChatChannel as getIsChatChannel } from '@tloncorp/shared'; +import type * as db from '@tloncorp/shared/db'; +import * as urbit from '@tloncorp/shared/urbit'; +import { Story } from '@tloncorp/shared/urbit'; import { ImagePickerAsset } from 'expo-image-picker'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FlatList } from 'react-native'; diff --git a/packages/ui/src/components/ProfileRow.tsx b/packages/ui/src/components/ProfileRow.tsx index de70bed86d..d163fc2f0d 100644 --- a/packages/ui/src/components/ProfileRow.tsx +++ b/packages/ui/src/components/ProfileRow.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { XStack, YStack } from 'tamagui'; import { ContactAvatar } from './Avatar'; diff --git a/packages/ui/src/components/ProfileSheet.tsx b/packages/ui/src/components/ProfileSheet.tsx index 53fb752305..a6e7348845 100644 --- a/packages/ui/src/components/ProfileSheet.tsx +++ b/packages/ui/src/components/ProfileSheet.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback } from 'react'; import { useCurrentUserId } from '../contexts/appDataContext'; @@ -112,10 +112,7 @@ export function ProfileSheet({ ); return ( - + diff --git a/packages/ui/src/components/SendPostRetrySheet.tsx b/packages/ui/src/components/SendPostRetrySheet.tsx index bf806e6dd5..ba9c42d78b 100644 --- a/packages/ui/src/components/SendPostRetrySheet.tsx +++ b/packages/ui/src/components/SendPostRetrySheet.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo } from 'react'; import { Action, SimpleActionSheet } from './ActionSheet'; diff --git a/packages/ui/src/components/UserProfileScreenView.tsx b/packages/ui/src/components/UserProfileScreenView.tsx index 17355e0803..f007abc6be 100644 --- a/packages/ui/src/components/UserProfileScreenView.tsx +++ b/packages/ui/src/components/UserProfileScreenView.tsx @@ -1,6 +1,6 @@ -import * as api from '@tloncorp/shared/dist/api'; -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as api from '@tloncorp/shared/api'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { useCallback, useMemo } from 'react'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { diff --git a/packages/ui/src/components/draftInputs/shared.ts b/packages/ui/src/components/draftInputs/shared.ts index 4f4519a163..135061bfb2 100644 --- a/packages/ui/src/components/draftInputs/shared.ts +++ b/packages/ui/src/components/draftInputs/shared.ts @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import { JSONContent, Story } from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import { JSONContent, Story } from '@tloncorp/shared/urbit'; import { Dispatch, SetStateAction } from 'react'; export type GalleryDraftType = 'caption' | 'text'; diff --git a/packages/ui/src/contexts/appDataContext.tsx b/packages/ui/src/contexts/appDataContext.tsx index 3400ad6de3..3c3bac1291 100644 --- a/packages/ui/src/contexts/appDataContext.tsx +++ b/packages/ui/src/contexts/appDataContext.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import { Session } from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import { Session } from '@tloncorp/shared/store'; import { PropsWithChildren, createContext, useContext, useMemo } from 'react'; export type CalmState = { diff --git a/packages/ui/src/contexts/attachment.tsx b/packages/ui/src/contexts/attachment.tsx index 2511ffdbb4..e00874f243 100644 --- a/packages/ui/src/contexts/attachment.tsx +++ b/packages/ui/src/contexts/attachment.tsx @@ -1,9 +1,9 @@ -import { ContentReference } from '@tloncorp/shared/dist/api'; +import { ContentReference } from '@tloncorp/shared/api'; import { UploadState, useUploadStates, waitForUploads, -} from '@tloncorp/shared/dist/store'; +} from '@tloncorp/shared/store'; import { ImagePickerAsset } from 'expo-image-picker'; import { PropsWithChildren, diff --git a/packages/ui/src/contexts/channel.tsx b/packages/ui/src/contexts/channel.tsx index f16f6c7e27..79f69c0bce 100644 --- a/packages/ui/src/contexts/channel.tsx +++ b/packages/ui/src/contexts/channel.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ReactNode, createContext, useContext } from 'react'; export type ChannelState = { diff --git a/packages/ui/src/contexts/chatOptions.tsx b/packages/ui/src/contexts/chatOptions.tsx index 5d0fe22060..fbed826993 100644 --- a/packages/ui/src/contexts/chatOptions.tsx +++ b/packages/ui/src/contexts/chatOptions.tsx @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as store from '@tloncorp/shared/dist/store'; +import * as db from '@tloncorp/shared/db'; +import * as store from '@tloncorp/shared/store'; import { ReactNode, createContext, diff --git a/packages/ui/src/contexts/componentsKits.tsx b/packages/ui/src/contexts/componentsKits.tsx index 2d3714d85f..265db7000c 100644 --- a/packages/ui/src/contexts/componentsKits.tsx +++ b/packages/ui/src/contexts/componentsKits.tsx @@ -1,6 +1,6 @@ import { DraftInputId, PostContentRendererId } from '@tloncorp/shared'; -import * as db from '@tloncorp/shared/dist/db'; -import { Story } from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import { Story } from '@tloncorp/shared/urbit'; import { ReactElement, createContext, useContext, useMemo } from 'react'; import { ChatMessage } from '../components/ChatMessage'; diff --git a/packages/ui/src/contexts/groups.tsx b/packages/ui/src/contexts/groups.tsx index bd57bf0641..f5d1463064 100644 --- a/packages/ui/src/contexts/groups.tsx +++ b/packages/ui/src/contexts/groups.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { createContext, useContext, useMemo } from 'react'; type State = { diff --git a/packages/ui/src/contexts/navigation.tsx b/packages/ui/src/contexts/navigation.tsx index 960a5ffa58..68ab156349 100644 --- a/packages/ui/src/contexts/navigation.tsx +++ b/packages/ui/src/contexts/navigation.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { createContext, useContext, useMemo } from 'react'; type State = { diff --git a/packages/ui/src/contexts/requests.tsx b/packages/ui/src/contexts/requests.tsx index 0658ad226b..3f4557a7b5 100644 --- a/packages/ui/src/contexts/requests.tsx +++ b/packages/ui/src/contexts/requests.tsx @@ -3,8 +3,8 @@ import { useGroupPreview, usePostReference, usePostWithRelations, -} from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; +} from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; import { isEqual } from 'lodash'; import { PropsWithChildren, diff --git a/packages/ui/src/contexts/thread.tsx b/packages/ui/src/contexts/thread.tsx index 8555f69beb..084bda0a82 100644 --- a/packages/ui/src/contexts/thread.tsx +++ b/packages/ui/src/contexts/thread.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { ReactNode, createContext, useContext } from 'react'; export type ThreadState = { diff --git a/packages/ui/src/hooks/contactSorters.ts b/packages/ui/src/hooks/contactSorters.ts index e319d3703e..c960e1470c 100644 --- a/packages/ui/src/hooks/contactSorters.ts +++ b/packages/ui/src/hooks/contactSorters.ts @@ -1,6 +1,6 @@ -import { createDevLogger, logSyncDuration } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; -import { preSig } from '@tloncorp/shared/src/urbit'; +import { createDevLogger, logSyncDuration } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; +import { preSig } from '@tloncorp/shared/urbit'; import anyAscii from 'any-ascii'; import { useMemo } from 'react'; import { isValidPatp } from 'urbit-ob'; diff --git a/packages/ui/src/hooks/groupsSorters.ts b/packages/ui/src/hooks/groupsSorters.ts index d68edf4e4e..2c256119bb 100644 --- a/packages/ui/src/hooks/groupsSorters.ts +++ b/packages/ui/src/hooks/groupsSorters.ts @@ -1,5 +1,5 @@ -import { createDevLogger, logSyncDuration } from '@tloncorp/shared/dist'; -import * as db from '@tloncorp/shared/dist/db'; +import { createDevLogger, logSyncDuration } from '@tloncorp/shared'; +import * as db from '@tloncorp/shared/db'; import anyAscii from 'any-ascii'; import { useMemo } from 'react'; diff --git a/packages/ui/src/utils/channelUtils.tsx b/packages/ui/src/utils/channelUtils.tsx index 02d566df31..b57658a548 100644 --- a/packages/ui/src/utils/channelUtils.tsx +++ b/packages/ui/src/utils/channelUtils.tsx @@ -1,6 +1,6 @@ import { configurationFromChannel } from '@tloncorp/shared'; -import type * as db from '@tloncorp/shared/dist/db'; -import { useMemberRoles } from '@tloncorp/shared/dist/store'; +import type * as db from '@tloncorp/shared/db'; +import { useMemberRoles } from '@tloncorp/shared/store'; import { useMemo } from 'react'; import type { IconType } from '../components/Icon'; diff --git a/packages/ui/src/utils/postUtils.tsx b/packages/ui/src/utils/postUtils.tsx index 6f43d7e9e9..41ea73f98f 100644 --- a/packages/ui/src/utils/postUtils.tsx +++ b/packages/ui/src/utils/postUtils.tsx @@ -1,4 +1,4 @@ -import * as db from '@tloncorp/shared/dist/db'; +import * as db from '@tloncorp/shared/db'; import { useMemo } from 'react'; export interface ReactionDetails { diff --git a/packages/ui/src/utils/user.ts b/packages/ui/src/utils/user.ts index 80b9d50ed6..2debf00acb 100644 --- a/packages/ui/src/utils/user.ts +++ b/packages/ui/src/utils/user.ts @@ -1,5 +1,5 @@ -import * as db from '@tloncorp/shared/dist/db'; -import * as urbit from '@tloncorp/shared/dist/urbit'; +import * as db from '@tloncorp/shared/db'; +import * as urbit from '@tloncorp/shared/urbit'; import { cite as shorten } from '@urbit/aura'; const USER_ID_SEPARATORS = /([_^-])/; diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 2d14224768..4fe6447528 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../../tsconfig", "include": ["./src"], "compilerOptions": { - "composite": true, - "moduleResolution": "bundler" + "composite": true } } diff --git a/tsconfig.json b/tsconfig.json index 6755f6847b..d874b39826 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,7 @@ "incremental": true, "jsx": "react-jsx", "forceConsistentCasingInFileNames": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "noEmitOnError": false, "noImplicitAny": true, "noImplicitReturns": false, From 8f529c9bfe016bcd0daa2d76e94e65315eb0f5dd Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 27 Oct 2024 11:51:18 -0700 Subject: [PATCH 215/259] specific changes for tlon-mobile --- apps/tlon-mobile/src/fixtures/fakeData.ts | 2 +- packages/app/features/groups/GroupPrivacyScreen.tsx | 4 +++- packages/app/lib/nativeDb.ts | 2 +- packages/app/lib/sqliteConnection.ts | 2 +- packages/shared/package.json | 2 ++ packages/shared/src/db/index.ts | 3 ++- packages/ui/src/components/ChannelSearch/SearchStatus.tsx | 2 +- packages/ui/src/components/GroupMembersScreenView.tsx | 3 ++- packages/ui/src/components/GroupPrivacySelector.tsx | 4 +++- packages/ui/src/components/UrbitSigilSvg.native.tsx | 2 +- 10 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/tlon-mobile/src/fixtures/fakeData.ts b/apps/tlon-mobile/src/fixtures/fakeData.ts index ae87b64dd8..5ff3e8224b 100644 --- a/apps/tlon-mobile/src/fixtures/fakeData.ts +++ b/apps/tlon-mobile/src/fixtures/fakeData.ts @@ -1,6 +1,6 @@ import * as db from '@tloncorp/shared/db'; import { getTextContent } from '@tloncorp/shared/urbit'; -import type { Story } from '@tloncorp/shared/urbit/channel'; +import type { Story } from '@tloncorp/shared/urbit'; import { formatUd, unixToDa } from '@urbit/aura'; import seedrandom from 'seedrandom'; diff --git a/packages/app/features/groups/GroupPrivacyScreen.tsx b/packages/app/features/groups/GroupPrivacyScreen.tsx index 5343ea5808..8d366436bc 100644 --- a/packages/app/features/groups/GroupPrivacyScreen.tsx +++ b/packages/app/features/groups/GroupPrivacyScreen.tsx @@ -1,5 +1,5 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; -import { GroupPrivacy } from '@tloncorp/shared/db/schema'; +import { schema } from '@tloncorp/shared/db'; import * as store from '@tloncorp/shared/store'; import { GroupPrivacySelector, @@ -12,6 +12,8 @@ import { useCallback } from 'react'; import { useGroupContext } from '../../hooks/useGroupContext'; import { GroupSettingsStackParamList } from '../../navigation/types'; +type GroupPrivacy = schema.GroupPrivacy; + type Props = NativeStackScreenProps; export function GroupPrivacyScreen(props: Props) { diff --git a/packages/app/lib/nativeDb.ts b/packages/app/lib/nativeDb.ts index b4900e4cd5..7559fd395c 100644 --- a/packages/app/lib/nativeDb.ts +++ b/packages/app/lib/nativeDb.ts @@ -1,7 +1,7 @@ import { open } from '@op-engineering/op-sqlite'; import { createDevLogger, escapeLog } from '@tloncorp/shared'; import { handleChange, schema, setClient } from '@tloncorp/shared/db'; -import { AnySqliteDatabase } from '@tloncorp/shared/db/client'; +import { AnySqliteDatabase } from '@tloncorp/shared/db'; import { useEffect, useMemo, useState } from 'react'; import { OPSQLite$SQLiteConnection } from './opsqliteConnection'; diff --git a/packages/app/lib/sqliteConnection.ts b/packages/app/lib/sqliteConnection.ts index 24d8542116..2eb7a59cae 100644 --- a/packages/app/lib/sqliteConnection.ts +++ b/packages/app/lib/sqliteConnection.ts @@ -1,4 +1,4 @@ -import { AnySqliteDatabase } from '@tloncorp/shared/db/client'; +import { AnySqliteDatabase } from '@tloncorp/shared/db'; import { Schema } from '@tloncorp/shared/db/types'; import type { DrizzleConfig } from 'drizzle-orm/utils'; diff --git a/packages/shared/package.json b/packages/shared/package.json index fe835bfd92..89321aefff 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -9,6 +9,8 @@ "./api": "./src/api/index.ts", "./client": "./src/client/index.ts", "./db": "./src/db/index.ts", + "./db/migrations": "./src/db/migrations/index.ts", + "./db/types": "./src/db/types.ts", "./logic": "./src/logic/index.ts", "./perf": "./src/perf.ts", "./store": "./src/store/index.ts", diff --git a/packages/shared/src/db/index.ts b/packages/shared/src/db/index.ts index 059095474d..6cd44f78ce 100644 --- a/packages/shared/src/db/index.ts +++ b/packages/shared/src/db/index.ts @@ -4,6 +4,7 @@ export * from './types'; export * from './fallback'; export * from './modelBuilders'; export * from './keyValue'; -export { setClient } from './client'; +export { AnySqliteDatabase, setClient } from './client'; export * from './changeListener'; export * from './domainTypes'; +export { migrations } from './migrations'; diff --git a/packages/ui/src/components/ChannelSearch/SearchStatus.tsx b/packages/ui/src/components/ChannelSearch/SearchStatus.tsx index 0789d52211..75e7c4240f 100644 --- a/packages/ui/src/components/ChannelSearch/SearchStatus.tsx +++ b/packages/ui/src/components/ChannelSearch/SearchStatus.tsx @@ -1,4 +1,4 @@ -import { makePrettyShortDate } from '@tloncorp/shared/logic/utils'; +import { makePrettyShortDate } from '@tloncorp/shared/logic'; import { ColorTokens } from 'tamagui'; import { SizableText, View, XStack, YStack } from 'tamagui'; diff --git a/packages/ui/src/components/GroupMembersScreenView.tsx b/packages/ui/src/components/GroupMembersScreenView.tsx index c01499e68f..717b459265 100644 --- a/packages/ui/src/components/GroupMembersScreenView.tsx +++ b/packages/ui/src/components/GroupMembersScreenView.tsx @@ -1,5 +1,4 @@ import * as db from '@tloncorp/shared/db'; -import { GroupPrivacy } from '@tloncorp/shared/db/schema'; import { useCallback, useMemo, useState } from 'react'; import { SectionList } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -12,6 +11,8 @@ import { ProfileSheet } from './ProfileSheet'; import { ScreenHeader } from './ScreenHeader'; import { SectionListHeader } from './SectionList'; +type GroupPrivacy = db.schema.GroupPrivacy; + export function GroupMembersScreenView({ goBack, members, diff --git a/packages/ui/src/components/GroupPrivacySelector.tsx b/packages/ui/src/components/GroupPrivacySelector.tsx index cbf1d831c3..fb7709e0a5 100644 --- a/packages/ui/src/components/GroupPrivacySelector.tsx +++ b/packages/ui/src/components/GroupPrivacySelector.tsx @@ -1,8 +1,10 @@ -import { GroupPrivacy } from '@tloncorp/shared/db/schema'; +import { schema } from '@tloncorp/shared/db'; import React from 'react'; import * as Form from './Form'; +type GroupPrivacy = schema.GroupPrivacy; + function GroupPrivacySelectorRaw(props: { currentValue: GroupPrivacy; onChange: (newValue: GroupPrivacy) => void; diff --git a/packages/ui/src/components/UrbitSigilSvg.native.tsx b/packages/ui/src/components/UrbitSigilSvg.native.tsx index a9477e50fe..09228e11ea 100644 --- a/packages/ui/src/components/UrbitSigilSvg.native.tsx +++ b/packages/ui/src/components/UrbitSigilSvg.native.tsx @@ -1,6 +1,6 @@ // Note: the import statement for sigil is different in the native version // The native version uses the core entry point of sigil-js -import sigil from '@urbit/sigil-js/dist/core'; +import sigil from '@urbit/sigil-js/core'; import { SvgXml } from 'react-native-svg'; export const makeSigil = sigil; From 7d95a014ee22a9fa7fa1c7a6ce09d3a023d27c51 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 27 Oct 2024 12:00:27 -0700 Subject: [PATCH 216/259] specific changes for tlon-web-new --- packages/shared/package.json | 7 ++++++- packages/shared/src/db/index.ts | 3 ++- packages/shared/src/index.ts | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/shared/package.json b/packages/shared/package.json index 89321aefff..82f39e653e 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -14,7 +14,12 @@ "./logic": "./src/logic/index.ts", "./perf": "./src/perf.ts", "./store": "./src/store/index.ts", - "./urbit": "./src/urbit/index.ts" + "./urbit": "./src/urbit/index.ts", + "./urbit/activity": "./src/urbit/activity.ts", + "./urbit/channel": "./src/urbit/channel.ts", + "./urbit/content": "./src/urbit/content.ts", + "./urbit/groups": "./src/urbit/groups.ts", + "./urbit/hark": "./src/urbit/hark.ts" }, "scripts": { "build": "tsup", diff --git a/packages/shared/src/db/index.ts b/packages/shared/src/db/index.ts index 6cd44f78ce..e0cd43ac34 100644 --- a/packages/shared/src/db/index.ts +++ b/packages/shared/src/db/index.ts @@ -4,7 +4,8 @@ export * from './types'; export * from './fallback'; export * from './modelBuilders'; export * from './keyValue'; -export { AnySqliteDatabase, setClient } from './client'; +export { setClient } from './client'; +export type { AnySqliteDatabase } from './client'; export * from './changeListener'; export * from './domainTypes'; export { migrations } from './migrations'; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 0cefbc2504..bae870b668 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -9,10 +9,12 @@ export type { WebAppAction, WebAppCommand, } from './types/native'; -export { +export type { PostCollectionConfiguration, PostCollectionLayout, PostCollectionLayoutType, +} from './types/PostCollectionConfiguration'; +export { configurationFromChannel, layoutForType, layoutTypeFromChannel, From 1e1ebb36cc4a7bc1ab59d644061ada6dea9fed05 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 27 Oct 2024 12:05:25 -0700 Subject: [PATCH 217/259] specific changes for tlon-web --- apps/tlon-web/src/channels/ChannelActions.tsx | 2 +- apps/tlon-web/src/state/lure/lure.ts | 2 +- packages/shared/package.json | 8 +++++++- packages/shared/src/index.ts | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/tlon-web/src/channels/ChannelActions.tsx b/apps/tlon-web/src/channels/ChannelActions.tsx index ffd1f00596..b8107718ca 100644 --- a/apps/tlon-web/src/channels/ChannelActions.tsx +++ b/apps/tlon-web/src/channels/ChannelActions.tsx @@ -1,4 +1,4 @@ -import { getPrettyAppName } from '@tloncorp/shared/logic/utils'; +import { getPrettyAppName } from '@tloncorp/shared/logic'; import { GroupChannel } from '@tloncorp/shared/urbit/groups'; import cn from 'classnames'; import React, { PropsWithChildren, useCallback, useState } from 'react'; diff --git a/apps/tlon-web/src/state/lure/lure.ts b/apps/tlon-web/src/state/lure/lure.ts index 9a062381ce..0689190d3d 100644 --- a/apps/tlon-web/src/state/lure/lure.ts +++ b/apps/tlon-web/src/state/lure/lure.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; +import { Contact } from '@tloncorp/shared/urbit'; import { GroupMeta } from '@tloncorp/shared/urbit/groups'; import produce from 'immer'; -import { Contact } from 'packages/shared/urbit'; import { useCallback, useEffect, useMemo, useRef } from 'react'; import create from 'zustand'; import { persist } from 'zustand/middleware'; diff --git a/packages/shared/package.json b/packages/shared/package.json index 82f39e653e..b4d6c0176c 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -17,9 +17,15 @@ "./urbit": "./src/urbit/index.ts", "./urbit/activity": "./src/urbit/activity.ts", "./urbit/channel": "./src/urbit/channel.ts", + "./urbit/contact": "./src/urbit/contact.ts", "./urbit/content": "./src/urbit/content.ts", + "./urbit/dms": "./src/urbit/dms.ts", "./urbit/groups": "./src/urbit/groups.ts", - "./urbit/hark": "./src/urbit/hark.ts" + "./urbit/hark": "./src/urbit/hark.ts", + "./urbit/negotiation": "./src/urbit/negotiation.ts", + "./urbit/sigil": "./src/urbit/sigil.ts", + "./urbit/ui": "./src/urbit/ui.ts", + "./urbit/volume": "./src/urbit/volume.ts" }, "scripts": { "build": "tsup", diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index bae870b668..386beb74fb 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -19,11 +19,11 @@ export { layoutForType, layoutTypeFromChannel, } from './types/PostCollectionConfiguration'; +export type { ChannelContentConfiguration } from './api/channelContentConfig'; export { CollectionRendererId, DraftInputId, PostContentRendererId, - ChannelContentConfiguration, } from './api/channelContentConfig'; export { parseActiveTab, trimFullPath } from './logic/navigation'; export * from './logic'; From 1e11510258f2b6c332b7a27053f6b5456885e480 Mon Sep 17 00:00:00 2001 From: David Lee Date: Sun, 27 Oct 2024 12:07:29 -0700 Subject: [PATCH 218/259] Remove tsup config --- packages/shared/package.json | 6 ----- packages/shared/tsup.config.ts | 40 ---------------------------------- pnpm-lock.yaml | 16 +------------- 3 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 packages/shared/tsup.config.ts diff --git a/packages/shared/package.json b/packages/shared/package.json index b4d6c0176c..0c07d51984 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -28,9 +28,7 @@ "./urbit/volume": "./src/urbit/volume.ts" }, "scripts": { - "build": "tsup", "preinstall": "rm -f ./tsconfig.tsbuildinfo", - "dev": "pnpm build --watch", "dev:migrations": "concurrently \"pnpm watch-migrations\" \"pnpm dev\"", "test": "vitest", "types": "tsc --emitDeclarationOnly --noEmit false", @@ -62,7 +60,6 @@ "@types/better-sqlite3": "^7.6.9", "better-sqlite3": "~9.4.3", "drizzle-kit": "0.20.17", - "tsup": "^8.0.1", "typescript": "5.1.3", "vitest": "^1.4.0" }, @@ -75,8 +72,5 @@ "drizzle-orm": "0.30.9", "react": "^18.2.0", "zustand": "^3.7.2" - }, - "optionalDependencies": { - "@rollup/rollup-linux-x64-gnu": "4.9.5" } } diff --git a/packages/shared/tsup.config.ts b/packages/shared/tsup.config.ts deleted file mode 100644 index 8102813f0e..0000000000 --- a/packages/shared/tsup.config.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { exec } from 'child_process'; -import { defineConfig } from 'tsup'; - -export default defineConfig({ - entryPoints: [ - 'src/index.ts', - 'src/urbit/*', - 'src/client/index.ts', - 'src/db/index.ts', - 'src/hooks/index.ts', - 'src/db/migrations/index.ts', - 'src/api/index.ts', - 'src/logic/index.ts', - 'src/store/index.ts', - ], - format: ['esm'], - minify: false, - external: [ - 'react', - '@aws-sdk/client-s3', - '@aws-sdk/s3-request-presigner', - 'expo-image-manipulator', - 'expo-image-picker', - 'expo-file-system', - '@react-native-firebase/crashlytics', - '@react-native-community/netinfo', - 'expo-battery', - ], - ignoreWatch: ['**/node_modules/**', '**/.git/**'], - loader: { - '.sql': 'text', - }, - onSuccess() { - return new Promise((resolve, reject) => { - exec('pnpm types', (err) => { - err ? reject(err) : resolve(); - }); - }); - }, -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15bd06798c..a3ff2ab854 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1667,10 +1667,6 @@ importers: zustand: specifier: ^3.7.2 version: 3.7.2(react@18.2.0) - optionalDependencies: - '@rollup/rollup-linux-x64-gnu': - specifier: 4.9.5 - version: 4.9.5 devDependencies: '@types/better-sqlite3': specifier: ^7.6.9 @@ -1681,9 +1677,6 @@ importers: drizzle-kit: specifier: 0.20.17 version: 0.20.17 - tsup: - specifier: ^8.0.1 - version: 8.0.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(postcss@8.4.35)(typescript@5.4.5) typescript: specifier: 5.4.5 version: 5.4.5 @@ -5097,11 +5090,6 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.9.5': - resolution: {integrity: sha512-Dq1bqBdLaZ1Gb/l2e5/+o3B18+8TI9ANlA1SkejZqDgdU/jK/ThYaMPMJpVMMXy2uRHvGKbkz9vheVGdq3cJfA==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-musl@4.13.0': resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} cpu: [x64] @@ -6616,6 +6604,7 @@ packages: '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} + deprecated: this version is no longer supported, please update to at least 0.8.* '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} @@ -18852,9 +18841,6 @@ snapshots: '@rollup/rollup-linux-x64-gnu@4.13.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.9.5': - optional: true - '@rollup/rollup-linux-x64-musl@4.13.0': optional: true From 972e1476de8a7ce3bf169018d1533a27252c8a1f Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Mon, 28 Oct 2024 07:01:04 -0500 Subject: [PATCH 219/259] fix tlon-web-new deploy issues and add internal deploy --- .github/workflows/deploy-canary.yml | 2 +- .github/workflows/deploy-internal.yml | 21 ++++++++++++++++++++- .github/workflows/deploy.yml | 5 +++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-canary.yml b/.github/workflows/deploy-canary.yml index 1b51aa7d38..5ec0a1a027 100644 --- a/.github/workflows/deploy-canary.yml +++ b/.github/workflows/deploy-canary.yml @@ -121,7 +121,7 @@ jobs: run: | git config --global user.name github-actions git config --global user.email github-actions@github.com - git add desk/desk.docket-0 + git add tm-alpha-desk/desk.docket-0 git commit -n -m "update glob: ${{ steps.glob.outputs.hash }} [skip actions]" || echo "No changes to commit" INPUT=${{ env.tag }} BRANCH=${INPUT:-"staging"} diff --git a/.github/workflows/deploy-internal.yml b/.github/workflows/deploy-internal.yml index b4677680cb..bf0678048e 100644 --- a/.github/workflows/deploy-internal.yml +++ b/.github/workflows/deploy-internal.yml @@ -25,4 +25,23 @@ jobs: env: SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }} SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }} - URBIT_REPO_TAG: ${{ vars.URBIT_REPO_TAG }} \ No newline at end of file + URBIT_REPO_TAG: ${{ vars.URBIT_REPO_TAG }} + deploy-new: + runs-on: ubuntu-latest + name: "Release new frontend to ~marnec-dozzod-marnus (internal)" + steps: + - uses: actions/checkout@v3 + - id: 'auth' + uses: 'google-github-actions/auth@v1' + with: + credentials_json: '${{ secrets.GCP_SERVICE_KEY }}' + - name: 'Set up Cloud SDK' + uses: 'google-github-actions/setup-gcloud@v1' + - id: deploy + name: Deploy + run: + ./.github/helpers/deploy.sh tloncorp/tlon-apps tm-alpha marnec-dozzod-marnus us-central1-a mainnet-tlon-other-2d ${{ github.event.inputs.tag }} + env: + SSH_SEC_KEY: ${{ secrets.GCP_SSH_SEC_KEY }} + SSH_PUB_KEY: ${{ secrets.GCP_SSH_PUB_KEY }} + URBIT_REPO_TAG: ${{ vars.URBIT_REPO_TAG }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d24344fa59..09e0a1d2b3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -107,10 +107,11 @@ jobs: - uses: actions/checkout@v3 with: ref: ${{ env.tag }} + ssh-key: ${{ secrets.DEPLOY_KEY }} - uses: actions/download-artifact@v3 with: name: "ui-dist-new" - path: apps/tlon-web/dist + path: apps/tlon-web-new/dist - id: "auth" uses: "google-github-actions/auth@v1" with: @@ -126,7 +127,7 @@ jobs: run: | git config --global user.name github-actions git config --global user.email github-actions@github.com - git add desk/desk.docket-0 + git add tm-alpha-desk/desk.docket-0 git commit -n -m "update new frontend glob: ${{ steps.glob.outputs.hash }} [skip actions]" || echo "No changes to commit" INPUT=${{ env.tag }} BRANCH=${INPUT:-"develop"} From 97432eb102c677eca60a28e8ee93cdc34e7efde3 Mon Sep 17 00:00:00 2001 From: Dan Brewster Date: Mon, 28 Oct 2024 10:17:58 -0400 Subject: [PATCH 220/259] allow import sql imports in tests --- packages/shared/vitest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/vitest.config.ts b/packages/shared/vitest.config.ts index 715b126baa..5c68efa68a 100644 --- a/packages/shared/vitest.config.ts +++ b/packages/shared/vitest.config.ts @@ -1,6 +1,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ + assetsInclude: ['**/*.sql'], test: { setupFiles: ['./src/test/setup.ts'], }, From b941166944bdecdc3497e4f1a0de689a25104402 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Oct 2024 14:47:22 +0000 Subject: [PATCH 221/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 5f37b0a44d..26df4d3cdd 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v5.0c43a.lnuh2.71lu4.2q7vd.e8tho.glob' 0v5.0c43a.lnuh2.71lu4.2q7vd.e8tho] + glob-http+['https://bootstrap.urbit.org/glob-0verrde.fch7g.1qc24.6v2t7.d01tm.glob' 0verrde.fch7g.1qc24.6v2t7.d01tm] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From d9cc8a5e4ac637de1dc887e8427595791a8796d9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Oct 2024 15:23:52 +0000 Subject: [PATCH 222/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 26df4d3cdd..8d01b88ce9 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0verrde.fch7g.1qc24.6v2t7.d01tm.glob' 0verrde.fch7g.1qc24.6v2t7.d01tm] + glob-http+['https://bootstrap.urbit.org/glob-0v2.ru923.n24nf.5iglu.3c2r6.j6r2s.glob' 0v2.ru923.n24nf.5iglu.3c2r6.j6r2s] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From 20e413b362f86b8179d79b964d0d18da41fad52d Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 28 Oct 2024 09:04:00 -0700 Subject: [PATCH 223/259] Add missing @tloncorp/shared/db/client export --- packages/shared/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/shared/package.json b/packages/shared/package.json index 0c07d51984..cb8b79e953 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -9,6 +9,7 @@ "./api": "./src/api/index.ts", "./client": "./src/client/index.ts", "./db": "./src/db/index.ts", + "./db/client": "./src/db/client.ts", "./db/migrations": "./src/db/migrations/index.ts", "./db/types": "./src/db/types.ts", "./logic": "./src/logic/index.ts", From 4ae2f2d2f0c29736ffaefc8c1b5cf0fb532a6d34 Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 28 Oct 2024 09:11:02 -0700 Subject: [PATCH 224/259] Remove migrations export from db barrel --- packages/app/lib/betterSqlite3Connection.ts | 1 - packages/shared/src/db/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/app/lib/betterSqlite3Connection.ts b/packages/app/lib/betterSqlite3Connection.ts index 62dffa9aaa..148bdc16b3 100644 --- a/packages/app/lib/betterSqlite3Connection.ts +++ b/packages/app/lib/betterSqlite3Connection.ts @@ -50,7 +50,6 @@ export class BetterSqlite3$SQLiteConnection implements SQLiteConnection { Object.entries(migrations.migrations) .sort(([keyA], [keyB]) => keyA.localeCompare(keyB)) .forEach(([_key, migration]) => { - // @ts-expect-error - migration is an SQL import this.execute(migration); }); return; diff --git a/packages/shared/src/db/index.ts b/packages/shared/src/db/index.ts index e0cd43ac34..ce9a2ab5e9 100644 --- a/packages/shared/src/db/index.ts +++ b/packages/shared/src/db/index.ts @@ -8,4 +8,3 @@ export { setClient } from './client'; export type { AnySqliteDatabase } from './client'; export * from './changeListener'; export * from './domainTypes'; -export { migrations } from './migrations'; From 009b66dd3c2ed80af0324974c57d2bd3cb0f3fca Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Mon, 28 Oct 2024 11:28:48 -0500 Subject: [PATCH 225/259] groups-ui: better alignment --- desk/app/groups-ui.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desk/app/groups-ui.hoon b/desk/app/groups-ui.hoon index e6d36188c9..22a435db83 100644 --- a/desk/app/groups-ui.hoon +++ b/desk/app/groups-ui.hoon @@ -258,8 +258,8 @@ =+ .^(chat-running=? (scry %gu %chat /$)) =? cor chat-running =+ .^ [dms=(map ship dm:c) *] - (scry %gx %chat /full/noun) - == + (scry %gx %chat /full/noun) + == %- emil %+ murn ~(tap by dms) From 96fc5fd007476be172de1e6dbc70b7531acd8961 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Oct 2024 16:44:58 +0000 Subject: [PATCH 226/259] update glob: [skip actions] --- desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desk/desk.docket-0 b/desk/desk.docket-0 index c3b94f4bae..039689dedf 100644 --- a/desk/desk.docket-0 +++ b/desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v7.l7jnk.63qrr.ccg4p.ca9be.gs1ra.glob' 0v7.l7jnk.63qrr.ccg4p.ca9be.gs1ra] + glob-http+['https://bootstrap.urbit.org/glob-0v5.f4pdu.bsc20.evndm.111eo.g9061.glob' 0v5.f4pdu.bsc20.evndm.111eo.g9061] base+'groups' version+[6 4 2] website+'https://tlon.io' From b9f0bbddd34da509e076520580912ff04a3b951b Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Mon, 28 Oct 2024 12:50:06 -0500 Subject: [PATCH 227/259] add build:new-web to root package scripts --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b1ffd30b4..f91fa73cad 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ "build:ui": "pnpm --filter '@tloncorp/ui' build", "build:editor": "pnpm --filter '@tloncorp/editor' build", "build:web": "pnpm --filter 'tlon-web' build", + "build:new-web": "pnpm --filter 'tlon-web-new' build", "build:mobile": "pnpm --filter 'tlon-mobile' build", - "build:apps": "pnpm run build:mobile", + "build:apps": "pnpm run build:mobile && pnpm run build:web && pnpm run build:new-web", "build:packages": "pnpm run build:shared && pnpm run build:ui && pnpm run build:editor", "build:all": "pnpm run build:packages && pnpm run build:apps", "dev:shared": "pnpm --filter '@tloncorp/shared' dev", From c6499fdc22eb306e7237cbb8bda9db77362f13ed Mon Sep 17 00:00:00 2001 From: David Lee Date: Mon, 28 Oct 2024 11:30:22 -0700 Subject: [PATCH 228/259] Bundle *.sql imports as `export default {filecontent}` in tlon-web-new --- apps/tlon-web-new/vite.config.mts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/tlon-web-new/vite.config.mts b/apps/tlon-web-new/vite.config.mts index 4cb17ca05b..4ba781a0d1 100644 --- a/apps/tlon-web-new/vite.config.mts +++ b/apps/tlon-web-new/vite.config.mts @@ -3,6 +3,7 @@ import { tamaguiPlugin } from '@tamagui/vite-plugin'; import { urbitPlugin } from '@urbit/vite-plugin-urbit'; import basicSsl from '@vitejs/plugin-basic-ssl'; import react from '@vitejs/plugin-react'; +import fs from 'fs'; import analyze from 'rollup-plugin-analyzer'; import { visualizer } from 'rollup-plugin-visualizer'; import { fileURLToPath } from 'url'; @@ -62,6 +63,7 @@ export default ({ mode }: { mode: string }) => { return [ process.env.SSL === 'true' ? (basicSsl() as PluginOption) : null, + exportingRawText(/\.sql$/), urbitPlugin({ base: mode === 'alpha' ? 'tm-alpha' : 'groups', target: mode === 'dev2' ? SHIP_URL2 : SHIP_URL, @@ -268,3 +270,17 @@ export default ({ mode }: { mode: string }) => { }, }); }; + +/** Transforms matching files into ES modules that export the file's content as a string */ +function exportingRawText(matchId: RegExp): Plugin { + return { + name: 'inline sql', + enforce: 'pre', + transform(_code, id) { + if (matchId.test(id)) { + const sql = fs.readFileSync(id, 'utf-8'); + return `export default ${JSON.stringify(sql)}`; + } + }, + }; +} From 0ddb6d1c3acf8af8ea4abb56672cd8bd98364222 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Oct 2024 20:26:46 +0000 Subject: [PATCH 229/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 8d01b88ce9..840388d1ea 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v2.ru923.n24nf.5iglu.3c2r6.j6r2s.glob' 0v2.ru923.n24nf.5iglu.3c2r6.j6r2s] + glob-http+['https://bootstrap.urbit.org/glob-0v6.6c036.lj7nu.frsbt.vr9ic.a7qhe.glob' 0v6.6c036.lj7nu.frsbt.vr9ic.a7qhe] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From 79c6d8ea3356552e49cc4d62c50de9b5dca14916 Mon Sep 17 00:00:00 2001 From: ~latter-bolden Date: Tue, 29 Oct 2024 08:07:37 -0400 Subject: [PATCH 230/259] catch storage key not found --- packages/app/lib/debug.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/app/lib/debug.ts b/packages/app/lib/debug.ts index 37b7a15fa4..15390392fc 100644 --- a/packages/app/lib/debug.ts +++ b/packages/app/lib/debug.ts @@ -10,6 +10,9 @@ storage }) .then((enabled) => { useDebugStore.getState().toggle(enabled); + }) + .catch(() => { + useDebugStore.getState().toggle(false); }); export const setDebug = async (enabled: boolean) => { From 5a8830de66ace6898123a1f6c1705b65dccbb3a5 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 29 Oct 2024 10:25:13 -0500 Subject: [PATCH 231/259] web-new: add sidebar nav for desktop --- apps/tlon-mobile/package.json | 1 + apps/tlon-web-new/package.json | 1 + apps/tlon-web-new/src/app.tsx | 6 +- apps/tlon-web-new/vite.config.mts | 5 +- package.json | 3 +- .../app/features/settings/ProfileScreen.tsx | 5 +- packages/app/navigation/RootStack.tsx | 6 +- .../desktop/ChannelListDrawerContent.tsx | 66 +++ .../desktop/ChatListDrawerContent.tsx | 236 ++++++++++ .../app/navigation/desktop/HomeNavigator.tsx | 80 ++++ .../app/navigation/desktop/TopLevelDrawer.tsx | 73 +++ packages/app/navigation/types.ts | 10 + .../src/components/Channel/ChannelHeader.tsx | 6 +- packages/ui/src/components/ChatList.tsx | 5 +- .../components/GroupChannelsScreenView.tsx | 5 +- packages/ui/src/components/NavBarView.tsx | 6 + packages/ui/src/hooks/useIsMobile.ts | 6 + packages/ui/src/index.tsx | 1 + patches/@react-navigation__drawer@6.7.2.patch | 441 ++++++++++++++++++ pnpm-lock.yaml | 48 ++ 20 files changed, 997 insertions(+), 13 deletions(-) create mode 100644 packages/app/navigation/desktop/ChannelListDrawerContent.tsx create mode 100644 packages/app/navigation/desktop/ChatListDrawerContent.tsx create mode 100644 packages/app/navigation/desktop/HomeNavigator.tsx create mode 100644 packages/app/navigation/desktop/TopLevelDrawer.tsx create mode 100644 packages/ui/src/hooks/useIsMobile.ts create mode 100644 patches/@react-navigation__drawer@6.7.2.patch diff --git a/apps/tlon-mobile/package.json b/apps/tlon-mobile/package.json index c744dbdadf..643753704d 100644 --- a/apps/tlon-mobile/package.json +++ b/apps/tlon-mobile/package.json @@ -53,6 +53,7 @@ "@react-native-firebase/crashlytics": "^19.2.2", "@react-native-firebase/perf": "19.2.2", "@react-navigation/bottom-tabs": "^6.5.12", + "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.1.7", "@react-navigation/native-stack": "^6.9.13", "@shopify/flash-list": "1.6.3", diff --git a/apps/tlon-web-new/package.json b/apps/tlon-web-new/package.json index 2f1068f381..c8bebed89a 100644 --- a/apps/tlon-web-new/package.json +++ b/apps/tlon-web-new/package.json @@ -48,6 +48,7 @@ "@radix-ui/react-toggle": "^1.0.2", "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.0", + "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.1.7", "@tamagui/vite-plugin": "~1.112.12", "@tanstack/react-query": "^4.28.0", diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index a4e8831be0..dedfcf349a 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -11,6 +11,7 @@ import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; import { checkDb, useMigrations } from '@tloncorp/app/lib/webDb'; import { RootStack } from '@tloncorp/app/navigation/RootStack'; +import { TopLevelDrawer } from '@tloncorp/app/navigation/desktop/TopLevelDrawer'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { sync } from '@tloncorp/shared'; @@ -26,7 +27,7 @@ import { ANALYTICS_DEFAULT_PROPERTIES } from '@/logic/analytics'; import useAppUpdates, { AppUpdateContext } from '@/logic/useAppUpdates'; import useErrorHandler from '@/logic/useErrorHandler'; import useIsStandaloneMode from '@/logic/useIsStandaloneMode'; -import { useIsDark } from '@/logic/useMedia'; +import { useIsDark, useIsMobile } from '@/logic/useMedia'; import { preSig } from '@/logic/utils'; import { toggleDevTools, useLocalState, useShowDevTools } from '@/state/local'; import { useAnalyticsId, useLogActivity, useTheme } from '@/state/settings'; @@ -85,6 +86,7 @@ function AppRoutes({ isLoaded }: { isLoaded: boolean }) { }, [calmSettingsQuery, isLoaded]); const isDarkMode = useIsDarkMode(); + const isMobile = useIsMobile(); const navigationContainerRef = useNavigationContainerRef(); @@ -98,7 +100,7 @@ function AppRoutes({ isLoaded }: { isLoaded: boolean }) { theme={isDarkMode ? DarkTheme : DefaultTheme} ref={navigationContainerRef} > - + {isMobile ? : } ); diff --git a/apps/tlon-web-new/vite.config.mts b/apps/tlon-web-new/vite.config.mts index 4ba781a0d1..7081f90d0a 100644 --- a/apps/tlon-web-new/vite.config.mts +++ b/apps/tlon-web-new/vite.config.mts @@ -115,10 +115,7 @@ export default ({ mode }: { mode: string }) => { external: mode === 'mock' || mode === 'staging' ? ['virtual:pwa-register/react'] - : [ - '@urbit/sigil-js/dist/core', - 'react-native-device-info', - ], + : ['@urbit/sigil-js/dist/core', 'react-native-device-info'], output: { hashCharacters: 'base36' as any, manualChunks: { diff --git a/package.json b/package.json index f91fa73cad..169692cf3a 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,8 @@ "@10play/tentap-editor@0.4.55": "patches/@10play__tentap-editor@0.4.55.patch", "any-ascii@0.3.2": "patches/any-ascii@0.3.2.patch", "@likashefqet/react-native-image-zoom@3.0.0": "patches/@likashefqet__react-native-image-zoom@3.0.0.patch", - "react-native@0.73.4": "patches/react-native@0.73.4.patch" + "react-native@0.73.4": "patches/react-native@0.73.4.patch", + "@react-navigation/drawer@6.7.2": "patches/@react-navigation__drawer@6.7.2.patch" }, "allowNonAppliedPatches": true, "overrides": { diff --git a/packages/app/features/settings/ProfileScreen.tsx b/packages/app/features/settings/ProfileScreen.tsx index 3920ceb4fe..51af8fabc1 100644 --- a/packages/app/features/settings/ProfileScreen.tsx +++ b/packages/app/features/settings/ProfileScreen.tsx @@ -2,6 +2,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { useMutableRef } from '@tloncorp/shared'; import { NavBarView, ProfileScreenView, View } from '@tloncorp/ui'; import { useCallback, useEffect, useState } from 'react'; +import { Platform } from 'react-native'; import { useDMLureLink } from '../../hooks/useBranchLink'; import { useCurrentUserId } from '../../hooks/useCurrentUser'; @@ -99,7 +100,9 @@ function useHasHostedAuth() { setHasHostedAuth(true); } } - getHostingInfo(); + if (Platform.OS !== 'web') { + getHostingInfo(); + } }, []); return hasHostedAuth; diff --git a/packages/app/navigation/RootStack.tsx b/packages/app/navigation/RootStack.tsx index 4f02a1d84f..b65f1f327b 100644 --- a/packages/app/navigation/RootStack.tsx +++ b/packages/app/navigation/RootStack.tsx @@ -1,6 +1,6 @@ import { useFocusEffect } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import { useTheme } from '@tloncorp/ui'; +import { useTheme, useIsMobile } from '@tloncorp/ui'; import { Platform, StatusBar } from 'react-native'; import { ChannelMembersScreen } from '../features/channels/ChannelMembersScreen'; @@ -42,15 +42,17 @@ export function RootStack() { }); const theme = useTheme(); + const isMobile = useIsMobile(); return ( + {() => null} {/* top level tabs */} void; + onBack: () => void; +}; + +export const ChannelListDrawerContent = ( + props: ChannelListDrawerContentProps +) => { + const isFocused = useIsFocused(); + const [inviteSheetGroup, setInviteSheetGroup] = useState( + null + ); + + const { data: pins } = store.usePins({ + enabled: isFocused, + }); + + const pinnedItems = useMemo(() => { + return pins ?? []; + }, [pins]); + + const { group } = useGroupContext({ groupId: props.groupId, isFocused }); + + return ( + { + setInviteSheetGroup(group); + }} + {...useChatSettingsNavigation()} + > + + { + if (!open) { + setInviteSheetGroup(null); + } + }} + group={inviteSheetGroup ?? undefined} + onInviteComplete={() => setInviteSheetGroup(null)} + /> + + ); +}; diff --git a/packages/app/navigation/desktop/ChatListDrawerContent.tsx b/packages/app/navigation/desktop/ChatListDrawerContent.tsx new file mode 100644 index 0000000000..f2dfeb9961 --- /dev/null +++ b/packages/app/navigation/desktop/ChatListDrawerContent.tsx @@ -0,0 +1,236 @@ +import { DrawerContentComponentProps } from '@react-navigation/drawer'; +import { useIsFocused } from '@react-navigation/native'; +import * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import * as store from '@tloncorp/shared/store'; +import { + AddGroupSheet, + ChatList, + ChatOptionsProvider, + ChatOptionsSheet, + ChatOptionsSheetMethods, + GroupPreviewSheet, + InviteUsersSheet, + RequestsProvider, + ScreenHeader, + View, +} from '@tloncorp/ui'; +import { useCallback, useMemo, useRef, useState } from 'react'; + +import { useChatSettingsNavigation } from '../../hooks/useChatSettingsNavigation'; + +type DrawerContentProps = DrawerContentComponentProps & { + onPressItem: (item: db.Group | db.Channel) => void; + selectedGroup: db.Group | null; + setSelectedGroup: (group: db.Group | null) => void; +}; + +export const ChatListDrawerContent = (props: DrawerContentProps) => { + const { navigation, selectedGroup, setSelectedGroup } = props; + const isFocused = useIsFocused(); + const { data: pendingChats } = store.usePendingChats({ + enabled: isFocused, + }); + const { data: chats } = store.useCurrentChats({ + enabled: isFocused, + }); + + const resolvedChats = useMemo(() => { + return { + pinned: chats?.pinned ?? [], + unpinned: chats?.unpinned ?? [], + pendingChats: pendingChats ?? [], + }; + }, [chats, pendingChats]); + const [activeTab, setActiveTab] = useState<'all' | 'groups' | 'messages'>( + 'all' + ); + const [showSearchInput, setShowSearchInput] = useState(false); + const [longPressedChat, setLongPressedChat] = useState< + db.Channel | db.Group | null + >(null); + const chatOptionsSheetRef = useRef(null); + const [screenTitle, setScreenTitle] = useState('Home'); + const [addGroupOpen, setAddGroupOpen] = useState(false); + const [inviteSheetGroup, setInviteSheetGroup] = useState(); + const [searchQuery, setSearchQuery] = useState(''); + + const chatOptionsGroupId = useMemo(() => { + if (!longPressedChat) { + return; + } + return logic.isGroup(longPressedChat) + ? longPressedChat.id + : longPressedChat.group?.id; + }, [longPressedChat]); + + const chatOptionsChannelId = useMemo(() => { + if (!longPressedChat || logic.isGroup(longPressedChat)) { + return; + } + return longPressedChat.id; + }, [longPressedChat]); + + const onLongPressChat = useCallback((item: db.Channel | db.Group) => { + if (logic.isChannel(item) && !item.isDmInvite) { + setLongPressedChat(item); + if (item.pin?.type === 'channel' || !item.group) { + chatOptionsSheetRef.current?.open(item.id, item.type); + } else { + chatOptionsSheetRef.current?.open(item.group.id, 'group'); + } + } + }, []); + + const handleSearchInputToggled = useCallback(() => { + if (showSearchInput) { + setSearchQuery(''); + } + setShowSearchInput(!showSearchInput); + }, [showSearchInput]); + + const connStatus = store.useConnectionStatus(); + const notReadyMessage: string | null = useMemo(() => { + // if not fully connected yet, show status + if (connStatus !== 'Connected') { + return `${connStatus}...`; + } + + // if still loading the screen data, show loading + if (!chats || (!chats.unpinned.length && !chats.pinned.length)) { + return 'Loading...'; + } + + return null; + }, [connStatus, chats]); + + const { data: pins } = store.usePins({ + enabled: isFocused, + }); + const pinned = useMemo(() => pins ?? [], [pins]); + + const handleGroupPreviewSheetOpenChange = useCallback( + (open: boolean) => { + if (!open) { + setSelectedGroup(null); + } + }, + [setSelectedGroup] + ); + + const handleInviteSheetOpenChange = useCallback((open: boolean) => { + if (!open) { + setInviteSheetGroup(null); + } + }, []); + + const goToDm = useCallback( + async (userId: string) => { + const dmChannel = await store.upsertDmChannel({ + participants: [userId], + }); + setAddGroupOpen(false); + navigation.navigate('Channel', { channel: dmChannel }); + }, + [navigation, setAddGroupOpen] + ); + + const handleAddGroupOpenChange = useCallback((open: boolean) => { + if (!open) { + setAddGroupOpen(false); + } + }, []); + + const handleNavigateToFindGroups = useCallback(() => { + setAddGroupOpen(false); + navigation.navigate('FindGroups'); + }, [navigation]); + + const handleNavigateToCreateGroup = useCallback(() => { + setAddGroupOpen(false); + navigation.navigate('CreateGroup'); + }, [navigation]); + + const handleSectionChange = useCallback( + (title: string) => { + if (activeTab === 'all') { + setScreenTitle(title); + } + }, + [activeTab] + ); + + return ( + + { + setInviteSheetGroup(group); + }} + > + + + + setAddGroupOpen(true)} + /> + + } + /> + {chats && chats.unpinned.length ? ( + + ) : null} + + + + setInviteSheetGroup(null)} + group={inviteSheetGroup ?? undefined} + /> + + + + + ); +}; diff --git a/packages/app/navigation/desktop/HomeNavigator.tsx b/packages/app/navigation/desktop/HomeNavigator.tsx new file mode 100644 index 0000000000..d862052565 --- /dev/null +++ b/packages/app/navigation/desktop/HomeNavigator.tsx @@ -0,0 +1,80 @@ +import { + DrawerContentComponentProps, + createDrawerNavigator, +} from '@react-navigation/drawer'; +import { StackActions, useNavigation } from '@react-navigation/native'; +import type * as db from '@tloncorp/shared/db'; +import * as logic from '@tloncorp/shared/logic'; +import { useCallback, useState } from 'react'; + +import { RootStack } from '../RootStack'; +import { ChannelListDrawerContent } from './ChannelListDrawerContent'; +import { ChatListDrawerContent } from './ChatListDrawerContent'; + +const HomeDrawer = createDrawerNavigator(); + +export const HomeNavigator = () => { + const [selectedGroup, setSelectedGroup] = useState(null); + const [navGroupId, setNavGroupId] = useState(null); + const navigation = useNavigation(); + + const handleChatItemPress = useCallback( + (item: db.Group | db.Channel) => { + if (logic.isGroup(item)) { + // this is only used for handling group invite previews + setSelectedGroup(item); + } else if ( + item.group && + item.groupId && + // Should navigate to channel if it's pinned as a channel + (!item.pin || item.pin.type === 'group') + ) { + setNavGroupId(item.groupId); + } else { + navigation.dispatch( + StackActions.replace('Channel', { + channel: item, + selectedPostId: item.firstUnreadPostId, + }) + ); + } + }, + [navigation] + ); + + const DrawerContent = useCallback( + (props: DrawerContentComponentProps) => { + if (navGroupId) { + return ( + setNavGroupId(null)} + /> + ); + } + return ( + + ); + }, + [navGroupId, handleChatItemPress, selectedGroup] + ); + + return ( + + + + ); +}; diff --git a/packages/app/navigation/desktop/TopLevelDrawer.tsx b/packages/app/navigation/desktop/TopLevelDrawer.tsx new file mode 100644 index 0000000000..2aef7727ba --- /dev/null +++ b/packages/app/navigation/desktop/TopLevelDrawer.tsx @@ -0,0 +1,73 @@ +import { + DrawerContentComponentProps, + createDrawerNavigator, +} from '@react-navigation/drawer'; +import * as store from '@tloncorp/shared/store'; +import { AvatarNavIcon, NavIcon, YStack } from '@tloncorp/ui'; + +import ProfileScreen from '../../features/settings/ProfileScreen'; +import { ActivityScreen } from '../../features/top/ActivityScreen'; +import { useCurrentUserId } from '../../hooks/useCurrentUser'; +import { DrawerParamList } from '../types'; +import { HomeNavigator } from './HomeNavigator'; + +const Drawer = createDrawerNavigator(); + +const DrawerContent = (props: DrawerContentComponentProps) => { + const userId = useCurrentUserId(); + const haveUnreadUnseenActivity = store.useHaveUnreadUnseenActivity(); + const isRouteActive = (routeName: string) => { + return ( + props.state.index === + props.state.routes.findIndex((r) => r.name === routeName) + ); + }; + + return ( + + 0} + // intentionally leave undotted for now + hasUnreads={false} + onPress={() => props.navigation.navigate('Home')} + /> + props.navigation.navigate('Activity')} + /> + props.navigation.navigate('Profile')} + /> + + ); +}; + +export const TopLevelDrawer = () => { + return ( + { + return ; + }} + initialRouteName="Home" + screenOptions={{ + drawerType: 'permanent', + headerShown: false, + drawerStyle: { + width: 48, + }, + }} + > + + + + + ); +}; diff --git a/packages/app/navigation/types.ts b/packages/app/navigation/types.ts index 86a4e1ef7a..c79f47223c 100644 --- a/packages/app/navigation/types.ts +++ b/packages/app/navigation/types.ts @@ -18,7 +18,17 @@ export type WebViewStackParamList = { ExternalWebView: ExternalWebViewScreenParams; }; +export type DrawerParamList = { + Home: undefined; + Activity: undefined; + Profile: undefined; + Channel: { + channel: db.Channel; + }; +}; + export type RootStackParamList = { + Empty: undefined; ChatList: { previewGroup: db.Group } | undefined; Activity: undefined; Profile: undefined; diff --git a/packages/ui/src/components/Channel/ChannelHeader.tsx b/packages/ui/src/components/Channel/ChannelHeader.tsx index fb326952f0..57c1ae4c3f 100644 --- a/packages/ui/src/components/Channel/ChannelHeader.tsx +++ b/packages/ui/src/components/Channel/ChannelHeader.tsx @@ -8,6 +8,7 @@ import { useState, } from 'react'; +import useIsMobile from '../../hooks/useIsMobile'; import { ChatOptionsSheet, ChatOptionsSheetMethods } from '../ChatOptionsSheet'; import { ScreenHeader } from '../ScreenHeader'; import { BaubleHeader } from './BaubleHeader'; @@ -100,6 +101,7 @@ export function ChannelHeader({ }, [channel.id, channel.type]); const contextItems = useContext(ChannelHeaderItemsContext)?.items ?? []; + const isMobile = useIsMobile(); if (mode === 'next') { return ; @@ -124,7 +126,9 @@ export function ChannelHeader({ titleWidth={titleWidth()} showSessionStatus isLoading={showSpinner} - leftControls={} + leftControls={ + isMobile ? : undefined + } rightControls={ <> {showSearchButton && ( diff --git a/packages/ui/src/components/ChatList.tsx b/packages/ui/src/components/ChatList.tsx index 893152b235..555c717d50 100644 --- a/packages/ui/src/components/ChatList.tsx +++ b/packages/ui/src/components/ChatList.tsx @@ -307,7 +307,7 @@ function useFilteredChats({ ); return useMemo(() => { - const isSearching = searchQuery.trim() !== ''; + const isSearching = searchQuery && searchQuery.trim() !== ''; if (!isSearching) { const pinnedSection = { title: 'Pinned', @@ -362,6 +362,9 @@ function useChatSearch({ const performSearch = useCallback( (query: string) => { + // necessary for web, otherwise fuse.search will throw + // an error + if (!query) return []; return fuse.search(query).map((result) => result.item); }, [fuse] diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index 819e13c604..1a3b5182e4 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -4,6 +4,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ScrollView, View, YStack } from 'tamagui'; import { useCurrentUserId } from '../contexts'; +import useIsMobile from '../hooks/useIsMobile'; import { useIsAdmin } from '../utils/channelUtils'; import ChannelNavSections from './ChannelNavSections'; import { ChatOptionsSheet, ChatOptionsSheetMethods } from './ChatOptionsSheet'; @@ -65,6 +66,8 @@ export function GroupChannelsScreenView({ } }, [isGroupAdmin]); + const isMobile = useIsMobile(); + return ( ) : ( diff --git a/packages/ui/src/components/NavBarView.tsx b/packages/ui/src/components/NavBarView.tsx index d07ba83733..f53a88b733 100644 --- a/packages/ui/src/components/NavBarView.tsx +++ b/packages/ui/src/components/NavBarView.tsx @@ -1,5 +1,6 @@ import * as store from '@tloncorp/shared/store'; +import useIsMobile from '../hooks/useIsMobile'; import { AvatarNavIcon, NavBar, NavIcon } from './NavBar'; export const NavBarView = ({ @@ -19,6 +20,11 @@ export const NavBarView = ({ return currentRoute === routeName; }; const haveUnreadUnseenActivity = store.useHaveUnreadUnseenActivity(); + const isMobile = useIsMobile(); + + if (!isMobile) { + return null; + } return ( diff --git a/packages/ui/src/hooks/useIsMobile.ts b/packages/ui/src/hooks/useIsMobile.ts new file mode 100644 index 0000000000..bfc1414e7f --- /dev/null +++ b/packages/ui/src/hooks/useIsMobile.ts @@ -0,0 +1,6 @@ +import { useWindowDimensions } from 'tamagui' + +export default function useIsMobile() { + const { width } = useWindowDimensions(); + return width < 768; +} diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index 646066520e..de520f2e45 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -81,6 +81,7 @@ export * from './tamagui.config'; export * from './types'; export * from './utils'; export * as TlonText from './components/TextV2'; +export { default as useIsMobile } from './hooks/useIsMobile'; export { Circle, diff --git a/patches/@react-navigation__drawer@6.7.2.patch b/patches/@react-navigation__drawer@6.7.2.patch new file mode 100644 index 0000000000..380eef58b6 --- /dev/null +++ b/patches/@react-navigation__drawer@6.7.2.patch @@ -0,0 +1,441 @@ +diff --git a/lib/module/views/modern/Drawer.js b/lib/module/views/modern/Drawer.js +index 3aa1baa2efd65bab22da56416c90e3a294dab266..08fe2866924f233fa4bd349258a4b35ff51c7fc7 100644 +--- a/lib/module/views/modern/Drawer.js ++++ b/lib/module/views/modern/Drawer.js +@@ -1,7 +1,38 @@ +-function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } ++function _extends() { ++ _extends = Object.assign ++ ? Object.assign.bind() ++ : function (target) { ++ for (var i = 1; i < arguments.length; i++) { ++ var source = arguments[i]; ++ for (var key in source) { ++ if (Object.prototype.hasOwnProperty.call(source, key)) { ++ target[key] = source[key]; ++ } ++ } ++ } ++ return target; ++ }; ++ return _extends.apply(this, arguments); ++} + import * as React from 'react'; +-import { I18nManager, InteractionManager, Keyboard, Platform, StatusBar, StyleSheet, View } from 'react-native'; +-import Animated, { interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useDerivedValue, useSharedValue, withSpring } from 'react-native-reanimated'; ++import { ++ I18nManager, ++ InteractionManager, ++ Keyboard, ++ Platform, ++ StatusBar, ++ StyleSheet, ++ View ++} from 'react-native'; ++import Animated, { ++ interpolate, ++ runOnJS, ++ useAnimatedGestureHandler, ++ useAnimatedStyle, ++ useDerivedValue, ++ useSharedValue, ++ withSpring ++} from 'react-native-reanimated'; + import DrawerProgressContext from '../../utils/DrawerProgressContext'; + import { GestureState, PanGestureHandler } from '../GestureHandler'; + import Overlay from './Overlay'; +@@ -35,9 +66,8 @@ export default function Drawer(_ref) { + overlayAccessibilityLabel + } = _ref; + const getDrawerWidth = () => { +- const { +- width = DEFAULT_DRAWER_WIDTH +- } = StyleSheet.flatten(drawerStyle) || {}; ++ const { width = DEFAULT_DRAWER_WIDTH } = ++ StyleSheet.flatten(drawerStyle) || {}; + if (typeof width === 'string' && width.endsWith('%')) { + // Try to calculate width if a percentage is given + const percentage = Number(width.replace(/%$/, '')); +@@ -50,19 +80,25 @@ export default function Drawer(_ref) { + const drawerWidth = getDrawerWidth(); + const isOpen = drawerType === 'permanent' ? true : open; + const isRight = drawerPosition === 'right'; +- const getDrawerTranslationX = React.useCallback(open => { +- 'worklet'; ++ const getDrawerTranslationX = React.useCallback( ++ open => { ++ 'worklet'; + +- if (drawerPosition === 'left') { +- return open ? 0 : -drawerWidth; +- } +- return open ? 0 : drawerWidth; +- }, [drawerPosition, drawerWidth]); +- const hideStatusBar = React.useCallback(hide => { +- if (hideStatusBarOnOpen) { +- StatusBar.setHidden(hide, statusBarAnimation); +- } +- }, [hideStatusBarOnOpen, statusBarAnimation]); ++ if (drawerPosition === 'left') { ++ return open ? 0 : -drawerWidth; ++ } ++ return open ? 0 : drawerWidth; ++ }, ++ [drawerPosition, drawerWidth] ++ ); ++ const hideStatusBar = React.useCallback( ++ hide => { ++ if (hideStatusBarOnOpen) { ++ StatusBar.setHidden(hide, statusBarAnimation); ++ } ++ }, ++ [hideStatusBarOnOpen, statusBarAnimation] ++ ); + React.useEffect(() => { + hideStatusBar(isOpen); + return () => hideStatusBar(false); +@@ -93,55 +129,59 @@ export default function Drawer(_ref) { + + // FIXME: Currently hitSlop is broken when on Android when drawer is on right + // https://github.com/software-mansion/react-native-gesture-handler/issues/569 +- const hitSlop = isRight ? +- // Extend hitSlop to the side of the screen when drawer is closed +- // This lets the user drag the drawer from the side of the screen +- { +- right: 0, +- width: isOpen ? undefined : swipeEdgeWidth +- } : { +- left: 0, +- width: isOpen ? undefined : swipeEdgeWidth +- }; ++ const hitSlop = isRight ++ ? // Extend hitSlop to the side of the screen when drawer is closed ++ // This lets the user drag the drawer from the side of the screen ++ { ++ right: 0, ++ width: isOpen ? undefined : swipeEdgeWidth ++ } ++ : { ++ left: 0, ++ width: isOpen ? undefined : swipeEdgeWidth ++ }; + const touchStartX = useSharedValue(0); + const touchX = useSharedValue(0); + const translationX = useSharedValue(getDrawerTranslationX(open)); + const gestureState = useSharedValue(GestureState.UNDETERMINED); +- const toggleDrawer = React.useCallback(_ref2 => { +- 'worklet'; ++ const toggleDrawer = React.useCallback( ++ _ref2 => { ++ 'worklet'; + +- let { +- open, +- isUserInitiated, +- velocity +- } = _ref2; +- const translateX = getDrawerTranslationX(open); +- touchStartX.value = 0; +- touchX.value = 0; +- translationX.value = withSpring(translateX, { +- velocity, +- stiffness: 1000, +- damping: 500, +- mass: 3, +- overshootClamping: true, +- restDisplacementThreshold: 0.01, +- restSpeedThreshold: 0.01, +- // @ts-expect-error: This is available in newer reanimated versions +- reduceMotion: 'never' +- }); +- if (!isUserInitiated) { +- return; +- } +- if (open) { +- runOnJS(onOpen)(); +- } else { +- runOnJS(onClose)(); +- } +- }, [getDrawerTranslationX, onClose, onOpen, touchStartX, touchX, translationX]); +- React.useEffect(() => toggleDrawer({ +- open, +- isUserInitiated: false +- }), [open, toggleDrawer]); ++ let { open, isUserInitiated, velocity } = _ref2; ++ const translateX = getDrawerTranslationX(open); ++ touchStartX.value = 0; ++ touchX.value = 0; ++ translationX.value = withSpring(translateX, { ++ velocity, ++ stiffness: 1000, ++ damping: 500, ++ mass: 3, ++ overshootClamping: true, ++ restDisplacementThreshold: 0.01, ++ restSpeedThreshold: 0.01, ++ // @ts-expect-error: This is available in newer reanimated versions ++ reduceMotion: 'never' ++ }); ++ if (!isUserInitiated) { ++ return; ++ } ++ if (open) { ++ runOnJS(onOpen)(); ++ } else { ++ runOnJS(onClose)(); ++ } ++ }, ++ [getDrawerTranslationX, onClose, onOpen, touchStartX, touchX, translationX] ++ ); ++ React.useEffect( ++ () => ++ toggleDrawer({ ++ open, ++ isUserInitiated: false ++ }), ++ [open, toggleDrawer] ++ ); + const onGestureEvent = useAnimatedGestureHandler({ + onStart: (event, ctx) => { + ctx.hasCalledOnStart = false; +@@ -164,11 +204,16 @@ export default function Drawer(_ref) { + }, + onEnd: event => { + gestureState.value = event.state; +- const nextOpen = Math.abs(event.translationX) > SWIPE_DISTANCE_MINIMUM && Math.abs(event.translationX) > swipeVelocityThreshold || Math.abs(event.translationX) > swipeDistanceThreshold ? drawerPosition === 'left' ? +- // If swiped to right, open the drawer, otherwise close it +- (event.velocityX === 0 ? event.translationX : event.velocityX) > 0 : +- // If swiped to left, open the drawer, otherwise close it +- (event.velocityX === 0 ? event.translationX : event.velocityX) < 0 : open; ++ const nextOpen = ++ (Math.abs(event.translationX) > SWIPE_DISTANCE_MINIMUM && ++ Math.abs(event.translationX) > swipeVelocityThreshold) || ++ Math.abs(event.translationX) > swipeDistanceThreshold ++ ? drawerPosition === 'left' ++ ? // If swiped to right, open the drawer, otherwise close it ++ (event.velocityX === 0 ? event.translationX : event.velocityX) > 0 ++ : // If swiped to left, open the drawer, otherwise close it ++ (event.velocityX === 0 ? event.translationX : event.velocityX) < 0 ++ : open; + toggleDrawer({ + open: nextOpen, + isUserInitiated: true, +@@ -205,72 +250,159 @@ export default function Drawer(_ref) { + // drawer be pulled back as soon as you start the pan. + // + // This is used only when drawerType is "front" +- const touchDistance = drawerType === 'front' && gestureState.value === GestureState.ACTIVE ? minmax(drawerPosition === 'left' ? touchStartX.value - drawerWidth : dimensions.width - drawerWidth - touchStartX.value, 0, dimensions.width) : 0; +- const translateX = drawerPosition === 'left' ? minmax(translationX.value + touchDistance, -drawerWidth, 0) : minmax(translationX.value - touchDistance, 0, drawerWidth); ++ const touchDistance = ++ drawerType === 'front' && gestureState.value === GestureState.ACTIVE ++ ? minmax( ++ drawerPosition === 'left' ++ ? touchStartX.value - drawerWidth ++ : dimensions.width - drawerWidth - touchStartX.value, ++ 0, ++ dimensions.width ++ ) ++ : 0; ++ const translateX = ++ drawerPosition === 'left' ++ ? minmax(translationX.value + touchDistance, -drawerWidth, 0) ++ : minmax(translationX.value - touchDistance, 0, drawerWidth); + return translateX; + }); + const isRTL = I18nManager.getConstants().isRTL; + const drawerAnimatedStyle = useAnimatedStyle(() => { + const distanceFromEdge = dimensions.width - drawerWidth; + return { +- transform: drawerType === 'permanent' ? +- // Reanimated needs the property to be present, but it results in Browser bug +- // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 +- [] : [{ +- translateX: +- // The drawer stays in place when `drawerType` is `back` +- (drawerType === 'back' ? 0 : translateX.value) + (drawerPosition === 'left' ? isRTL ? -distanceFromEdge : 0 : isRTL ? 0 : distanceFromEdge) +- }] ++ transform: ++ drawerType === 'permanent' ++ ? // Reanimated needs the property to be present, but it results in Browser bug ++ // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 ++ [] ++ : [ ++ { ++ translateX: ++ // The drawer stays in place when `drawerType` is `back` ++ (drawerType === 'back' ? 0 : translateX.value) + ++ (drawerPosition === 'left' ++ ? isRTL ++ ? -distanceFromEdge ++ : 0 ++ : isRTL ++ ? 0 ++ : distanceFromEdge) ++ } ++ ] + }; +- }); ++ }, [ ++ dimensions.width, ++ drawerPosition, ++ drawerType, ++ drawerWidth, ++ isRTL, ++ translateX ++ ]); + const contentAnimatedStyle = useAnimatedStyle(() => { + return { +- transform: drawerType === 'permanent' ? +- // Reanimated needs the property to be present, but it results in Browser bug +- // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 +- [] : [{ +- translateX: +- // The screen content stays in place when `drawerType` is `front` +- drawerType === 'front' ? 0 : translateX.value + drawerWidth * (drawerPosition === 'left' ? 1 : -1) +- }] ++ transform: ++ drawerType === 'permanent' ++ ? // Reanimated needs the property to be present, but it results in Browser bug ++ // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 ++ [] ++ : [ ++ { ++ translateX: ++ // The screen content stays in place when `drawerType` is `front` ++ drawerType === 'front' ++ ? 0 ++ : translateX.value + ++ drawerWidth * (drawerPosition === 'left' ? 1 : -1) ++ } ++ ] + }; +- }); ++ }, [drawerPosition, drawerType, drawerWidth, translateX]); + const progress = useDerivedValue(() => { +- return drawerType === 'permanent' ? 1 : interpolate(translateX.value, [getDrawerTranslationX(false), getDrawerTranslationX(true)], [0, 1]); ++ return drawerType === 'permanent' ++ ? 1 ++ : interpolate( ++ translateX.value, ++ [getDrawerTranslationX(false), getDrawerTranslationX(true)], ++ [0, 1] ++ ); + }); +- return /*#__PURE__*/React.createElement(DrawerProgressContext.Provider, { +- value: progress +- }, /*#__PURE__*/React.createElement(PanGestureHandler, _extends({ +- activeOffsetX: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], +- failOffsetY: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], +- hitSlop: hitSlop, +- enabled: drawerType !== 'permanent' && swipeEnabled, +- onGestureEvent: onGestureEvent +- }, gestureHandlerProps), /*#__PURE__*/React.createElement(Animated.View, { +- style: [styles.main, { +- flexDirection: drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row' +- }] +- }, /*#__PURE__*/React.createElement(Animated.View, { +- style: [styles.content, contentAnimatedStyle] +- }, /*#__PURE__*/React.createElement(View, { +- accessibilityElementsHidden: isOpen && drawerType !== 'permanent', +- importantForAccessibility: isOpen && drawerType !== 'permanent' ? 'no-hide-descendants' : 'auto', +- style: styles.content +- }, renderSceneContent()), drawerType !== 'permanent' ? /*#__PURE__*/React.createElement(Overlay, { +- progress: progress, +- onPress: () => toggleDrawer({ +- open: false, +- isUserInitiated: true +- }), +- style: overlayStyle, +- accessibilityLabel: overlayAccessibilityLabel +- }) : null), /*#__PURE__*/React.createElement(Animated.View, { +- removeClippedSubviews: Platform.OS !== 'ios', +- style: [styles.container, { +- position: drawerType === 'permanent' ? 'relative' : 'absolute', +- zIndex: drawerType === 'back' ? -1 : 0 +- }, drawerAnimatedStyle, drawerStyle] +- }, renderDrawerContent())))); ++ return /*#__PURE__*/ React.createElement( ++ DrawerProgressContext.Provider, ++ { ++ value: progress ++ }, ++ /*#__PURE__*/ React.createElement( ++ PanGestureHandler, ++ _extends( ++ { ++ activeOffsetX: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], ++ failOffsetY: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], ++ hitSlop: hitSlop, ++ enabled: drawerType !== 'permanent' && swipeEnabled, ++ onGestureEvent: onGestureEvent ++ }, ++ gestureHandlerProps ++ ), ++ /*#__PURE__*/ React.createElement( ++ Animated.View, ++ { ++ style: [ ++ styles.main, ++ { ++ flexDirection: ++ drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row' ++ } ++ ] ++ }, ++ /*#__PURE__*/ React.createElement( ++ Animated.View, ++ { ++ style: [styles.content, contentAnimatedStyle] ++ }, ++ /*#__PURE__*/ React.createElement( ++ View, ++ { ++ accessibilityElementsHidden: isOpen && drawerType !== 'permanent', ++ importantForAccessibility: ++ isOpen && drawerType !== 'permanent' ++ ? 'no-hide-descendants' ++ : 'auto', ++ style: styles.content ++ }, ++ renderSceneContent() ++ ), ++ drawerType !== 'permanent' ++ ? /*#__PURE__*/ React.createElement(Overlay, { ++ progress: progress, ++ onPress: () => ++ toggleDrawer({ ++ open: false, ++ isUserInitiated: true ++ }), ++ style: overlayStyle, ++ accessibilityLabel: overlayAccessibilityLabel ++ }) ++ : null ++ ), ++ /*#__PURE__*/ React.createElement( ++ Animated.View, ++ { ++ removeClippedSubviews: Platform.OS !== 'ios', ++ style: [ ++ styles.container, ++ { ++ position: drawerType === 'permanent' ? 'relative' : 'absolute', ++ zIndex: drawerType === 'back' ? -1 : 0 ++ }, ++ drawerAnimatedStyle, ++ drawerStyle ++ ] ++ }, ++ renderDrawerContent() ++ ) ++ ) ++ ) ++ ); + } + const styles = StyleSheet.create({ + container: { +@@ -295,3 +427,4 @@ const styles = StyleSheet.create({ + } + }); + //# sourceMappingURL=Drawer.js.map ++ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3ff2ab854..e88e64bede 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,9 @@ patchedDependencies: '@likashefqet/react-native-image-zoom@3.0.0': hash: zkdmh374s554i7qlaqtqn2nhfm path: patches/@likashefqet__react-native-image-zoom@3.0.0.patch + '@react-navigation/drawer@6.7.2': + hash: xry4exjnht3vohn7iwtifercxi + path: patches/@react-navigation__drawer@6.7.2.patch '@tiptap/react@2.0.3': hash: tt2duu22fpwhmhaws3iaoig4mu path: patches/@tiptap__react@2.0.3.patch @@ -144,6 +147,9 @@ importers: '@react-navigation/bottom-tabs': specifier: ^6.5.12 version: 6.5.12(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/drawer': + specifier: ^6.7.2 + version: 6.7.2(patch_hash=xry4exjnht3vohn7iwtifercxi)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': specifier: ^6.1.7 version: 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -1019,6 +1025,9 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.0.0 version: 1.0.0(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@react-navigation/drawer': + specifier: ^6.7.2 + version: 6.7.2(patch_hash=xry4exjnht3vohn7iwtifercxi)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': specifier: ^6.1.7 version: 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -4975,6 +4984,17 @@ packages: peerDependencies: react: '*' + '@react-navigation/drawer@6.7.2': + resolution: {integrity: sha512-o4g2zgTZa2+oLd+8V33etrSM38KIqu8S/zCBTsdsHUoQyVE7JNRiv3Qgq/jMvEb8PZCqWmm7jHItcgzrBuwyOQ==} + peerDependencies: + '@react-navigation/native': ^6.0.0 + react: '*' + react-native: '*' + react-native-gesture-handler: '>= 1.0.0' + react-native-reanimated: '>= 1.0.0' + react-native-safe-area-context: '>= 3.0.0' + react-native-screens: '>= 3.0.0' + '@react-navigation/elements@1.3.22': resolution: {integrity: sha512-HYKucs0TwQT8zMvgoZbJsY/3sZfzeP8Dk9IDv4agst3zlA7ReTx4+SROCG6VGC7JKqBCyQykHIwkSwxhapoc+Q==} peerDependencies: @@ -4983,6 +5003,14 @@ packages: react-native: '*' react-native-safe-area-context: '>= 3.0.0' + '@react-navigation/elements@1.3.31': + resolution: {integrity: sha512-bUzP4Awlljx5RKEExw8WYtif8EuQni2glDaieYROKTnaxsu9kEIA515sXQgUDZU4Ob12VoL7+z70uO3qrlfXcQ==} + peerDependencies: + '@react-navigation/native': ^6.0.0 + react: '*' + react-native: '*' + react-native-safe-area-context: '>= 3.0.0' + '@react-navigation/native-stack@6.9.18': resolution: {integrity: sha512-PSe0qjROy8zD78ehW048NSuzWRktioSCJmB8LzWSR65ndgVaC2rO+xvgyjhHjqm01YdyVM1XTct2EorSjDV2Ow==} peerDependencies: @@ -18738,6 +18766,19 @@ snapshots: react: 18.2.0 stacktrace-parser: 0.1.10 + ? '@react-navigation/drawer@6.7.2(patch_hash=xry4exjnht3vohn7iwtifercxi)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)' + : dependencies: + '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + color: 4.2.3 + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) + react-native-gesture-handler: 2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-reanimated: 3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-safe-area-context: 4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-screens: 3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + warn-once: 0.1.1 + '@react-navigation/elements@1.3.22(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -18745,6 +18786,13 @@ snapshots: react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) react-native-safe-area-context: 4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/elements@1.3.31(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react: 18.2.0 + react-native: 0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0) + react-native-safe-area-context: 4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native-stack@6.9.18(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@react-navigation/elements': 1.3.22(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) From 3efab4bd309d84219ed063e34b98a188a1611537 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 29 Oct 2024 10:40:19 -0500 Subject: [PATCH 232/259] filter pending group invites out of chat list on messages tab --- packages/ui/src/components/ChatList.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/ChatList.tsx b/packages/ui/src/components/ChatList.tsx index 555c717d50..c582dac810 100644 --- a/packages/ui/src/components/ChatList.tsx +++ b/packages/ui/src/components/ChatList.tsx @@ -315,7 +315,10 @@ function useFilteredChats({ }; const allSection = { title: 'All', - data: [...pending, ...filterChats(unpinned, activeTab)], + data: [ + ...filterPendingChats(pending, activeTab), + ...filterChats(unpinned, activeTab), + ], }; return pinnedSection.data.length ? [pinnedSection, allSection] @@ -331,6 +334,14 @@ function useFilteredChats({ }, [activeTab, pending, searchQuery, searchResults, unpinned, pinned]); } +function filterPendingChats(pending: Chat[], activeTab: TabName) { + if (activeTab === 'all') return pending; + return pending.filter((chat) => { + const isGroupChannel = logic.isGroup(chat); + return activeTab === 'groups' ? isGroupChannel : !isGroupChannel; + }); +} + function filterChats(chats: Chat[], activeTab: TabName) { if (activeTab === 'all') return chats; return chats.filter((chat) => { From 29206e9c9adb7911e1e006d6e34d6f9641b8786a Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Oct 2024 15:52:01 +0000 Subject: [PATCH 233/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 840388d1ea..f310dadacb 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v6.6c036.lj7nu.frsbt.vr9ic.a7qhe.glob' 0v6.6c036.lj7nu.frsbt.vr9ic.a7qhe] + glob-http+['https://bootstrap.urbit.org/glob-0v1.n7qcb.nki5c.smn6g.v1gdn.2tp19.glob' 0v1.n7qcb.nki5c.smn6g.v1gdn.2tp19] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From 4ddbf656c17cec62b1146cf936bb0c37490bfea5 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 29 Oct 2024 13:06:39 -0500 Subject: [PATCH 234/259] Fix height/padding issues with BareChatInput on web, add new eslint rule to prevent use of getToken since it could break things when we're expecting to manipulate raw values --- .eslintrc.cjs | 8 ++++ .../ui/src/components/BareChatInput/index.tsx | 45 ++++++++++++++++--- .../ui/src/components/BigInput.native.tsx | 6 +-- packages/ui/src/components/BigInput.tsx | 6 +-- .../components/MessageInput/index.native.tsx | 6 +-- packages/ui/src/components/NavBar/NavBar.tsx | 4 +- 6 files changed, 59 insertions(+), 16 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ceca6aa7ba..3a7743f3f2 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -39,5 +39,13 @@ module.exports = { additionalHooks: '(useAnimatedStyle|useDerivedValue|useAnimatedProps)', }, ], + 'no-restricted-syntax': [ + 'error', + { + selector: 'CallExpression[callee.name="getToken"]', + message: + 'Please use getTokenValue() instead of getToken() to ensure web compatibility. See: https://tamagui.dev/docs/core/exports#gettokenvalue', + }, + ], }, }; diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 11ea982226..d53dd32f78 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -24,11 +24,12 @@ import { View, YStack, getFontSize, - getToken, getVariableValue, useTheme, useWindowDimensions, } from 'tamagui'; +import { getTokenValue } from 'tamagui'; +import { isWeb } from 'tamagui'; import { Attachment, @@ -86,6 +87,7 @@ export default function BareChatInput({ waitForAttachmentUploads, } = useAttachmentContext(); const [text, setText] = useState(''); + const [inputHeight, setInputHeight] = useState(initialHeight); const [isSending, setIsSending] = useState(false); const [sendError, setSendError] = useState(false); const [hasSetInitialContent, setHasSetInitialContent] = useState(false); @@ -489,6 +491,32 @@ export default function BareChatInput({ const paddingTopAdjustment = Platform.OS === 'ios' ? 2 : 4; const mentionLineHeightAdjustment = Platform.OS === 'ios' ? 1.3 : 1.5; + const theme = useTheme(); + // placeholderTextColor is not supported on native, just web + // https://necolas.github.io/react-native-web/docs/text-input/ + const placeholderTextColor = isWeb + ? { + placeholderTextColor: getVariableValue(theme.secondaryText), + } + : {}; + + const adjustTextInputSize = (e: any) => { + if (!isWeb) { + return; + } + // we need to manipulate the element directly in order to adjust the height + // back down as the content shrinks, apparently + // https://github.com/necolas/react-native-web/issues/795 + // + const el = e?.target; + if (el && 'style' in el && 'height' in el.style) { + el.style.height = 0; + const newHeight = el.offsetHeight - el.clientHeight + el.scrollHeight; + el.style.height = `${newHeight}px`; + setInputHeight(newHeight); + } + }; + return ( diff --git a/packages/ui/src/components/BigInput.native.tsx b/packages/ui/src/components/BigInput.native.tsx index 86f3f4aa6e..f85ded1496 100644 --- a/packages/ui/src/components/BigInput.native.tsx +++ b/packages/ui/src/components/BigInput.native.tsx @@ -4,7 +4,7 @@ import { Dimensions, KeyboardAvoidingView, Platform } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; // TODO: replace input with our own input component -import { Input, View, YStack, getToken } from 'tamagui'; +import { Input, View, YStack, getTokenValue } from 'tamagui'; import { ImageAttachment, useAttachmentContext } from '../contexts/attachment'; import AttachmentSheet from './AttachmentSheet'; @@ -40,8 +40,8 @@ export function BigInput({ }>(null); const { top } = useSafeAreaInsets(); const { width } = Dimensions.get('screen'); - const titleInputHeight = getToken('$4xl', 'size'); - const imageButtonHeight = getToken('$4xl', 'size'); + const titleInputHeight = getTokenValue('$4xl', 'size'); + const imageButtonHeight = getTokenValue('$4xl', 'size'); const keyboardVerticalOffset = Platform.OS === 'ios' ? top + titleInputHeight : top; diff --git a/packages/ui/src/components/BigInput.tsx b/packages/ui/src/components/BigInput.tsx index 4d89360235..3a3b58a498 100644 --- a/packages/ui/src/components/BigInput.tsx +++ b/packages/ui/src/components/BigInput.tsx @@ -5,7 +5,7 @@ import { Dimensions, KeyboardAvoidingView, Platform } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; // TODO: replace input with our own input component -import { Input, ScrollView, View, YStack, getToken } from 'tamagui'; +import { Input, ScrollView, View, YStack, getTokenValue } from 'tamagui'; import { ImageAttachment, useAttachmentContext } from '../contexts/attachment'; import AttachmentSheet from './AttachmentSheet'; @@ -43,8 +43,8 @@ export function BigInput({ // }>(null); const { top } = useSafeAreaInsets(); const { width } = Dimensions.get('screen'); - const titleInputHeight = getToken('$4xl', 'size'); - const imageButtonHeight = getToken('$4xl', 'size'); + const titleInputHeight = getTokenValue('$4xl', 'size'); + const imageButtonHeight = getTokenValue('$4xl', 'size'); const keyboardVerticalOffset = Platform.OS === 'ios' ? top + titleInputHeight : top; diff --git a/packages/ui/src/components/MessageInput/index.native.tsx b/packages/ui/src/components/MessageInput/index.native.tsx index 385d984541..3c62759e49 100644 --- a/packages/ui/src/components/MessageInput/index.native.tsx +++ b/packages/ui/src/components/MessageInput/index.native.tsx @@ -49,7 +49,7 @@ import { import { Keyboard } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import type { WebViewMessageEvent } from 'react-native-webview'; -import { YStack, getToken, useWindowDimensions } from 'tamagui'; +import { YStack, getTokenValue, useWindowDimensions } from 'tamagui'; import { XStack } from 'tamagui'; import { useBranchDomain, useBranchKey } from '../../contexts'; @@ -156,7 +156,7 @@ export const MessageInput = forwardRef( const { height } = useWindowDimensions(); const headerHeight = 48; const titleInputHeight = 48; - const inputBasePadding = getToken('$s', 'space'); + const inputBasePadding = getTokenValue('$s', 'space'); const imageInputButtonHeight = 50; const maxInputHeightBasic = useMemo( () => height - headerHeight - bottom - top, @@ -961,7 +961,7 @@ export const MessageInput = forwardRef( Date: Tue, 29 Oct 2024 13:11:56 -0500 Subject: [PATCH 235/259] Cleaner drawer patch --- patches/@react-navigation__drawer@6.7.2.patch | 439 +----------------- pnpm-lock.yaml | 8 +- 2 files changed, 14 insertions(+), 433 deletions(-) diff --git a/patches/@react-navigation__drawer@6.7.2.patch b/patches/@react-navigation__drawer@6.7.2.patch index 380eef58b6..ab28152f8c 100644 --- a/patches/@react-navigation__drawer@6.7.2.patch +++ b/patches/@react-navigation__drawer@6.7.2.patch @@ -1,441 +1,22 @@ diff --git a/lib/module/views/modern/Drawer.js b/lib/module/views/modern/Drawer.js -index 3aa1baa2efd65bab22da56416c90e3a294dab266..08fe2866924f233fa4bd349258a4b35ff51c7fc7 100644 +index 3aa1baa2efd65bab22da56416c90e3a294dab266..8737778293408588026d6efab2c9070ed1def4f4 100644 --- a/lib/module/views/modern/Drawer.js +++ b/lib/module/views/modern/Drawer.js -@@ -1,7 +1,38 @@ --function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } -+function _extends() { -+ _extends = Object.assign -+ ? Object.assign.bind() -+ : function (target) { -+ for (var i = 1; i < arguments.length; i++) { -+ var source = arguments[i]; -+ for (var key in source) { -+ if (Object.prototype.hasOwnProperty.call(source, key)) { -+ target[key] = source[key]; -+ } -+ } -+ } -+ return target; -+ }; -+ return _extends.apply(this, arguments); -+} - import * as React from 'react'; --import { I18nManager, InteractionManager, Keyboard, Platform, StatusBar, StyleSheet, View } from 'react-native'; --import Animated, { interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useDerivedValue, useSharedValue, withSpring } from 'react-native-reanimated'; -+import { -+ I18nManager, -+ InteractionManager, -+ Keyboard, -+ Platform, -+ StatusBar, -+ StyleSheet, -+ View -+} from 'react-native'; -+import Animated, { -+ interpolate, -+ runOnJS, -+ useAnimatedGestureHandler, -+ useAnimatedStyle, -+ useDerivedValue, -+ useSharedValue, -+ withSpring -+} from 'react-native-reanimated'; - import DrawerProgressContext from '../../utils/DrawerProgressContext'; - import { GestureState, PanGestureHandler } from '../GestureHandler'; - import Overlay from './Overlay'; -@@ -35,9 +66,8 @@ export default function Drawer(_ref) { - overlayAccessibilityLabel - } = _ref; - const getDrawerWidth = () => { -- const { -- width = DEFAULT_DRAWER_WIDTH -- } = StyleSheet.flatten(drawerStyle) || {}; -+ const { width = DEFAULT_DRAWER_WIDTH } = -+ StyleSheet.flatten(drawerStyle) || {}; - if (typeof width === 'string' && width.endsWith('%')) { - // Try to calculate width if a percentage is given - const percentage = Number(width.replace(/%$/, '')); -@@ -50,19 +80,25 @@ export default function Drawer(_ref) { - const drawerWidth = getDrawerWidth(); - const isOpen = drawerType === 'permanent' ? true : open; - const isRight = drawerPosition === 'right'; -- const getDrawerTranslationX = React.useCallback(open => { -- 'worklet'; -+ const getDrawerTranslationX = React.useCallback( -+ open => { -+ 'worklet'; - -- if (drawerPosition === 'left') { -- return open ? 0 : -drawerWidth; -- } -- return open ? 0 : drawerWidth; -- }, [drawerPosition, drawerWidth]); -- const hideStatusBar = React.useCallback(hide => { -- if (hideStatusBarOnOpen) { -- StatusBar.setHidden(hide, statusBarAnimation); -- } -- }, [hideStatusBarOnOpen, statusBarAnimation]); -+ if (drawerPosition === 'left') { -+ return open ? 0 : -drawerWidth; -+ } -+ return open ? 0 : drawerWidth; -+ }, -+ [drawerPosition, drawerWidth] -+ ); -+ const hideStatusBar = React.useCallback( -+ hide => { -+ if (hideStatusBarOnOpen) { -+ StatusBar.setHidden(hide, statusBarAnimation); -+ } -+ }, -+ [hideStatusBarOnOpen, statusBarAnimation] -+ ); - React.useEffect(() => { - hideStatusBar(isOpen); - return () => hideStatusBar(false); -@@ -93,55 +129,59 @@ export default function Drawer(_ref) { - - // FIXME: Currently hitSlop is broken when on Android when drawer is on right - // https://github.com/software-mansion/react-native-gesture-handler/issues/569 -- const hitSlop = isRight ? -- // Extend hitSlop to the side of the screen when drawer is closed -- // This lets the user drag the drawer from the side of the screen -- { -- right: 0, -- width: isOpen ? undefined : swipeEdgeWidth -- } : { -- left: 0, -- width: isOpen ? undefined : swipeEdgeWidth -- }; -+ const hitSlop = isRight -+ ? // Extend hitSlop to the side of the screen when drawer is closed -+ // This lets the user drag the drawer from the side of the screen -+ { -+ right: 0, -+ width: isOpen ? undefined : swipeEdgeWidth -+ } -+ : { -+ left: 0, -+ width: isOpen ? undefined : swipeEdgeWidth -+ }; - const touchStartX = useSharedValue(0); - const touchX = useSharedValue(0); - const translationX = useSharedValue(getDrawerTranslationX(open)); - const gestureState = useSharedValue(GestureState.UNDETERMINED); -- const toggleDrawer = React.useCallback(_ref2 => { -- 'worklet'; -+ const toggleDrawer = React.useCallback( -+ _ref2 => { -+ 'worklet'; - -- let { -- open, -- isUserInitiated, -- velocity -- } = _ref2; -- const translateX = getDrawerTranslationX(open); -- touchStartX.value = 0; -- touchX.value = 0; -- translationX.value = withSpring(translateX, { -- velocity, -- stiffness: 1000, -- damping: 500, -- mass: 3, -- overshootClamping: true, -- restDisplacementThreshold: 0.01, -- restSpeedThreshold: 0.01, -- // @ts-expect-error: This is available in newer reanimated versions -- reduceMotion: 'never' -- }); -- if (!isUserInitiated) { -- return; -- } -- if (open) { -- runOnJS(onOpen)(); -- } else { -- runOnJS(onClose)(); -- } -- }, [getDrawerTranslationX, onClose, onOpen, touchStartX, touchX, translationX]); -- React.useEffect(() => toggleDrawer({ -- open, -- isUserInitiated: false -- }), [open, toggleDrawer]); -+ let { open, isUserInitiated, velocity } = _ref2; -+ const translateX = getDrawerTranslationX(open); -+ touchStartX.value = 0; -+ touchX.value = 0; -+ translationX.value = withSpring(translateX, { -+ velocity, -+ stiffness: 1000, -+ damping: 500, -+ mass: 3, -+ overshootClamping: true, -+ restDisplacementThreshold: 0.01, -+ restSpeedThreshold: 0.01, -+ // @ts-expect-error: This is available in newer reanimated versions -+ reduceMotion: 'never' -+ }); -+ if (!isUserInitiated) { -+ return; -+ } -+ if (open) { -+ runOnJS(onOpen)(); -+ } else { -+ runOnJS(onClose)(); -+ } -+ }, -+ [getDrawerTranslationX, onClose, onOpen, touchStartX, touchX, translationX] -+ ); -+ React.useEffect( -+ () => -+ toggleDrawer({ -+ open, -+ isUserInitiated: false -+ }), -+ [open, toggleDrawer] -+ ); - const onGestureEvent = useAnimatedGestureHandler({ - onStart: (event, ctx) => { - ctx.hasCalledOnStart = false; -@@ -164,11 +204,16 @@ export default function Drawer(_ref) { - }, - onEnd: event => { - gestureState.value = event.state; -- const nextOpen = Math.abs(event.translationX) > SWIPE_DISTANCE_MINIMUM && Math.abs(event.translationX) > swipeVelocityThreshold || Math.abs(event.translationX) > swipeDistanceThreshold ? drawerPosition === 'left' ? -- // If swiped to right, open the drawer, otherwise close it -- (event.velocityX === 0 ? event.translationX : event.velocityX) > 0 : -- // If swiped to left, open the drawer, otherwise close it -- (event.velocityX === 0 ? event.translationX : event.velocityX) < 0 : open; -+ const nextOpen = -+ (Math.abs(event.translationX) > SWIPE_DISTANCE_MINIMUM && -+ Math.abs(event.translationX) > swipeVelocityThreshold) || -+ Math.abs(event.translationX) > swipeDistanceThreshold -+ ? drawerPosition === 'left' -+ ? // If swiped to right, open the drawer, otherwise close it -+ (event.velocityX === 0 ? event.translationX : event.velocityX) > 0 -+ : // If swiped to left, open the drawer, otherwise close it -+ (event.velocityX === 0 ? event.translationX : event.velocityX) < 0 -+ : open; - toggleDrawer({ - open: nextOpen, - isUserInitiated: true, -@@ -205,72 +250,159 @@ export default function Drawer(_ref) { - // drawer be pulled back as soon as you start the pan. - // - // This is used only when drawerType is "front" -- const touchDistance = drawerType === 'front' && gestureState.value === GestureState.ACTIVE ? minmax(drawerPosition === 'left' ? touchStartX.value - drawerWidth : dimensions.width - drawerWidth - touchStartX.value, 0, dimensions.width) : 0; -- const translateX = drawerPosition === 'left' ? minmax(translationX.value + touchDistance, -drawerWidth, 0) : minmax(translationX.value - touchDistance, 0, drawerWidth); -+ const touchDistance = -+ drawerType === 'front' && gestureState.value === GestureState.ACTIVE -+ ? minmax( -+ drawerPosition === 'left' -+ ? touchStartX.value - drawerWidth -+ : dimensions.width - drawerWidth - touchStartX.value, -+ 0, -+ dimensions.width -+ ) -+ : 0; -+ const translateX = -+ drawerPosition === 'left' -+ ? minmax(translationX.value + touchDistance, -drawerWidth, 0) -+ : minmax(translationX.value - touchDistance, 0, drawerWidth); - return translateX; - }); - const isRTL = I18nManager.getConstants().isRTL; - const drawerAnimatedStyle = useAnimatedStyle(() => { - const distanceFromEdge = dimensions.width - drawerWidth; - return { -- transform: drawerType === 'permanent' ? -- // Reanimated needs the property to be present, but it results in Browser bug -- // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 -- [] : [{ -- translateX: -- // The drawer stays in place when `drawerType` is `back` -- (drawerType === 'back' ? 0 : translateX.value) + (drawerPosition === 'left' ? isRTL ? -distanceFromEdge : 0 : isRTL ? 0 : distanceFromEdge) -- }] -+ transform: -+ drawerType === 'permanent' -+ ? // Reanimated needs the property to be present, but it results in Browser bug -+ // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 -+ [] -+ : [ -+ { -+ translateX: -+ // The drawer stays in place when `drawerType` is `back` -+ (drawerType === 'back' ? 0 : translateX.value) + -+ (drawerPosition === 'left' -+ ? isRTL -+ ? -distanceFromEdge -+ : 0 -+ : isRTL -+ ? 0 -+ : distanceFromEdge) -+ } -+ ] +@@ -222,7 +222,7 @@ export default function Drawer(_ref) { + (drawerType === 'back' ? 0 : translateX.value) + (drawerPosition === 'left' ? isRTL ? -distanceFromEdge : 0 : isRTL ? 0 : distanceFromEdge) + }] }; - }); -+ }, [ -+ dimensions.width, -+ drawerPosition, -+ drawerType, -+ drawerWidth, -+ isRTL, -+ translateX -+ ]); ++ }, [dimensions.width, drawerPosition, drawerType, drawerWidth, isRTL, translateX]); const contentAnimatedStyle = useAnimatedStyle(() => { return { -- transform: drawerType === 'permanent' ? -- // Reanimated needs the property to be present, but it results in Browser bug -- // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 -- [] : [{ -- translateX: -- // The screen content stays in place when `drawerType` is `front` -- drawerType === 'front' ? 0 : translateX.value + drawerWidth * (drawerPosition === 'left' ? 1 : -1) -- }] -+ transform: -+ drawerType === 'permanent' -+ ? // Reanimated needs the property to be present, but it results in Browser bug -+ // https://bugs.chromium.org/p/chromium/issues/detail?id=20574 -+ [] -+ : [ -+ { -+ translateX: -+ // The screen content stays in place when `drawerType` is `front` -+ drawerType === 'front' -+ ? 0 -+ : translateX.value + -+ drawerWidth * (drawerPosition === 'left' ? 1 : -1) -+ } -+ ] + transform: drawerType === 'permanent' ? +@@ -234,7 +234,7 @@ export default function Drawer(_ref) { + drawerType === 'front' ? 0 : translateX.value + drawerWidth * (drawerPosition === 'left' ? 1 : -1) + }] }; - }); + }, [drawerPosition, drawerType, drawerWidth, translateX]); const progress = useDerivedValue(() => { -- return drawerType === 'permanent' ? 1 : interpolate(translateX.value, [getDrawerTranslationX(false), getDrawerTranslationX(true)], [0, 1]); -+ return drawerType === 'permanent' -+ ? 1 -+ : interpolate( -+ translateX.value, -+ [getDrawerTranslationX(false), getDrawerTranslationX(true)], -+ [0, 1] -+ ); + return drawerType === 'permanent' ? 1 : interpolate(translateX.value, [getDrawerTranslationX(false), getDrawerTranslationX(true)], [0, 1]); }); -- return /*#__PURE__*/React.createElement(DrawerProgressContext.Provider, { -- value: progress -- }, /*#__PURE__*/React.createElement(PanGestureHandler, _extends({ -- activeOffsetX: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], -- failOffsetY: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], -- hitSlop: hitSlop, -- enabled: drawerType !== 'permanent' && swipeEnabled, -- onGestureEvent: onGestureEvent -- }, gestureHandlerProps), /*#__PURE__*/React.createElement(Animated.View, { -- style: [styles.main, { -- flexDirection: drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row' -- }] -- }, /*#__PURE__*/React.createElement(Animated.View, { -- style: [styles.content, contentAnimatedStyle] -- }, /*#__PURE__*/React.createElement(View, { -- accessibilityElementsHidden: isOpen && drawerType !== 'permanent', -- importantForAccessibility: isOpen && drawerType !== 'permanent' ? 'no-hide-descendants' : 'auto', -- style: styles.content -- }, renderSceneContent()), drawerType !== 'permanent' ? /*#__PURE__*/React.createElement(Overlay, { -- progress: progress, -- onPress: () => toggleDrawer({ -- open: false, -- isUserInitiated: true -- }), -- style: overlayStyle, -- accessibilityLabel: overlayAccessibilityLabel -- }) : null), /*#__PURE__*/React.createElement(Animated.View, { -- removeClippedSubviews: Platform.OS !== 'ios', -- style: [styles.container, { -- position: drawerType === 'permanent' ? 'relative' : 'absolute', -- zIndex: drawerType === 'back' ? -1 : 0 -- }, drawerAnimatedStyle, drawerStyle] -- }, renderDrawerContent())))); -+ return /*#__PURE__*/ React.createElement( -+ DrawerProgressContext.Provider, -+ { -+ value: progress -+ }, -+ /*#__PURE__*/ React.createElement( -+ PanGestureHandler, -+ _extends( -+ { -+ activeOffsetX: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], -+ failOffsetY: [-SWIPE_DISTANCE_MINIMUM, SWIPE_DISTANCE_MINIMUM], -+ hitSlop: hitSlop, -+ enabled: drawerType !== 'permanent' && swipeEnabled, -+ onGestureEvent: onGestureEvent -+ }, -+ gestureHandlerProps -+ ), -+ /*#__PURE__*/ React.createElement( -+ Animated.View, -+ { -+ style: [ -+ styles.main, -+ { -+ flexDirection: -+ drawerType === 'permanent' && !isRight ? 'row-reverse' : 'row' -+ } -+ ] -+ }, -+ /*#__PURE__*/ React.createElement( -+ Animated.View, -+ { -+ style: [styles.content, contentAnimatedStyle] -+ }, -+ /*#__PURE__*/ React.createElement( -+ View, -+ { -+ accessibilityElementsHidden: isOpen && drawerType !== 'permanent', -+ importantForAccessibility: -+ isOpen && drawerType !== 'permanent' -+ ? 'no-hide-descendants' -+ : 'auto', -+ style: styles.content -+ }, -+ renderSceneContent() -+ ), -+ drawerType !== 'permanent' -+ ? /*#__PURE__*/ React.createElement(Overlay, { -+ progress: progress, -+ onPress: () => -+ toggleDrawer({ -+ open: false, -+ isUserInitiated: true -+ }), -+ style: overlayStyle, -+ accessibilityLabel: overlayAccessibilityLabel -+ }) -+ : null -+ ), -+ /*#__PURE__*/ React.createElement( -+ Animated.View, -+ { -+ removeClippedSubviews: Platform.OS !== 'ios', -+ style: [ -+ styles.container, -+ { -+ position: drawerType === 'permanent' ? 'relative' : 'absolute', -+ zIndex: drawerType === 'back' ? -1 : 0 -+ }, -+ drawerAnimatedStyle, -+ drawerStyle -+ ] -+ }, -+ renderDrawerContent() -+ ) -+ ) -+ ) -+ ); - } - const styles = StyleSheet.create({ - container: { -@@ -295,3 +427,4 @@ const styles = StyleSheet.create({ - } - }); - //# sourceMappingURL=Drawer.js.map -+ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e88e64bede..ac418d3e0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,7 +25,7 @@ patchedDependencies: hash: zkdmh374s554i7qlaqtqn2nhfm path: patches/@likashefqet__react-native-image-zoom@3.0.0.patch '@react-navigation/drawer@6.7.2': - hash: xry4exjnht3vohn7iwtifercxi + hash: uvadz7wecy3yfbv66nyfswys5y path: patches/@react-navigation__drawer@6.7.2.patch '@tiptap/react@2.0.3': hash: tt2duu22fpwhmhaws3iaoig4mu @@ -149,7 +149,7 @@ importers: version: 6.5.12(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.7.2 - version: 6.7.2(patch_hash=xry4exjnht3vohn7iwtifercxi)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 6.7.2(patch_hash=uvadz7wecy3yfbv66nyfswys5y)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': specifier: ^6.1.7 version: 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -1027,7 +1027,7 @@ importers: version: 1.0.0(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.7.2 - version: 6.7.2(patch_hash=xry4exjnht3vohn7iwtifercxi)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 6.7.2(patch_hash=uvadz7wecy3yfbv66nyfswys5y)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': specifier: ^6.1.7 version: 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -18766,7 +18766,7 @@ snapshots: react: 18.2.0 stacktrace-parser: 0.1.10 - ? '@react-navigation/drawer@6.7.2(patch_hash=xry4exjnht3vohn7iwtifercxi)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)' + ? '@react-navigation/drawer@6.7.2(patch_hash=uvadz7wecy3yfbv66nyfswys5y)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)' : dependencies: '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) From 80a44dc07f2fa5eec2d595a35755874571175538 Mon Sep 17 00:00:00 2001 From: Hunter Miller Date: Tue, 29 Oct 2024 14:08:05 -0500 Subject: [PATCH 236/259] groups-ui: preload -> suggested + import action --- desk/app/groups-ui.hoon | 56 ++++++++++++++++++++++++----------- desk/mar/ui/hide-contact.hoon | 2 ++ desk/mar/ui/import-pals.hoon | 2 ++ desk/mar/ui/show-contact.hoon | 2 ++ 4 files changed, 44 insertions(+), 18 deletions(-) create mode 100644 desk/mar/ui/hide-contact.hoon create mode 100644 desk/mar/ui/import-pals.hoon create mode 100644 desk/mar/ui/show-contact.hoon diff --git a/desk/app/groups-ui.hoon b/desk/app/groups-ui.hoon index 22a435db83..193615b82f 100644 --- a/desk/app/groups-ui.hoon +++ b/desk/app/groups-ui.hoon @@ -8,6 +8,7 @@ +$ card card:agent:gall +$ current-state $: %2 + hidden-contact-suggestions=(set ship) pins=(list whom:u) first-load=? == @@ -88,8 +89,6 @@ =+ !<(old=versioned-state vase) =? old ?=(~ old) *current-state =? old ?=(%0 -.old) (state-0-to-1 old) - =? cor ?=(%1 -.old) - (emit %pass /preload-contacts %agent [our dap]:bowl %poke noun+!>(%preload-contacts)) =? old ?=(%1 -.old) (state-1-to-2 old) ?> ?=(%2 -.old) =. state old @@ -104,7 +103,7 @@ == :: ++ state-1-to-2 - |=(state-1 [%2 pins first-load]) + |=(state-1 [%2 ~ pins first-load]) +$ state-0 [%0 first-load=?] ++ state-0-to-1 |=(state-0 [%1 ~ first-load]) @@ -115,6 +114,12 @@ ^- (unit (unit cage)) ?+ pole [~ ~] [%x %pins ~] ``ui-pins+!>(pins) + :: + [%x %hidden-contact-suggestions ~] + ``ships+!>(hidden-contact-suggestions) + :: + [%x %suggested-contacts ~] + ``ships+!>(get-suggested-contacts) :: [%x %init ~] =+ .^([=groups-ui:g =gangs:g] (scry %gx %groups /init/v1/noun)) @@ -209,11 +214,19 @@ ^+ cor ?+ mark ~|(bad-mark/mark !!) %ui-vita (emit (active:vita-client bowl)) + %ui-import-pals import-pals :: - %noun - ?+ q.vase ~|(bad-poke+mark !!) - %preload-contacts preload-contacts - == + %ui-show-contact + =+ !<(=ship vase) + =. hidden-contact-suggestions + (~(del in hidden-contact-suggestions) ship) + cor + :: + %ui-hide-contact + =+ !<(=ship vase) + =. hidden-contact-suggestions + (~(put in hidden-contact-suggestions) ship) + cor :: %ui-vita-toggle =+ !<(=vita-enabled:u vase) @@ -254,13 +267,15 @@ ?+ wire !! [%build ~] cor == -++ preload-contacts +++ get-suggested-contacts =+ .^(chat-running=? (scry %gu %chat /$)) - =? cor chat-running + =| suggestions=(set ship) + =? suggestions chat-running =+ .^ [dms=(map ship dm:c) *] (scry %gx %chat /full/noun) == - %- emil + %- ~(uni in suggestions) + %- sy %+ murn ~(tap by dms) |= [=ship =dm:c] @@ -268,14 +283,19 @@ =/ count (wyt:on:writs:c wit.pact.dm) =/ cutoff (sub now.bowl ~d30) ?. &((gth count 10) (gth -.u.latest cutoff)) ~ - `[%pass /contact %agent [our.bowl %contacts] %poke contact-action-1+!>([%page ship ~])] + `ship =+ .^(pals-running=? (scry %gu %pals /$)) - =? cor pals-running + =? suggestions pals-running =+ .^(targets=(set ship) (scry %gx %pals /targets/noun)) - %- emil - %+ turn - ~(tap in targets) - |= =ship - [%pass /contact %agent [our.bowl %contacts] %poke contact-action-1+!>([%page ship ~])] - cor + (~(uni in suggestions) targets) + (~(dif in suggestions) hidden-contact-suggestions) +++ import-pals + =+ .^(pals-running=? (scry %gu %pals /$)) + ?. pals-running cor + =+ .^(targets=(set ship) (scry %gx %pals /targets/noun)) + %- emil + %+ turn + ~(tap in targets) + |= =ship + [%pass /contact %agent [our.bowl %contacts] %poke contact-action-1+!>([%page ship ~])] -- diff --git a/desk/mar/ui/hide-contact.hoon b/desk/mar/ui/hide-contact.hoon new file mode 100644 index 0000000000..f795efd06f --- /dev/null +++ b/desk/mar/ui/hide-contact.hoon @@ -0,0 +1,2 @@ +/= mark /mar/ship +mark diff --git a/desk/mar/ui/import-pals.hoon b/desk/mar/ui/import-pals.hoon new file mode 100644 index 0000000000..bfec219f21 --- /dev/null +++ b/desk/mar/ui/import-pals.hoon @@ -0,0 +1,2 @@ +/= mark /mar/dummy +mark \ No newline at end of file diff --git a/desk/mar/ui/show-contact.hoon b/desk/mar/ui/show-contact.hoon new file mode 100644 index 0000000000..f795efd06f --- /dev/null +++ b/desk/mar/ui/show-contact.hoon @@ -0,0 +1,2 @@ +/= mark /mar/ship +mark From 61bfee937f5f6ce067aafb01b1884049fed3d435 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 29 Oct 2024 14:45:39 -0500 Subject: [PATCH 237/259] input: show ref previews and allow attachments in chat threads --- packages/ui/src/components/PostScreenView.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/ui/src/components/PostScreenView.tsx b/packages/ui/src/components/PostScreenView.tsx index 03098f615b..4eb6402e4a 100644 --- a/packages/ui/src/components/PostScreenView.tsx +++ b/packages/ui/src/components/PostScreenView.tsx @@ -223,6 +223,8 @@ export function PostScreenView({ editPost={editPost} channelType="chat" getDraft={getDraft} + showAttachmentButton={channel.type === 'chat'} + showInlineAttachments={channel.type === 'chat'} shouldAutoFocus={ (channel.type === 'chat' && parentPost?.replyCount === 0) || !!editingPost From 66d79b4dc982143c4dfb758b04d393eb061105e4 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Oct 2024 20:04:47 +0000 Subject: [PATCH 238/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index f310dadacb..6ab897bfca 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v1.n7qcb.nki5c.smn6g.v1gdn.2tp19.glob' 0v1.n7qcb.nki5c.smn6g.v1gdn.2tp19] + glob-http+['https://bootstrap.urbit.org/glob-0v2.8ptkr.rus77.76rnh.ol153.qtgdp.glob' 0v2.8ptkr.rus77.76rnh.ol153.qtgdp] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From f45e3f5ccc0494948c98b0501c9f6f1d2b178c55 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Tue, 29 Oct 2024 15:17:20 -0500 Subject: [PATCH 239/259] change useIsMobile hook to useIsWindowNarrow --- apps/tlon-mobile/ios/Podfile.lock | 2 +- packages/app/navigation/RootStack.tsx | 6 +++--- packages/ui/src/components/Channel/ChannelHeader.tsx | 6 +++--- packages/ui/src/components/GroupChannelsScreenView.tsx | 6 +++--- packages/ui/src/components/NavBarView.tsx | 6 +++--- .../ui/src/hooks/{useIsMobile.ts => useIsWindowNarrow.ts} | 2 +- packages/ui/src/index.tsx | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) rename packages/ui/src/hooks/{useIsMobile.ts => useIsWindowNarrow.ts} (71%) diff --git a/apps/tlon-mobile/ios/Podfile.lock b/apps/tlon-mobile/ios/Podfile.lock index 06412313e2..716c600b86 100644 --- a/apps/tlon-mobile/ios/Podfile.lock +++ b/apps/tlon-mobile/ios/Podfile.lock @@ -1880,7 +1880,7 @@ SPEC CHECKSUMS: sqlite3: f163dbbb7aa3339ad8fc622782c2d9d7b72f7e9c tentap: 2cf2e387dd284bf867010eb7d0f91618fb35b673 UMAppLoader: 5df85360d65cabaef544be5424ac64672e648482 - Yoga: 4dbfeceb9bb0f62899d0a53d37a1ddd58898d3f2 + Yoga: fb61b2337c7688c81a137e5560b3cbb515289f91 PODFILE CHECKSUM: 0cb7a78e5777e69c86c1bf4bb5135fd660376dbe diff --git a/packages/app/navigation/RootStack.tsx b/packages/app/navigation/RootStack.tsx index b65f1f327b..43d41350d5 100644 --- a/packages/app/navigation/RootStack.tsx +++ b/packages/app/navigation/RootStack.tsx @@ -1,6 +1,6 @@ import { useFocusEffect } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import { useTheme, useIsMobile } from '@tloncorp/ui'; +import { useTheme, useIsWindowNarrow } from '@tloncorp/ui'; import { Platform, StatusBar } from 'react-native'; import { ChannelMembersScreen } from '../features/channels/ChannelMembersScreen'; @@ -42,11 +42,11 @@ export function RootStack() { }); const theme = useTheme(); - const isMobile = useIsMobile(); + const isWindowNarrow = useIsWindowNarrow(); return ( ; @@ -127,7 +127,7 @@ export function ChannelHeader({ showSessionStatus isLoading={showSpinner} leftControls={ - isMobile ? : undefined + isWindowNarrow ? : undefined } rightControls={ <> diff --git a/packages/ui/src/components/GroupChannelsScreenView.tsx b/packages/ui/src/components/GroupChannelsScreenView.tsx index 1a3b5182e4..fb87988cbf 100644 --- a/packages/ui/src/components/GroupChannelsScreenView.tsx +++ b/packages/ui/src/components/GroupChannelsScreenView.tsx @@ -4,7 +4,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { ScrollView, View, YStack } from 'tamagui'; import { useCurrentUserId } from '../contexts'; -import useIsMobile from '../hooks/useIsMobile'; +import useIsWindowNarrow from '../hooks/useIsWindowNarrow'; import { useIsAdmin } from '../utils/channelUtils'; import ChannelNavSections from './ChannelNavSections'; import { ChatOptionsSheet, ChatOptionsSheetMethods } from './ChatOptionsSheet'; @@ -66,7 +66,7 @@ export function GroupChannelsScreenView({ } }, [isGroupAdmin]); - const isMobile = useIsMobile(); + const isWindowNarrow = useIsWindowNarrow(); return ( @@ -109,7 +109,7 @@ export function GroupChannelsScreenView({ channels={group.channels} onSelect={onChannelPressed} sortBy={sortBy || 'recency'} - onLongPress={isMobile ? handleOpenChannelOptions : undefined} + onLongPress={isWindowNarrow ? handleOpenChannelOptions : undefined} /> ) : ( diff --git a/packages/ui/src/components/NavBarView.tsx b/packages/ui/src/components/NavBarView.tsx index f53a88b733..9ebf882ecc 100644 --- a/packages/ui/src/components/NavBarView.tsx +++ b/packages/ui/src/components/NavBarView.tsx @@ -1,6 +1,6 @@ import * as store from '@tloncorp/shared/store'; -import useIsMobile from '../hooks/useIsMobile'; +import useIsWindowNarrow from '../hooks/useIsWindowNarrow'; import { AvatarNavIcon, NavBar, NavIcon } from './NavBar'; export const NavBarView = ({ @@ -20,9 +20,9 @@ export const NavBarView = ({ return currentRoute === routeName; }; const haveUnreadUnseenActivity = store.useHaveUnreadUnseenActivity(); - const isMobile = useIsMobile(); + const isWindowNarrow = useIsWindowNarrow(); - if (!isMobile) { + if (!isWindowNarrow) { return null; } diff --git a/packages/ui/src/hooks/useIsMobile.ts b/packages/ui/src/hooks/useIsWindowNarrow.ts similarity index 71% rename from packages/ui/src/hooks/useIsMobile.ts rename to packages/ui/src/hooks/useIsWindowNarrow.ts index bfc1414e7f..c5a933962c 100644 --- a/packages/ui/src/hooks/useIsMobile.ts +++ b/packages/ui/src/hooks/useIsWindowNarrow.ts @@ -1,6 +1,6 @@ import { useWindowDimensions } from 'tamagui' -export default function useIsMobile() { +export default function useIsWindowNarrow() { const { width } = useWindowDimensions(); return width < 768; } diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index de520f2e45..e97b6b9895 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -81,7 +81,7 @@ export * from './tamagui.config'; export * from './types'; export * from './utils'; export * as TlonText from './components/TextV2'; -export { default as useIsMobile } from './hooks/useIsMobile'; +export { default as useIsWindowNarrow } from './hooks/useIsWindowNarrow'; export { Circle, From 89ce74642747d070a614cc50373f7e7bb4b0da62 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 29 Oct 2024 20:31:01 +0000 Subject: [PATCH 240/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 6ab897bfca..3df0ac422d 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v2.8ptkr.rus77.76rnh.ol153.qtgdp.glob' 0v2.8ptkr.rus77.76rnh.ol153.qtgdp] + glob-http+['https://bootstrap.urbit.org/glob-0v5.db799.j0451.ljtdp.r62n9.infqs.glob' 0v5.db799.j0451.ljtdp.r62n9.infqs] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From 26b6ea800f90557a926d0efdfe213e15e9579061 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Wed, 30 Oct 2024 11:23:16 -0500 Subject: [PATCH 241/259] use separate build script for EAS post-install --- apps/tlon-mobile/package.json | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/tlon-mobile/package.json b/apps/tlon-mobile/package.json index 643753704d..cd09fff60a 100644 --- a/apps/tlon-mobile/package.json +++ b/apps/tlon-mobile/package.json @@ -25,7 +25,7 @@ "tsc": "tsc --noEmit", "build": "pnpm generate", "cosmos": "cosmos-native", - "eas-build-post-install": "pnpm -w run build:all" + "eas-build-post-install": "pnpm -w run build:mobile-release" }, "lint-staged": { "*.{js,jsx,ts,tsx,json,md,html}": [ diff --git a/package.json b/package.json index 169692cf3a..9c1a22e341 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:mobile": "pnpm --filter 'tlon-mobile' build", "build:apps": "pnpm run build:mobile && pnpm run build:web && pnpm run build:new-web", "build:packages": "pnpm run build:shared && pnpm run build:ui && pnpm run build:editor", + "build:mobile-release": "pnpm run build:packages && pnpm run build:mobile", "build:all": "pnpm run build:packages && pnpm run build:apps", "dev:shared": "pnpm --filter '@tloncorp/shared' dev", "dev:android": "concurrently \"pnpm run dev:shared\" \"pnpm --filter 'tlon-mobile' dev\" \"pnpm --filter 'tlon-mobile' android\"", From 1e6ca9c20024c62c9a1615cc3e326911772354b3 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 30 Oct 2024 15:55:03 -0400 Subject: [PATCH 242/259] BareChatInput: eliminate all line-height shennanigans --- .../ui/src/components/BareChatInput/index.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index d53dd32f78..4001c876de 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -556,20 +556,19 @@ export default function BareChatInput({ style={{ backgroundColor: 'transparent', minHeight: initialHeight, - height: isWeb ? inputHeight : undefined, + height: isWeb ? inputHeight : undefined, maxHeight: maxInputHeight - getTokenValue('$s', 'space'), paddingHorizontal: getTokenValue('$l', 'space'), - paddingTop: getTokenValue('$s', 'space') + paddingTopAdjustment, - paddingBottom: getTokenValue('$s', 'space'), + paddingTop: getTokenValue('$l', 'space'), + paddingBottom: getTokenValue('$l', 'space'), fontSize: getFontSize('$m'), textAlignVertical: 'top', - lineHeight: getFontSize('$m') * 1.5, + // lineHeight: getFontSize('$m') * 1.5, letterSpacing: -0.032, - // @ts-expect-error this property is not supported on native, - // but it is on web. Removes the blue outline on web. - outlineStyle: 'none', + color: getVariableValue(useTheme().primaryText), ...placeholderTextColor, + ...(isWeb ? { outlineStyle: 'none' } : {}), }} placeholder={placeholder} /> @@ -577,10 +576,10 @@ export default function BareChatInput({ From acc38ed06ed05bb9519fe8e66131f675972364bf Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 30 Oct 2024 16:32:36 -0400 Subject: [PATCH 243/259] BareChatInput: enhance multiline support and adjust padding based on content size --- .../ui/src/components/BareChatInput/index.tsx | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 4001c876de..bbbfc2071d 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -103,6 +103,7 @@ export default function BareChatInput({ } = useMentions(); const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); const inputRef = useRef(null); + const [isMultiline, setIsMultiline] = useState(false); const processReferences = useCallback( (text: string): string => { @@ -504,19 +505,30 @@ export default function BareChatInput({ if (!isWeb) { return; } - // we need to manipulate the element directly in order to adjust the height - // back down as the content shrinks, apparently - // https://github.com/necolas/react-native-web/issues/795 - // + const el = e?.target; if (el && 'style' in el && 'height' in el.style) { - el.style.height = 0; - const newHeight = el.offsetHeight - el.clientHeight + el.scrollHeight; + el.style.height = `${initialHeight}px`; + const scrollHeight = el.scrollHeight; + const newHeight = Math.max(initialHeight, scrollHeight); el.style.height = `${newHeight}px`; setInputHeight(newHeight); + setIsMultiline(scrollHeight > initialHeight); } }; + const handleContentSizeChange = (event: any) => { + if (isWeb) { + return; + } + const { height } = event.nativeEvent.contentSize; + const topPadding = getTokenValue('$l', 'space'); + const bottomPadding = getTokenValue('$s', 'space'); + + const fullHeight = height + topPadding + bottomPadding; + setIsMultiline(fullHeight > initialHeight); + }; + return ( From 615694dc185f23880d23d8b5391cf3cc66b0b488 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Wed, 30 Oct 2024 19:09:44 -0400 Subject: [PATCH 244/259] BareChatInput: eliminate lineheight for experimentation's sake --- .../ui/src/components/BareChatInput/index.tsx | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index bbbfc2071d..dfd74e6008 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -18,7 +18,7 @@ import { pathToCite, } from '@tloncorp/shared/urbit'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { Keyboard, Platform, TextInput } from 'react-native'; +import { Keyboard, TextInput } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { View, @@ -103,7 +103,6 @@ export default function BareChatInput({ } = useMentions(); const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); const inputRef = useRef(null); - const [isMultiline, setIsMultiline] = useState(false); const processReferences = useCallback( (text: string): string => { @@ -489,9 +488,6 @@ export default function BareChatInput({ clearAttachments(); }, [setEditingPost, clearDraft, clearAttachments]); - const paddingTopAdjustment = Platform.OS === 'ios' ? 2 : 4; - const mentionLineHeightAdjustment = Platform.OS === 'ios' ? 1.3 : 1.5; - const theme = useTheme(); // placeholderTextColor is not supported on native, just web // https://necolas.github.io/react-native-web/docs/text-input/ @@ -513,20 +509,7 @@ export default function BareChatInput({ const newHeight = Math.max(initialHeight, scrollHeight); el.style.height = `${newHeight}px`; setInputHeight(newHeight); - setIsMultiline(scrollHeight > initialHeight); - } - }; - - const handleContentSizeChange = (event: any) => { - if (isWeb) { - return; } - const { height } = event.nativeEvent.contentSize; - const topPadding = getTokenValue('$l', 'space'); - const bottomPadding = getTokenValue('$s', 'space'); - - const fullHeight = height + topPadding + bottomPadding; - setIsMultiline(fullHeight > initialHeight); }; return ( @@ -564,7 +547,6 @@ export default function BareChatInput({ onChangeText={handleTextChange} onChange={isWeb ? adjustTextInputSize : undefined} onLayout={isWeb ? adjustTextInputSize : undefined} - onContentSizeChange={!isWeb ? handleContentSizeChange : undefined} multiline style={{ backgroundColor: 'transparent', @@ -573,12 +555,9 @@ export default function BareChatInput({ maxHeight: maxInputHeight - getTokenValue('$s', 'space'), paddingHorizontal: getTokenValue('$l', 'space'), paddingTop: getTokenValue('$l', 'space'), - paddingBottom: isMultiline - ? getTokenValue('$l', 'space') - : getTokenValue('$s', 'space'), + paddingBottom: getTokenValue('$l', 'space'), fontSize: getFontSize('$m'), - textAlignVertical: 'top', - lineHeight: isMultiline ? 24 : undefined, + textAlignVertical: 'center', letterSpacing: -0.032, color: getVariableValue(useTheme().primaryText), ...placeholderTextColor, @@ -590,10 +569,7 @@ export default function BareChatInput({ From b7a920abfca4285e61fedea41e73cf06bad917d6 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 31 Oct 2024 07:43:31 -0500 Subject: [PATCH 245/259] web-new: fix build issue, clean up vite config --- apps/tlon-web-new/reactNativeWebPlugin.ts | 58 ++++++++++++++++++- apps/tlon-web-new/vite.config.mts | 37 ------------ patches/@react-navigation__drawer@6.7.2.patch | 27 ++++++++- pnpm-lock.yaml | 8 +-- 4 files changed, 87 insertions(+), 43 deletions(-) diff --git a/apps/tlon-web-new/reactNativeWebPlugin.ts b/apps/tlon-web-new/reactNativeWebPlugin.ts index 1b3972d9a1..7cc8cfd415 100644 --- a/apps/tlon-web-new/reactNativeWebPlugin.ts +++ b/apps/tlon-web-new/reactNativeWebPlugin.ts @@ -3,6 +3,7 @@ import type { Plugin as ESBuildPlugin } from 'esbuild'; // @ts-expect-error - flow-remove-types is not typed import flowRemoveTypes from 'flow-remove-types'; import fs from 'fs/promises'; +import { fileURLToPath } from 'url'; import { transformWithEsbuild } from 'vite'; import type { Plugin as VitePlugin } from 'vite'; @@ -64,7 +65,45 @@ const reactNativeWeb = }, resolve: { extensions, - alias: [{ find: 'react-native', replacement: 'react-native-web' }], + alias: [ + { find: 'react-native', replacement: 'react-native-web' }, + { + find: '@react-native-firebase/crashlytics', + replacement: fileURLToPath( + new URL( + './src/mocks/react-native-firebase-crashlytics.js', + import.meta.url + ) + ), + }, + { + find: '@tloncorp/editor/dist/editorHtml', + replacement: fileURLToPath( + new URL('./src/mocks/tloncorp-editor-html.js', import.meta.url) + ), + }, + { + find: '@tloncorp/editor/src/bridges', + replacement: fileURLToPath( + new URL('./src/mocks/tloncorp-editor-bridges.js', import.meta.url) + ), + }, + { + find: '@10play/tentap-editor', + replacement: fileURLToPath( + new URL('./src/mocks/tentap-editor.js', import.meta.url) + ), + }, + { + find: 'react-native-gesture-handler/ReanimatedSwipeable', + replacement: fileURLToPath( + new URL( + './src/mocks/react-native-gesture-handler.js', + import.meta.url + ) + ), + }, + ], }, optimizeDeps: { esbuildOptions: { @@ -72,6 +111,23 @@ const reactNativeWeb = resolveExtensions: extensions, }, }, + build: { + rollupOptions: { + output: { + manualChunks: { + 'react-native-web': ['react-native-web'], + 'react-native-reanimated': ['react-native-reanimated'], + 'react-native-gesture-handler': ['react-native-gesture-handler'], + 'react-native-screens': ['react-native-screens'], + 'react-native-safe-area-context': [ + 'react-native-safe-area-context', + ], + '@react-navigation/native': ['@react-navigation/native'], + '@react-navigation/drawer': ['@react-navigation/drawer'], + }, + }, + }, + }, }), async transform(code, id) { diff --git a/apps/tlon-web-new/vite.config.mts b/apps/tlon-web-new/vite.config.mts index 7081f90d0a..4e9e046e7e 100644 --- a/apps/tlon-web-new/vite.config.mts +++ b/apps/tlon-web-new/vite.config.mts @@ -146,7 +146,6 @@ export default ({ mode }: { mode: string }) => { 'radix-ui/react-popover': ['@radix-ui/react-popover'], 'radix-ui/react-toast': ['@radix-ui/react-toast'], 'radix-ui/react-tooltip': ['@radix-ui/react-tooltip'], - 'react-native-reanimated': ['react-native-reanimated'], }, }, }; @@ -212,42 +211,6 @@ export default ({ mode }: { mode: string }) => { find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)), }, - { - find: '@react-native-firebase/crashlytics', - replacement: fileURLToPath( - new URL( - './src/mocks/react-native-firebase-crashlytics.js', - import.meta.url - ) - ), - }, - { - find: '@tloncorp/editor/dist/editorHtml', - replacement: fileURLToPath( - new URL('./src/mocks/tloncorp-editor-html.js', import.meta.url) - ), - }, - { - find: '@tloncorp/editor/src/bridges', - replacement: fileURLToPath( - new URL('./src/mocks/tloncorp-editor-bridges.js', import.meta.url) - ), - }, - { - find: '@10play/tentap-editor', - replacement: fileURLToPath( - new URL('./src/mocks/tentap-editor.js', import.meta.url) - ), - }, - { - find: 'react-native-gesture-handler/ReanimatedSwipeable', - replacement: fileURLToPath( - new URL( - './src/mocks/react-native-gesture-handler.js', - import.meta.url - ) - ), - }, ], }, optimizeDeps: { diff --git a/patches/@react-navigation__drawer@6.7.2.patch b/patches/@react-navigation__drawer@6.7.2.patch index ab28152f8c..cd8467cee9 100644 --- a/patches/@react-navigation__drawer@6.7.2.patch +++ b/patches/@react-navigation__drawer@6.7.2.patch @@ -1,5 +1,30 @@ +diff --git a/lib/module/views/DrawerView.js b/lib/module/views/DrawerView.js +index 38765bbff02327474d73480cc9e8996b6a22f019..c264fabce759878a62d495ed2676b730f4111283 100644 +--- a/lib/module/views/DrawerView.js ++++ b/lib/module/views/DrawerView.js +@@ -13,6 +13,7 @@ import DrawerContent from './DrawerContent'; + import DrawerToggleButton from './DrawerToggleButton'; + import { GestureHandlerRootView } from './GestureHandler'; + import { MaybeScreen, MaybeScreenContainer } from './ScreenFallback'; ++import Drawer from './modern/Drawer'; + const getDefaultDrawerWidth = _ref => { + let { + height, +@@ -45,11 +46,10 @@ function DrawerViewBase(_ref2) { + useLegacyImplementation = !((_Reanimated$isConfigu = Reanimated.isConfigured) !== null && _Reanimated$isConfigu !== void 0 && _Reanimated$isConfigu.call(Reanimated)) + } = _ref2; + // Reanimated v3 dropped legacy v1 syntax +- const legacyImplemenationNotAvailable = require('react-native-reanimated').abs === undefined; ++ const legacyImplemenationNotAvailable = true; + if (useLegacyImplementation && legacyImplemenationNotAvailable) { + throw new Error('The `useLegacyImplementation` prop is not available with Reanimated 3 as it no longer includes support for Reanimated 1 legacy API. Remove the `useLegacyImplementation` prop from `Drawer.Navigator` to be able to use it.'); + } +- const Drawer = useLegacyImplementation ? require('./legacy/Drawer').default : require('./modern/Drawer').default; + const focusedRouteKey = state.routes[state.index].key; + const { + drawerHideStatusBarOnOpen = false, diff --git a/lib/module/views/modern/Drawer.js b/lib/module/views/modern/Drawer.js -index 3aa1baa2efd65bab22da56416c90e3a294dab266..8737778293408588026d6efab2c9070ed1def4f4 100644 +index 3aa1baa2efd65bab22da56416c90e3a294dab266..9c02ff62e84496e62e6c1843cd1786b37b9207a8 100644 --- a/lib/module/views/modern/Drawer.js +++ b/lib/module/views/modern/Drawer.js @@ -222,7 +222,7 @@ export default function Drawer(_ref) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac418d3e0c..bc0eb56761 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,7 +25,7 @@ patchedDependencies: hash: zkdmh374s554i7qlaqtqn2nhfm path: patches/@likashefqet__react-native-image-zoom@3.0.0.patch '@react-navigation/drawer@6.7.2': - hash: uvadz7wecy3yfbv66nyfswys5y + hash: rib4hjvzksqzwv3bbw4vfi5a5i path: patches/@react-navigation__drawer@6.7.2.patch '@tiptap/react@2.0.3': hash: tt2duu22fpwhmhaws3iaoig4mu @@ -149,7 +149,7 @@ importers: version: 6.5.12(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.7.2 - version: 6.7.2(patch_hash=uvadz7wecy3yfbv66nyfswys5y)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 6.7.2(patch_hash=rib4hjvzksqzwv3bbw4vfi5a5i)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': specifier: ^6.1.7 version: 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -1027,7 +1027,7 @@ importers: version: 1.0.0(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.7.2 - version: 6.7.2(patch_hash=uvadz7wecy3yfbv66nyfswys5y)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + version: 6.7.2(patch_hash=rib4hjvzksqzwv3bbw4vfi5a5i)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': specifier: ^6.1.7 version: 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -18766,7 +18766,7 @@ snapshots: react: 18.2.0 stacktrace-parser: 0.1.10 - ? '@react-navigation/drawer@6.7.2(patch_hash=uvadz7wecy3yfbv66nyfswys5y)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)' + ? '@react-navigation/drawer@6.7.2(patch_hash=rib4hjvzksqzwv3bbw4vfi5a5i)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)' : dependencies: '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': 6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) From 0136c6163cbc9dcabce028a3aeb545e359f251a2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 31 Oct 2024 14:41:06 +0000 Subject: [PATCH 246/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 3df0ac422d..ac9f12aa91 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v5.db799.j0451.ljtdp.r62n9.infqs.glob' 0v5.db799.j0451.ljtdp.r62n9.infqs] + glob-http+['https://bootstrap.urbit.org/glob-0v6.t86nd.7ra0p.g36f2.4thum.v62cp.glob' 0v6.t86nd.7ra0p.g36f2.4thum.v62cp] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From c7e3affc8e8e17eb980ea3a5a4331f995cfdeff1 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 31 Oct 2024 11:45:01 -0400 Subject: [PATCH 247/259] BareChatInput: handle blur, don't blur on send --- packages/ui/src/components/BareChatInput/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index dfd74e6008..946937be69 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -333,7 +333,6 @@ export default function BareChatInput({ ); const handleSend = useCallback(async () => { - Keyboard.dismiss(); runSendMessage(false); }, [runSendMessage]); @@ -512,6 +511,10 @@ export default function BareChatInput({ } }; + const handleBlur = useCallback(() => { + setShouldBlur(true); + }, [setShouldBlur]); + return ( Date: Thu, 31 Oct 2024 12:55:27 -0500 Subject: [PATCH 248/259] desktop: make action sheet adaptive, display a modal on desktop --- .../desktop/ChatListDrawerContent.tsx | 26 +++---- packages/ui/src/components/ActionSheet.tsx | 75 ++++++++++++++++++- .../ui/src/components/ChatOptionsSheet.tsx | 61 ++++++++------- packages/ui/src/tamagui.config.ts | 6 ++ 4 files changed, 124 insertions(+), 44 deletions(-) diff --git a/packages/app/navigation/desktop/ChatListDrawerContent.tsx b/packages/app/navigation/desktop/ChatListDrawerContent.tsx index f2dfeb9961..9794cf82a8 100644 --- a/packages/app/navigation/desktop/ChatListDrawerContent.tsx +++ b/packages/app/navigation/desktop/ChatListDrawerContent.tsx @@ -46,9 +46,9 @@ export const ChatListDrawerContent = (props: DrawerContentProps) => { 'all' ); const [showSearchInput, setShowSearchInput] = useState(false); - const [longPressedChat, setLongPressedChat] = useState< - db.Channel | db.Group | null - >(null); + const [pressedChat, setPressedChat] = useState( + null + ); const chatOptionsSheetRef = useRef(null); const [screenTitle, setScreenTitle] = useState('Home'); const [addGroupOpen, setAddGroupOpen] = useState(false); @@ -56,24 +56,22 @@ export const ChatListDrawerContent = (props: DrawerContentProps) => { const [searchQuery, setSearchQuery] = useState(''); const chatOptionsGroupId = useMemo(() => { - if (!longPressedChat) { + if (!pressedChat) { return; } - return logic.isGroup(longPressedChat) - ? longPressedChat.id - : longPressedChat.group?.id; - }, [longPressedChat]); + return logic.isGroup(pressedChat) ? pressedChat.id : pressedChat.group?.id; + }, [pressedChat]); const chatOptionsChannelId = useMemo(() => { - if (!longPressedChat || logic.isGroup(longPressedChat)) { + if (!pressedChat || logic.isGroup(pressedChat)) { return; } - return longPressedChat.id; - }, [longPressedChat]); + return pressedChat.id; + }, [pressedChat]); - const onLongPressChat = useCallback((item: db.Channel | db.Group) => { + const onPressMenuButton = useCallback((item: db.Channel | db.Group) => { if (logic.isChannel(item) && !item.isDmInvite) { - setLongPressedChat(item); + setPressedChat(item); if (item.pin?.type === 'channel' || !item.group) { chatOptionsSheetRef.current?.open(item.id, item.type); } else { @@ -204,7 +202,7 @@ export const ChatListDrawerContent = (props: DrawerContentProps) => { showSearchInput={showSearchInput} onSearchToggle={handleSearchInputToggled} onSectionChange={handleSectionChange} - onPressMenuButton={onLongPressChat} + onPressMenuButton={onPressMenuButton} searchQuery={searchQuery} onSearchQueryChange={setSearchQuery} /> diff --git a/packages/ui/src/components/ActionSheet.tsx b/packages/ui/src/components/ActionSheet.tsx index 4973c95315..33395b60d0 100644 --- a/packages/ui/src/components/ActionSheet.tsx +++ b/packages/ui/src/components/ActionSheet.tsx @@ -11,8 +11,10 @@ import { import { Modal } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { + Dialog, SheetProps, View, + VisuallyHidden, YStack, createStyledContext, getTokenValue, @@ -21,6 +23,7 @@ import { } from 'tamagui'; import { useCopy } from '../hooks/useCopy'; +import useIsWindowNarrow from '../hooks/useIsWindowNarrow'; import { Icon, IconType } from './Icon'; import { ListItem } from './ListItem'; import { Sheet } from './Sheet'; @@ -72,6 +75,12 @@ export function createActionGroup( type ActionSheetProps = { open: boolean; onOpenChange: (open: boolean) => void; + title?: string; +}; + +const useAdaptiveMode = () => { + const isWindowNarrow = useIsWindowNarrow(); + return isWindowNarrow ? 'sheet' : 'dialog'; }; // Main component @@ -79,9 +88,11 @@ type ActionSheetProps = { const ActionSheetComponent = ({ open, onOpenChange, + title, children, ...props }: PropsWithChildren) => { + const mode = useAdaptiveMode(); const hasOpened = useRef(open); if (!hasOpened.current && open) { hasOpened.current = true; @@ -90,6 +101,44 @@ const ActionSheetComponent = ({ // Sheets are heavy; we don't want to render until we need to if (!hasOpened.current) return null; + if (mode === 'dialog') { + return ( + + + + {title} + + + + {children} + + + + {/* Should not be necessary, but just in case */} + + + + + + + + + + + + ); + } + return ( - {/* + {/* press style is set here to ensure touch responders are added and drag gestures bubble up accordingly (unclear why needed after adding modal wrapper) */} @@ -181,6 +230,9 @@ const useContentStyle = () => { const ActionSheetContentBlock = styled(View, { name: 'ActionSheetContentBlock', padding: '$xl', + $gtSm: { + padding: '$l', + }, variants: { form: { true: { paddingHorizontal: '$2xl' }, @@ -291,6 +343,11 @@ const ActionSheetActionFrame = styled(ListItem, { context: ActionSheetActionGroupContext, borderRadius: 0, paddingHorizontal: '$2xl', + paddingVertical: '$l', + $gtSm: { + paddingHorizontal: '$l', + paddingVertical: '$m', + }, pressStyle: { backgroundColor: '$secondaryBackground', }, @@ -334,6 +391,10 @@ const ActionSheetActionTitle = styled(ListItem.Title, { const ActionSheetActionDescription = styled(ListItem.Subtitle, { context: ActionSheetActionGroupContext, + maxWidth: '100%', + $gtSm: { + maxWidth: 200, + }, variants: { accent: { positive: { @@ -347,6 +408,13 @@ const ActionSheetActionDescription = styled(ListItem.Subtitle, { } as const, }); +const ActionSheetMainContent = styled(YStack, { + name: 'ActionSheetMainContent', + flex: 1, + justifyContent: 'space-evenly', + height: '$4xl', +}); + function ActionSheetAction({ action }: { action: Action }) { const accent = useContext(ActionSheetActionGroupContext).accent; return action.render ? ( @@ -358,7 +426,7 @@ function ActionSheetAction({ action }: { action: Action }) { > {action.startIcon && resolveIcon(action.startIcon, action.accent ?? accent)} - + {action.title} @@ -367,7 +435,7 @@ function ActionSheetAction({ action }: { action: Action }) { {action.description} )} - + {action.endIcon && ( {resolveIcon(action.endIcon, action.accent ?? accent)} @@ -506,6 +574,7 @@ export const ActionSheet = withStaticProperties(ActionSheetComponent, { FormBlock: ActionSheetFormBlock, ActionGroup: ActionSheetActionGroup, Action: ActionSheetAction, + MainContent: ActionSheetMainContent, ActionFrame: ActionSheetActionFrame, ActionGroupContent: ActionSheetActionGroupContent, ActionGroupFrame: ActionSheetActionGroupFrame, diff --git a/packages/ui/src/components/ChatOptionsSheet.tsx b/packages/ui/src/components/ChatOptionsSheet.tsx index 41f51cec21..d47839151c 100644 --- a/packages/ui/src/components/ChatOptionsSheet.tsx +++ b/packages/ui/src/components/ChatOptionsSheet.tsx @@ -9,11 +9,9 @@ import React, { useEffect, useImperativeHandle, useMemo, - useRef, useState, } from 'react'; import { Alert } from 'react-native'; -import { useSheet } from 'tamagui'; import { ChevronLeft } from '../assets/icons'; import { useChatOptions, useCurrentUserId } from '../contexts'; @@ -113,6 +111,7 @@ export function GroupOptionsSheetLoader({ pane={pane} setPane={setPane} setSortBy={setSortBy} + onOpenChange={onOpenChange} /> ) : null; @@ -123,17 +122,16 @@ export function GroupOptions({ pane, setPane, setSortBy, + onOpenChange, }: { group: db.Group; pane: 'initial' | 'edit' | 'notifications' | 'sort'; setPane: (pane: 'initial' | 'edit' | 'notifications' | 'sort') => void; setSortBy?: (sortBy: db.ChannelSortPreference) => void; + onOpenChange: (open: boolean) => void; }) { const currentUser = useCurrentUserId(); const { data: currentVolumeLevel } = store.useGroupVolumeLevel(group.id); - const sheet = useSheet(); - const sheetRef = useRef(sheet); - sheetRef.current = sheet; const { onPressGroupMembers, @@ -214,7 +212,7 @@ export function GroupOptions({ title: 'Edit group info', description: 'Change name, description, and image', action: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressGroupMeta?.(group.id); }, endIcon: 'ChevronRight', @@ -224,7 +222,7 @@ export function GroupOptions({ title: 'Manage channels', description: 'Add or remove channels in this group', action: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressManageChannels?.(group.id); }, endIcon: 'ChevronRight', @@ -234,7 +232,7 @@ export function GroupOptions({ title: 'Privacy', description: 'Change who can find or join this group', action: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressGroupPrivacy?.(group.id); }, endIcon: 'ChevronRight', @@ -246,7 +244,13 @@ export function GroupOptions({ }, ]; return actionEdit; - }, [group.id, onPressGroupMeta, onPressGroupPrivacy, onPressManageChannels]); + }, [ + group.id, + onPressGroupMeta, + onPressGroupPrivacy, + onPressManageChannels, + onOpenChange, + ]); const actionGroups = useMemo(() => { const groupRef = logic.getGroupReferencePath(group.id); @@ -301,14 +305,14 @@ export function GroupOptions({ endIcon: 'ChevronRight', action: () => { onPressGroupMembers?.(group.id); - sheetRef.current.setOpen(false); + onOpenChange(false); }, }; const inviteAction: Action = { title: 'Invite people', action: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressInvite?.(group); }, endIcon: 'ChevronRight', @@ -350,7 +354,7 @@ export function GroupOptions({ title: 'Leave group', endIcon: 'LogOut', action: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressLeave?.(); }, }, @@ -367,6 +371,7 @@ export function GroupOptions({ onPressGroupMembers, onPressInvite, onPressLeave, + onOpenChange, ]); const actionSort: ActionGroup[] = useMemo(() => { @@ -379,7 +384,7 @@ export function GroupOptions({ action: () => { onSelectSort?.('recency'); setSortBy?.('recency'); - sheetRef.current.setOpen(false); + onOpenChange(false); }, }, { @@ -387,13 +392,13 @@ export function GroupOptions({ action: () => { onSelectSort?.('arranged'); setSortBy?.('arranged'); - sheetRef.current.setOpen(false); + onOpenChange(false); }, }, ], }, ]; - }, [onSelectSort, setSortBy]); + }, [onSelectSort, setSortBy, onOpenChange]); const memberCount = group?.members?.length ? group.members.length.toLocaleString() @@ -483,6 +488,7 @@ export function ChannelOptionsSheetLoader({ channel={channelQuery.data} pane={pane} setPane={setPane} + onOpenChange={onOpenChange} /> ) : null; @@ -492,20 +498,18 @@ export function ChannelOptions({ channel, pane, setPane, + onOpenChange, }: { channel: db.Channel; pane: 'initial' | 'notifications'; setPane: (pane: 'initial' | 'notifications') => void; + onOpenChange: (open: boolean) => void; }) { const { data: group } = store.useGroup({ id: channel?.groupId ?? undefined, }); const { data: currentVolumeLevel } = store.useChannelVolumeLevel(channel.id); const currentUser = useCurrentUserId(); - const sheet = useSheet(); - const sheetRef = useRef(sheet); - sheetRef.current = sheet; - const { onPressChannelMembers, onPressChannelMeta, @@ -637,7 +641,7 @@ export function ChannelOptions({ return; } onPressChannelMeta?.(channel.id); - sheetRef.current.setOpen(false); + onOpenChange(false); }, }, ], @@ -657,7 +661,7 @@ export function ChannelOptions({ return; } onPressChannelMembers?.(channel.id); - sheetRef.current.setOpen(false); + onOpenChange(false); }, }, ], @@ -677,7 +681,7 @@ export function ChannelOptions({ return; } onPressManageChannels?.(group.id); - sheetRef.current.setOpen(false); + onOpenChange(false); }, }, ], @@ -697,7 +701,7 @@ export function ChannelOptions({ { title: 'Invite people', action: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressInvite?.(group); }, endIcon: 'ChevronRight', @@ -747,7 +751,7 @@ export function ChannelOptions({ text: 'Leave', style: 'destructive', onPress: () => { - sheetRef.current.setOpen(false); + onOpenChange(false); onPressLeave?.(); if ( channel.type === 'dm' || @@ -783,6 +787,7 @@ export function ChannelOptions({ onPressInvite, onPressLeave, title, + onOpenChange, ]); const displayTitle = useMemo((): string => { @@ -831,10 +836,12 @@ function ChatOptionsSheetContent({ <> {icon} - + {title} - {subtitle} - + + {subtitle} + + diff --git a/packages/ui/src/tamagui.config.ts b/packages/ui/src/tamagui.config.ts index f1a8c78f41..56aec046e1 100644 --- a/packages/ui/src/tamagui.config.ts +++ b/packages/ui/src/tamagui.config.ts @@ -329,10 +329,16 @@ export const fonts = { // === }; +export const media = { + sm: { maxWidth: 768 }, + gtSm: { minWidth: 768 + 1 }, +}; + export const config = createTamagui({ tokens, fonts, themes, + media, settings: { allowedStyleValues: { space: 'somewhat-strict', From 6fa63ef87e4ffcbecd950d1b33c7760014de7395 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 31 Oct 2024 15:34:52 -0400 Subject: [PATCH 249/259] BareChatInput: refactor multiline handling and improve mention rendering --- .../ui/src/components/BareChatInput/index.tsx | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 946937be69..7260bed2e4 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -18,10 +18,9 @@ import { pathToCite, } from '@tloncorp/shared/urbit'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { Keyboard, TextInput } from 'react-native'; +import { Keyboard, TextInput, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { - View, YStack, getFontSize, getVariableValue, @@ -102,6 +101,7 @@ export default function BareChatInput({ showMentionPopup, } = useMentions(); const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); + const inputContainerRef = useRef(null); const inputRef = useRef(null); const processReferences = useCallback( @@ -168,7 +168,7 @@ export default function BareChatInput({ const renderTextWithMentions = useMemo(() => { if (!text || mentions.length === 0) { - return null; + return {text}; } const sortedMentions = [...mentions].sort((a, b) => a.start - b.start); @@ -177,7 +177,7 @@ export default function BareChatInput({ // Handle text before first mention if (sortedMentions[0].start > 0) { textParts.push( - + {text.slice(0, sortedMentions[0].start)} ); @@ -199,7 +199,7 @@ export default function BareChatInput({ const nextStart = sortedMentions[index + 1]?.start ?? text.length; if (mention.end < nextStart) { textParts.push( - + {text.slice(mention.end, nextStart)} ); @@ -515,6 +515,17 @@ export default function BareChatInput({ setShouldBlur(true); }, [setShouldBlur]); + const [isMultiline, setIsMultiline] = useState(false); + + const handleContentSizeChange = useCallback(() => { + if (inputContainerRef.current?.measure) { + inputContainerRef.current.measure((x, y, width, height) => { + // Tell the component the user has entered enough text to exceed the initial height of the input + setIsMultiline(height > initialHeight); + }); + } + }, [initialHeight]); + return ( {showInlineAttachments && } - - {mentions.length > 0 && ( - - - {renderTextWithMentions} - - - )} + + + {renderTextWithMentions} + + ); From 019d50f9ef433a6d9eec02e9de4be6901209f858 Mon Sep 17 00:00:00 2001 From: James Acklin Date: Thu, 31 Oct 2024 15:37:09 -0400 Subject: [PATCH 250/259] BareChatInput: final touches --- packages/ui/src/components/BareChatInput/index.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/components/BareChatInput/index.tsx b/packages/ui/src/components/BareChatInput/index.tsx index 7260bed2e4..0d85b1808a 100644 --- a/packages/ui/src/components/BareChatInput/index.tsx +++ b/packages/ui/src/components/BareChatInput/index.tsx @@ -101,6 +101,7 @@ export default function BareChatInput({ showMentionPopup, } = useMentions(); const [maxInputHeight, setMaxInputHeight] = useState(maxInputHeightBasic); + const [isMultiline, setIsMultiline] = useState(false); const inputContainerRef = useRef(null); const inputRef = useRef(null); @@ -503,9 +504,8 @@ export default function BareChatInput({ const el = e?.target; if (el && 'style' in el && 'height' in el.style) { - el.style.height = `${initialHeight}px`; - const scrollHeight = el.scrollHeight; - const newHeight = Math.max(initialHeight, scrollHeight); + el.style.height = 0; + const newHeight = el.offsetHeight - el.clientHeight + el.scrollHeight; el.style.height = `${newHeight}px`; setInputHeight(newHeight); } @@ -515,8 +515,6 @@ export default function BareChatInput({ setShouldBlur(true); }, [setShouldBlur]); - const [isMultiline, setIsMultiline] = useState(false); - const handleContentSizeChange = useCallback(() => { if (inputContainerRef.current?.measure) { inputContainerRef.current.measure((x, y, width, height) => { From 42532d884378f9261c97f4e2d7b04921708667be Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 31 Oct 2024 15:03:03 -0500 Subject: [PATCH 251/259] desktop: show updated button for service worker in nav --- apps/tlon-web-new/src/app.tsx | 24 +++++++---------- .../app/navigation/desktop/TopLevelDrawer.tsx | 12 ++++++++- packages/app/provider/AppDataProvider.tsx | 11 +++++++- packages/ui/src/components/NavBar/NavIcon.tsx | 27 +++++++++++++------ packages/ui/src/contexts/appDataContext.tsx | 26 +++++++++++++++++- 5 files changed, 75 insertions(+), 25 deletions(-) diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index dedfcf349a..05e14068b3 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -18,13 +18,13 @@ import { sync } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/store'; import cookies from 'browser-cookies'; import { usePostHog } from 'posthog-js/react'; -import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react'; +import React, { PropsWithChildren, useEffect, useState } from 'react'; import { Helmet } from 'react-helmet'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import EyrieMenu from '@/eyrie/EyrieMenu'; import { ANALYTICS_DEFAULT_PROPERTIES } from '@/logic/analytics'; -import useAppUpdates, { AppUpdateContext } from '@/logic/useAppUpdates'; +import useAppUpdates from '@/logic/useAppUpdates'; import useErrorHandler from '@/logic/useErrorHandler'; import useIsStandaloneMode from '@/logic/useIsStandaloneMode'; import { useIsDark, useIsMobile } from '@/logic/useMedia'; @@ -68,6 +68,7 @@ function AppRoutes({ isLoaded }: { isLoaded: boolean }) { const contactsQuery = store.useContacts(); const currentUserId = useCurrentUserId(); const calmSettingsQuery = store.useCalmSettings({ userId: currentUserId }); + const { needsUpdate, triggerUpdate } = useAppUpdates(); useEffect(() => { const { data, refetch, isRefetching, isFetching } = contactsQuery; @@ -95,7 +96,10 @@ function AppRoutes({ isLoaded }: { isLoaded: boolean }) { } return ( - + ({ needsUpdate, triggerUpdate }), - [needsUpdate, triggerUpdate] - ); - const theme = useTheme(); const isDarkMode = useIsDark(); @@ -265,11 +263,9 @@ function RoutedApp() { Tlon - - - - - + + + {showDevTools && ( <> diff --git a/packages/app/navigation/desktop/TopLevelDrawer.tsx b/packages/app/navigation/desktop/TopLevelDrawer.tsx index 2aef7727ba..6821df04e2 100644 --- a/packages/app/navigation/desktop/TopLevelDrawer.tsx +++ b/packages/app/navigation/desktop/TopLevelDrawer.tsx @@ -3,7 +3,7 @@ import { createDrawerNavigator, } from '@react-navigation/drawer'; import * as store from '@tloncorp/shared/store'; -import { AvatarNavIcon, NavIcon, YStack } from '@tloncorp/ui'; +import { AvatarNavIcon, NavIcon, YStack, useWebAppUpdate } from '@tloncorp/ui'; import ProfileScreen from '../../features/settings/ProfileScreen'; import { ActivityScreen } from '../../features/top/ActivityScreen'; @@ -16,6 +16,7 @@ const Drawer = createDrawerNavigator(); const DrawerContent = (props: DrawerContentComponentProps) => { const userId = useCurrentUserId(); const haveUnreadUnseenActivity = store.useHaveUnreadUnseenActivity(); + const { webAppNeedsUpdate, triggerWebAppUpdate } = useWebAppUpdate(); const isRouteActive = (routeName: string) => { return ( props.state.index === @@ -46,6 +47,15 @@ const DrawerContent = (props: DrawerContentComponentProps) => { focused={isRouteActive('Profile')} onPress={() => props.navigation.navigate('Profile')} /> + {webAppNeedsUpdate && ( + + )} ); }; diff --git a/packages/app/provider/AppDataProvider.tsx b/packages/app/provider/AppDataProvider.tsx index e51b7c79c5..06df37d459 100644 --- a/packages/app/provider/AppDataProvider.tsx +++ b/packages/app/provider/AppDataProvider.tsx @@ -5,7 +5,14 @@ import { PropsWithChildren } from 'react'; import { BRANCH_DOMAIN, BRANCH_KEY } from '../constants'; import { useCurrentUserId } from '../hooks/useCurrentUser'; -export function AppDataProvider({ children }: PropsWithChildren) { +export function AppDataProvider({ + webAppNeedsUpdate, + triggerWebAppUpdate, + children, +}: PropsWithChildren<{ + webAppNeedsUpdate?: boolean; + triggerWebAppUpdate?: (returnToRoot?: boolean) => Promise; +}>) { const currentUserId = useCurrentUserId(); const session = store.useCurrentSession(); const contactsQuery = store.useContacts(); @@ -18,6 +25,8 @@ export function AppDataProvider({ children }: PropsWithChildren) { branchDomain={BRANCH_DOMAIN} calmSettings={calmSettingsQuery.data} session={session} + webAppNeedsUpdate={webAppNeedsUpdate} + triggerWebAppUpdate={triggerWebAppUpdate} > {children} diff --git a/packages/ui/src/components/NavBar/NavIcon.tsx b/packages/ui/src/components/NavBar/NavIcon.tsx index 5d4a8f74c1..9663d0f4e6 100644 --- a/packages/ui/src/components/NavBar/NavIcon.tsx +++ b/packages/ui/src/components/NavBar/NavIcon.tsx @@ -1,4 +1,4 @@ -import { Circle } from 'tamagui'; +import { Circle, ColorTokens } from 'tamagui'; import { ContactAvatar } from '../Avatar'; import { Icon, IconType } from '../Icon'; @@ -33,26 +33,37 @@ export default function NavIcon({ isActive, hasUnreads = false, onPress, + backgroundColor, + shouldShowUnreads = true, }: { type: IconType; activeType?: IconType; isActive: boolean; hasUnreads?: boolean; onPress?: () => void; + backgroundColor?: ColorTokens; + shouldShowUnreads?: boolean; }) { const resolvedType = isActive && activeType ? activeType : type; return ( - + - - - + {shouldShowUnreads ? ( + + + + ) : null} ); } diff --git a/packages/ui/src/contexts/appDataContext.tsx b/packages/ui/src/contexts/appDataContext.tsx index 3c3bac1291..9bdf668483 100644 --- a/packages/ui/src/contexts/appDataContext.tsx +++ b/packages/ui/src/contexts/appDataContext.tsx @@ -16,6 +16,8 @@ export type CurrentAppDataState = { branchKey: string; session: Session | null; calmSettings: CalmState; + webAppNeedsUpdate?: boolean; + triggerWebAppUpdate?: (returnToRoot?: boolean) => Promise; }; type ContextValue = CurrentAppDataState; @@ -30,6 +32,8 @@ export const AppDataContextProvider = ({ branchKey, calmSettings, session, + webAppNeedsUpdate, + triggerWebAppUpdate, }: PropsWithChildren>) => { const value = useMemo( () => ({ @@ -44,8 +48,19 @@ export const AppDataContextProvider = ({ disableNicknames: false, }, session: session ?? null, + webAppNeedsUpdate, + triggerWebAppUpdate, }), - [currentUserId, contacts, branchDomain, branchKey, session, calmSettings] + [ + currentUserId, + contacts, + branchDomain, + branchKey, + session, + calmSettings, + webAppNeedsUpdate, + triggerWebAppUpdate, + ] ); return {children}; }; @@ -85,6 +100,15 @@ export const useCalm = () => { return context.calmSettings; }; +export const useWebAppUpdate = () => { + const context = useAppDataContext(); + + return { + webAppNeedsUpdate: context.webAppNeedsUpdate, + triggerWebAppUpdate: context.triggerWebAppUpdate, + }; +}; + const useAppDataContext = (): CurrentAppDataState => { const context = useContext(Context); From 6053bc2507de75d5513571eef4e72f0cc979de12 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 31 Oct 2024 15:06:17 -0500 Subject: [PATCH 252/259] remove radix deps --- apps/tlon-web-new/package.json | 11 ----------- apps/tlon-web-new/src/app.tsx | 5 +---- apps/tlon-web-new/vite.config.mts | 5 ----- 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/apps/tlon-web-new/package.json b/apps/tlon-web-new/package.json index c8bebed89a..42ae74ed6e 100644 --- a/apps/tlon-web-new/package.json +++ b/apps/tlon-web-new/package.json @@ -37,17 +37,6 @@ "@babel/runtime": "^7.25.9", "@emoji-mart/data": "^1.0.6", "@emoji-mart/react": "^1.0.1", - "@radix-ui/react-accordion": "^1.1.2", - "@radix-ui/react-collapsible": "^1.0.3", - "@radix-ui/react-dialog": "^1.0.4", - "@radix-ui/react-dropdown-menu": "^2.0.5", - "@radix-ui/react-popover": "^1.0.2", - "@radix-ui/react-radio-group": "^1.1.3", - "@radix-ui/react-tabs": "^1.0.4", - "@radix-ui/react-toast": "^1.0.0", - "@radix-ui/react-toggle": "^1.0.2", - "@radix-ui/react-toggle-group": "^1.0.4", - "@radix-ui/react-tooltip": "^1.0.0", "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.1.7", "@tamagui/vite-plugin": "~1.112.12", diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index 05e14068b3..857d6c74d6 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -1,5 +1,4 @@ // Copyright 2024, Tlon Corporation -import { TooltipProvider } from '@radix-ui/react-tooltip'; import { DarkTheme, DefaultTheme, @@ -263,9 +262,7 @@ function RoutedApp() { Tlon - - - + {showDevTools && ( <> diff --git a/apps/tlon-web-new/vite.config.mts b/apps/tlon-web-new/vite.config.mts index 4e9e046e7e..c27e4b3ce0 100644 --- a/apps/tlon-web-new/vite.config.mts +++ b/apps/tlon-web-new/vite.config.mts @@ -141,11 +141,6 @@ export default ({ mode }: { mode: string }) => { refractor: ['refractor'], 'urbit-ob': ['urbit-ob'], 'hast-to-hyperscript': ['hast-to-hyperscript'], - 'radix-ui/react-dialog': ['@radix-ui/react-dialog'], - 'radix-ui/react-dropdown-menu': ['@radix-ui/react-dropdown-menu'], - 'radix-ui/react-popover': ['@radix-ui/react-popover'], - 'radix-ui/react-toast': ['@radix-ui/react-toast'], - 'radix-ui/react-tooltip': ['@radix-ui/react-tooltip'], }, }, }; From 19580f17c3a86e65484874ec0a0517a39147e700 Mon Sep 17 00:00:00 2001 From: Patrick O'Sullivan Date: Thu, 31 Oct 2024 15:18:53 -0500 Subject: [PATCH 253/259] remove more old deps --- apps/tlon-web-new/package.json | 42 -------- apps/tlon-web-new/src/keyMap.ts | 50 --------- apps/tlon-web-new/vite.config.mts | 10 -- pnpm-lock.yaml | 172 ------------------------------ 4 files changed, 274 deletions(-) delete mode 100644 apps/tlon-web-new/src/keyMap.ts diff --git a/apps/tlon-web-new/package.json b/apps/tlon-web-new/package.json index 42ae74ed6e..e61753be31 100644 --- a/apps/tlon-web-new/package.json +++ b/apps/tlon-web-new/package.json @@ -35,15 +35,12 @@ "@aws-sdk/client-s3": "^3.190.0", "@aws-sdk/s3-request-presigner": "^3.190.0", "@babel/runtime": "^7.25.9", - "@emoji-mart/data": "^1.0.6", - "@emoji-mart/react": "^1.0.1", "@react-navigation/drawer": "^6.7.2", "@react-navigation/native": "^6.1.7", "@tamagui/vite-plugin": "~1.112.12", "@tanstack/react-query": "^4.28.0", "@tanstack/react-query-devtools": "^4.28.0", "@tanstack/react-query-persist-client": "^4.28.0", - "@tanstack/react-virtual": "^3.0.0-beta.60", "@tiptap/core": "^2.6.6", "@tiptap/extension-blockquote": "^2.6.6", "@tiptap/extension-bold": "^2.6.6", @@ -74,37 +71,18 @@ "@tloncorp/mock-http-api": "^1.2.0", "@tloncorp/shared": "workspace:*", "@tloncorp/ui": "workspace:*", - "@types/marked": "^4.3.0", "@urbit/api": "^2.2.0", "@urbit/aura": "^1.0.0", "@urbit/http-api": "3.2.0-dev", "@urbit/sigil-js": "^2.2.0", "any-ascii": "^0.3.1", "big-integer": "^1.6.51", - "browser-cookies": "^1.2.0", - "browser-image-compression": "^2.0.2", "classnames": "^2.3.1", - "clipboard-copy": "^4.0.1", - "color2k": "^2.0.0", "cross-fetch": "^3.1.5", - "date-fns": "^2.28.0", - "dompurify": "^3.0.6", - "emoji-mart": "^5.2.2", - "emoji-regex": "^10.2.1", - "fast-average-color": "^9.1.1", - "framer-motion": "^6.5.1", - "fuzzy": "^0.1.3", - "get-youtube-id": "^1.0.1", - "hast-to-hyperscript": "^10.0.1", - "history": "^5.3.0", "idb-keyval": "^6.2.0", "immer": "^9.0.12", "lodash": "^4.17.21", - "marked": "^4.3.0", - "masonic": "^3.6.5", - "moment": "^2.29.4", "posthog-js": "^1.68.2", - "prismjs": "^1.29.0", "prosemirror-commands": "~1.2.2", "prosemirror-history": "~1.2.0", "prosemirror-keymap": "~1.1.5", @@ -115,39 +93,19 @@ "prosemirror-transform": "~1.4.2", "prosemirror-view": "~1.23.13", "react": "^18.2.0", - "react-beautiful-dnd": "^13.1.1", - "react-colorful": "^5.5.1", - "react-dnd": "^15.1.1", - "react-dnd-html5-backend": "^15.1.2", - "react-dnd-touch-backend": "^15.1.1", "react-dom": "^18.2.0", "react-error-boundary": "^3.1.4", "react-helmet": "^6.1.0", - "react-hook-form": "^7.30.0", - "react-image-size": "^2.0.0", "react-intersection-observer": "^9.4.0", "react-native-safe-area-context": "^4.9.0", "react-native-screens": "~3.29.0", "react-native-web": "0.19.12", - "react-oembed-container": "github:stefkampen/react-oembed-container", - "react-qr-code": "^2.0.12", - "react-select": "^5.3.2", - "react-tweet": "^3.0.4", - "react-virtuoso": "^4.5.1", - "refractor": "^4.8.0", - "slugify": "^1.6.6", - "sorted-btree": "^1.8.1", "sqlocal": "^0.11.1", "tailwindcss-opentype": "^1.1.0", "tailwindcss-scoped-groups": "^2.0.0", - "tippy.js": "^6.3.7", "urbit-ob": "^5.0.1", "use-pwa-install": "^1.0.1", - "usehooks-ts": "^2.6.0", - "uuid": "^9.0.0", "validator": "^13.7.0", - "vaul": "github:latter-bolden/vaul", - "video-react": "^0.16.0", "vite-plugin-svgr": "^4.2.0", "workbox-precaching": "^6.5.4", "zustand": "^3.7.2" diff --git a/apps/tlon-web-new/src/keyMap.ts b/apps/tlon-web-new/src/keyMap.ts deleted file mode 100644 index dda098124c..0000000000 --- a/apps/tlon-web-new/src/keyMap.ts +++ /dev/null @@ -1,50 +0,0 @@ -export default { - leap: { - // not used programattically, but used in future for keyboard shortcuts modal - open: 'Cmd/Ctrl + k', - close: 'Escape', - nextResult: 'ArrowDown', - prevResult: 'ArrowUp', - selectResult: 'Enter', - }, - thread: { - close: 'Escape', - }, - mentionPopup: { - close: 'Escape', - nextItem: 'ArrowDown', - prevItem: 'ArrowUp', - selectItem: 'Enter', - }, - grid: { - close: 'Escape', - nextItem: 'ArrowRight', - prevItem: 'ArrowLeft', - nextItemAlt: 'l', - nextItemAlt2: 'Tab', - prevItemAlt: 'h', - nextRow: 'ArrowDown', - prevRow: 'ArrowUp', - nextRowAlt: 'j', - prevRowAlt: 'k', - open: 'Enter', - }, - curio: { - close: 'Escape', - next: 'ArrowRight', - prev: 'ArrowLeft', - }, - tippy: { - close: 'Escape', - nextItem: 'ArrowUp', - prevItem: 'ArrowDown', - selectItem: 'Enter', - }, - chatInputMenu: { - close: 'Escape', - nextItem: 'ArrowLeft', - prevItem: 'ArrowRight', - nextItemAlt: 'ArrowDown', - prevItemAlt: 'ArrowUp', - }, -}; diff --git a/apps/tlon-web-new/vite.config.mts b/apps/tlon-web-new/vite.config.mts index c27e4b3ce0..9234d9ad98 100644 --- a/apps/tlon-web-new/vite.config.mts +++ b/apps/tlon-web-new/vite.config.mts @@ -125,22 +125,12 @@ export default ({ mode }: { mode: string }) => { 'urbit/http-api': ['@urbit/http-api'], 'urbit/sigil-js': ['@urbit/sigil-js'], 'any-ascii': ['any-ascii'], - 'react-beautiful-dnd': ['react-beautiful-dnd'], - 'emoji-mart': ['emoji-mart'], 'tiptap/core': ['@tiptap/core'], 'tiptap/extension-placeholder': ['@tiptap/extension-placeholder'], 'tiptap/extension-link': ['@tiptap/extension-link'], - 'react-virtuoso': ['react-virtuoso'], - 'react-select': ['react-select'], - 'react-hook-form': ['react-hook-form'], - 'framer-motion': ['framer-motion'], - 'date-fns': ['date-fns'], - 'tippy.js': ['tippy.js'], 'aws-sdk/client-s3': ['@aws-sdk/client-s3'], 'aws-sdk/s3-request-presigner': ['@aws-sdk/s3-request-presigner'], - refractor: ['refractor'], 'urbit-ob': ['urbit-ob'], - 'hast-to-hyperscript': ['hast-to-hyperscript'], }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc0eb56761..713d4abe28 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -986,45 +986,6 @@ importers: '@babel/runtime': specifier: ^7.25.9 version: 7.25.9 - '@emoji-mart/data': - specifier: ^1.0.6 - version: 1.1.2 - '@emoji-mart/react': - specifier: ^1.0.1 - version: 1.0.1(emoji-mart@5.2.2)(react@18.2.0) - '@radix-ui/react-accordion': - specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-collapsible': - specifier: ^1.0.3 - version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-dialog': - specifier: ^1.0.4 - version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-dropdown-menu': - specifier: ^2.0.5 - version: 2.0.5(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-popover': - specifier: ^1.0.2 - version: 1.0.6(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-radio-group': - specifier: ^1.1.3 - version: 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-tabs': - specifier: ^1.0.4 - version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-toast': - specifier: ^1.0.0 - version: 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-toggle': - specifier: ^1.0.2 - version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-toggle-group': - specifier: ^1.0.4 - version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@radix-ui/react-tooltip': - specifier: ^1.0.0 - version: 1.0.0(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.7.2 version: 6.7.2(patch_hash=rib4hjvzksqzwv3bbw4vfi5a5i)(@react-navigation/native@6.1.10(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-gesture-handler@2.20.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-reanimated@3.8.1(patch_hash=n2blcrn244i77n7euhqt5mi2km)(@babel/core@7.25.2)(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.9.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.29.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -1043,9 +1004,6 @@ importers: '@tanstack/react-query-persist-client': specifier: ^4.28.0 version: 4.28.0(@tanstack/react-query@4.36.1(react-dom@18.2.0(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0)) - '@tanstack/react-virtual': - specifier: ^3.0.0-beta.60 - version: 3.0.0-beta.65(react@18.2.0) '@tiptap/core': specifier: ^2.6.6 version: 2.6.6(@tiptap/pm@2.6.6) @@ -1136,9 +1094,6 @@ importers: '@tloncorp/ui': specifier: workspace:* version: link:../../packages/ui - '@types/marked': - specifier: ^4.3.0 - version: 4.3.2 '@urbit/api': specifier: 2.2.0 version: 2.2.0 @@ -1157,54 +1112,12 @@ importers: big-integer: specifier: ^1.6.51 version: 1.6.52 - browser-cookies: - specifier: ^1.2.0 - version: 1.2.0 - browser-image-compression: - specifier: ^2.0.2 - version: 2.0.2 classnames: specifier: ^2.3.1 version: 2.5.1 - clipboard-copy: - specifier: ^4.0.1 - version: 4.0.1 - color2k: - specifier: ^2.0.0 - version: 2.0.3 cross-fetch: specifier: ^3.1.5 version: 3.1.5(encoding@0.1.13) - date-fns: - specifier: ^2.28.0 - version: 2.30.0 - dompurify: - specifier: ^3.0.6 - version: 3.0.6 - emoji-mart: - specifier: ^5.2.2 - version: 5.2.2 - emoji-regex: - specifier: ^10.2.1 - version: 10.3.0 - fast-average-color: - specifier: ^9.1.1 - version: 9.1.1 - framer-motion: - specifier: ^6.5.1 - version: 6.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - fuzzy: - specifier: ^0.1.3 - version: 0.1.3 - get-youtube-id: - specifier: ^1.0.1 - version: 1.0.1 - hast-to-hyperscript: - specifier: ^10.0.1 - version: 10.0.1 - history: - specifier: ^5.3.0 - version: 5.3.0 idb-keyval: specifier: ^6.2.0 version: 6.2.0 @@ -1214,21 +1127,9 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 - marked: - specifier: ^4.3.0 - version: 4.3.0 - masonic: - specifier: ^3.6.5 - version: 3.6.5(react@18.2.0) - moment: - specifier: ^2.29.4 - version: 2.29.4 posthog-js: specifier: ^1.68.2 version: 1.68.2 - prismjs: - specifier: ^1.29.0 - version: 1.29.0 prosemirror-commands: specifier: ~1.2.2 version: 1.2.2 @@ -1259,21 +1160,6 @@ importers: react: specifier: ^18.2.0 version: 18.2.0 - react-beautiful-dnd: - specifier: ^13.1.1 - version: 13.1.1(react-dom@18.2.0(react@18.2.0))(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-colorful: - specifier: ^5.5.1 - version: 5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-dnd: - specifier: ^15.1.1 - version: 15.1.2(@types/hoist-non-react-statics@3.3.1)(@types/node@20.14.10)(@types/react@18.2.55)(react@18.2.0) - react-dnd-html5-backend: - specifier: ^15.1.2 - version: 15.1.3 - react-dnd-touch-backend: - specifier: ^15.1.1 - version: 15.1.2 react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) @@ -1283,12 +1169,6 @@ importers: react-helmet: specifier: ^6.1.0 version: 6.1.0(react@18.2.0) - react-hook-form: - specifier: ^7.30.0 - version: 7.52.0(react@18.2.0) - react-image-size: - specifier: ^2.0.0 - version: 2.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-intersection-observer: specifier: ^9.4.0 version: 9.4.0(react@18.2.0) @@ -1301,30 +1181,6 @@ importers: react-native-web: specifier: 0.19.12 version: 0.19.12(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-oembed-container: - specifier: github:stefkampen/react-oembed-container - version: https://codeload.github.com/stefkampen/react-oembed-container/tar.gz/802eee0dba7986faa9c931b1c016acba5369d5f9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-qr-code: - specifier: ^2.0.12 - version: 2.0.12(react-native-svg@15.0.0(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react@18.2.0) - react-select: - specifier: ^5.3.2 - version: 5.4.0(@babel/core@7.25.2)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-tweet: - specifier: ^3.0.4 - version: 3.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-virtuoso: - specifier: ^4.5.1 - version: 4.6.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - refractor: - specifier: ^4.8.0 - version: 4.8.0 - slugify: - specifier: ^1.6.6 - version: 1.6.6 - sorted-btree: - specifier: ^1.8.1 - version: 1.8.1 sqlocal: specifier: ^0.11.1 version: 0.11.1(drizzle-orm@0.30.9(patch_hash=cegrec33e6f7d6ltk7vff5r7w4)(@op-engineering/op-sqlite@5.0.5(react-native@0.73.9(@babel/core@7.25.2)(@babel/preset-env@7.23.7(@babel/core@7.25.2))(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(@opentelemetry/api@1.8.0)(@types/better-sqlite3@7.6.9)(@types/react@18.2.55)(better-sqlite3@9.4.5)(react@18.2.0)) @@ -1334,30 +1190,15 @@ importers: tailwindcss-scoped-groups: specifier: ^2.0.0 version: 2.0.0(tailwindcss@3.4.1) - tippy.js: - specifier: ^6.3.7 - version: 6.3.7 urbit-ob: specifier: ^5.0.1 version: 5.0.1 use-pwa-install: specifier: ^1.0.1 version: 1.0.1(react@18.2.0) - usehooks-ts: - specifier: ^2.6.0 - version: 2.6.0(patch_hash=zfxlgoj5v64fvvaz7tv5fo5k2e)(react@18.2.0) - uuid: - specifier: ^9.0.0 - version: 9.0.0 validator: specifier: ^13.7.0 version: 13.7.0 - vaul: - specifier: github:latter-bolden/vaul - version: https://codeload.github.com/latter-bolden/vaul/tar.gz/9b06080c3f70c9ac6cf55d4d3306dc0baecc3213(@types/react-dom@18.2.18)(@types/react@18.2.55)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - video-react: - specifier: ^0.16.0 - version: 0.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) vite-plugin-svgr: specifier: ^4.2.0 version: 4.2.0(rollup@4.13.0)(typescript@5.4.5)(vite@5.1.6(@types/node@20.14.10)(lightningcss@1.19.0)(terser@5.19.1)) @@ -26882,19 +26723,6 @@ snapshots: '@types/node': 20.10.8 '@types/react': 18.2.55 - react-dnd@15.1.2(@types/hoist-non-react-statics@3.3.1)(@types/node@20.14.10)(@types/react@18.2.55)(react@18.2.0): - dependencies: - '@react-dnd/invariant': 3.0.1 - '@react-dnd/shallowequal': 3.0.1 - dnd-core: 15.1.2 - fast-deep-equal: 3.1.3 - hoist-non-react-statics: 3.3.2 - react: 18.2.0 - optionalDependencies: - '@types/hoist-non-react-statics': 3.3.1 - '@types/node': 20.14.10 - '@types/react': 18.2.55 - react-dom@18.2.0(react@18.2.0): dependencies: loose-envify: 1.4.0 From 6df53720b7cecdcd555130b66b4bc40a25fb6a44 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Nov 2024 13:35:46 +0000 Subject: [PATCH 254/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index ac9f12aa91..b785d5fe1b 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v6.t86nd.7ra0p.g36f2.4thum.v62cp.glob' 0v6.t86nd.7ra0p.g36f2.4thum.v62cp] + glob-http+['https://bootstrap.urbit.org/glob-0v7.of03m.88c84.6mb4f.j97e0.h29g4.glob' 0v7.of03m.88c84.6mb4f.j97e0.h29g4] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From 51ddb894f543eb6232e37a1de10741de10558d62 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Nov 2024 13:36:33 +0000 Subject: [PATCH 255/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index b785d5fe1b..3dc86cdfd1 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v7.of03m.88c84.6mb4f.j97e0.h29g4.glob' 0v7.of03m.88c84.6mb4f.j97e0.h29g4] + glob-http+['https://bootstrap.urbit.org/glob-0v3.eiis1.nh7vn.vtm1f.cls0q.mnr1u.glob' 0v3.eiis1.nh7vn.vtm1f.cls0q.mnr1u] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From 75a88720c62d4d2d94f6b56f0a9b44767b811b3f Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Nov 2024 14:15:52 +0000 Subject: [PATCH 256/259] update new frontend glob: [skip actions] --- tm-alpha-desk/desk.docket-0 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm-alpha-desk/desk.docket-0 b/tm-alpha-desk/desk.docket-0 index 3dc86cdfd1..a7609abe1e 100644 --- a/tm-alpha-desk/desk.docket-0 +++ b/tm-alpha-desk/desk.docket-0 @@ -2,7 +2,7 @@ info+'Start, host, and cultivate communities. Own your communications, organize your resources, and share documents. Tlon is a decentralized platform that offers a full, communal suite of tools for messaging, writing and sharing media with others.' color+0xde.dede image+'https://bootstrap.urbit.org/tlon.svg?v=1' - glob-http+['https://bootstrap.urbit.org/glob-0v3.eiis1.nh7vn.vtm1f.cls0q.mnr1u.glob' 0v3.eiis1.nh7vn.vtm1f.cls0q.mnr1u] + glob-http+['https://bootstrap.urbit.org/glob-0vo8ke1.a0vlm.b8nhv.nv6ka.08vb3.glob' 0vo8ke1.a0vlm.b8nhv.nv6ka.08vb3] base+'tm-alpha' version+[1 0 0] website+'https://tlon.io' From b50dfb487555b76c82616fc33cd1328bf146cb7c Mon Sep 17 00:00:00 2001 From: Dan Brewster Date: Fri, 1 Nov 2024 11:21:28 -0400 Subject: [PATCH 257/259] web routing / paths (#4137) * deduplicate navigation types * rough web routing * configure basepath base on mode * remove unused files * fix type error * fix post navigation * fix navigating out of profiles --- .../src/hooks/useDeepLinkListener.ts | 5 +- .../src/hooks/useNotificationListener.ts | 21 +- apps/tlon-mobile/src/navigation.d.ts | 2 +- apps/tlon-mobile/src/types.ts | 97 -------- apps/tlon-web-new/src/app.tsx | 35 ++- apps/tlon-web-new/src/main.tsx | 37 +-- packages/app/features/top/ActivityScreen.tsx | 11 +- packages/app/features/top/ChannelScreen.tsx | 48 ++-- .../app/features/top/ChannelSearchScreen.tsx | 23 +- packages/app/features/top/ChatListScreen.tsx | 60 +++-- .../app/features/top/GroupChannelsScreen.tsx | 24 +- .../app/features/top/ImageViewerScreen.tsx | 2 - packages/app/features/top/PostScreen.tsx | 24 +- packages/app/hooks/useChannelNavigation.ts | 33 ++- packages/app/navigation/BasePathNavigator.tsx | 38 +++ packages/app/navigation/RootStack.tsx | 10 +- packages/app/navigation/SettingsStack.tsx | 25 -- .../desktop/ChannelListDrawerContent.tsx | 66 ----- .../desktop/ChatListDrawerContent.tsx | 234 ------------------ .../app/navigation/desktop/HomeNavigator.tsx | 150 ++++++----- .../app/navigation/desktop/TopLevelDrawer.tsx | 4 +- packages/app/navigation/linking.ts | 145 +++++++++++ packages/app/navigation/types.ts | 99 +++----- packages/shared/src/api/channelsApi.ts | 22 +- packages/shared/src/store/useChannelSearch.ts | 10 +- .../src/components/Channel/ChannelHeader.tsx | 5 +- packages/ui/src/components/Channel/index.tsx | 5 +- .../src/components/ImageViewerScreenView.tsx | 2 - 28 files changed, 523 insertions(+), 714 deletions(-) create mode 100644 packages/app/navigation/BasePathNavigator.tsx delete mode 100644 packages/app/navigation/SettingsStack.tsx delete mode 100644 packages/app/navigation/desktop/ChannelListDrawerContent.tsx delete mode 100644 packages/app/navigation/desktop/ChatListDrawerContent.tsx create mode 100644 packages/app/navigation/linking.ts diff --git a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts index 24e5c715b5..3394455cb6 100644 --- a/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts +++ b/apps/tlon-mobile/src/hooks/useDeepLinkListener.ts @@ -1,14 +1,11 @@ import { NavigationProp, useNavigation } from '@react-navigation/native'; import { useBranch, useSignupParams } from '@tloncorp/app/contexts/branch'; import { useShip } from '@tloncorp/app/contexts/ship'; -import { inviteShipWithLure } from '@tloncorp/app/lib/hostingApi'; -import { trackError } from '@tloncorp/app/utils/posthog'; +import { RootStackParamList } from '@tloncorp/app/navigation/types'; import { createDevLogger } from '@tloncorp/shared'; import * as store from '@tloncorp/shared/store'; import { useEffect, useRef } from 'react'; -import { RootStackParamList } from '../types'; - const logger = createDevLogger('deeplinkHandler', true); export const useDeepLinkListener = () => { diff --git a/apps/tlon-mobile/src/hooks/useNotificationListener.ts b/apps/tlon-mobile/src/hooks/useNotificationListener.ts index 7932adecce..2d37615ab6 100644 --- a/apps/tlon-mobile/src/hooks/useNotificationListener.ts +++ b/apps/tlon-mobile/src/hooks/useNotificationListener.ts @@ -3,6 +3,7 @@ import type { NavigationProp } from '@react-navigation/native'; import { CommonActions, useNavigation } from '@react-navigation/native'; import { useFeatureFlag } from '@tloncorp/app/lib/featureFlags'; import { connectNotifications } from '@tloncorp/app/lib/notifications'; +import { RootStackParamList } from '@tloncorp/app/navigation/types'; import * as posthog from '@tloncorp/app/utils/posthog'; import { syncDms, syncGroups } from '@tloncorp/shared'; import { markChatRead } from '@tloncorp/shared/api'; @@ -16,8 +17,6 @@ import { } from 'expo-notifications'; import { useEffect, useState } from 'react'; -import { RootStackParamList } from '../types'; - type RouteStack = { name: keyof RootStackParamList; params?: RootStackParamList[keyof RootStackParamList]; @@ -151,13 +150,16 @@ export default function useNotificationListener() { } const routeStack: RouteStack = [{ name: 'ChatList' }]; - if (channel.group && !channelSwitcherEnabled) { + if (channel.groupId && !channelSwitcherEnabled) { routeStack.push({ name: 'GroupChannels', - params: { group: channel.group }, + params: { groupId: channel.groupId }, }); } - routeStack.push({ name: 'Channel', params: { channel } }); + routeStack.push({ + name: 'Channel', + params: { channelId: channel.id }, + }); // if we have a post id, try to navigate to the thread if (postInfo) { @@ -175,7 +177,14 @@ export default function useNotificationListener() { postToNavigateTo = { ...postInfo, channelId }; } - routeStack.push({ name: 'Post', params: { post: postToNavigateTo } }); + routeStack.push({ + name: 'Post', + params: { + postId: postToNavigateTo.id, + authorId: postToNavigateTo.authorId, + channelId: postToNavigateTo.channelId, + }, + }); } navigation.dispatch( diff --git a/apps/tlon-mobile/src/navigation.d.ts b/apps/tlon-mobile/src/navigation.d.ts index a546536c7b..33eaec9287 100644 --- a/apps/tlon-mobile/src/navigation.d.ts +++ b/apps/tlon-mobile/src/navigation.d.ts @@ -1,4 +1,4 @@ -import { RootStackParamList } from './types'; +import { RootStackParamList } from '@tloncorp/app/navigation/types'; declare global { namespace ReactNavigation { diff --git a/apps/tlon-mobile/src/types.ts b/apps/tlon-mobile/src/types.ts index 1ab59f89db..46c90745c7 100644 --- a/apps/tlon-mobile/src/types.ts +++ b/apps/tlon-mobile/src/types.ts @@ -1,100 +1,3 @@ -import type { NavigatorScreenParams } from '@react-navigation/native'; -import type * as db from '@tloncorp/shared/db'; - -export type SignUpExtras = { - nickname?: string; - notificationToken?: string; - telemetry?: boolean; -}; - -type ExternalWebViewScreenParams = { - uri: string; - headers?: Record; - injectedJavaScript?: string; -}; - -export type WebViewStackParamList = { - Webview: undefined; - ExternalWebView: ExternalWebViewScreenParams; -}; - -export type RootStackParamList = { - ChatList: { previewGroup: db.Group } | undefined; - Activity: undefined; - Profile: undefined; - Channel: { - channel: db.Channel; - selectedPostId?: string | null; - }; - FindGroups: undefined; - ContactHostedGroups: { - contactId: string; - }; - CreateGroup: undefined; - GroupChannels: { - group: db.Group; - }; - ChannelSearch: { - channel: db.Channel; - }; - Post: { - post: { - id: string; - channelId: string; - authorId: string; - }; - }; - ImageViewer: { - post: db.Post; - uri?: string; - }; - GroupSettings: NavigatorScreenParams; - AppSettings: undefined; - FeatureFlags: undefined; - ManageAccount: undefined; - BlockedUsers: undefined; - AppInfo: undefined; - PushNotificationSettings: undefined; - UserProfile: { - userId: string; - }; - EditProfile: undefined; - WompWomp: undefined; - ChannelMembers: { - channelId: string; - }; - ChannelMeta: { - channelId: string; - }; -}; - -export type GroupSettingsStackParamList = { - EditChannel: { - channelId: string; - groupId: string; - }; - GroupMeta: { - groupId: string; - }; - GroupMembers: { - groupId: string; - }; - ManageChannels: { - groupId: string; - }; - Privacy: { - groupId: string; - }; - GroupRoles: { - groupId: string; - }; -}; - -export type SettingsStackParamList = { - Settings: undefined; - FeatureFlags: undefined; -}; - export type OnboardingStackParamList = { Welcome: undefined; InventoryCheck: undefined; diff --git a/apps/tlon-web-new/src/app.tsx b/apps/tlon-web-new/src/app.tsx index 857d6c74d6..1e37e66e69 100644 --- a/apps/tlon-web-new/src/app.tsx +++ b/apps/tlon-web-new/src/app.tsx @@ -3,14 +3,16 @@ import { DarkTheme, DefaultTheme, NavigationContainer, - useNavigationContainerRef, } from '@react-navigation/native'; import { useConfigureUrbitClient } from '@tloncorp/app/hooks/useConfigureUrbitClient'; import { useCurrentUserId } from '@tloncorp/app/hooks/useCurrentUser'; import { useIsDarkMode } from '@tloncorp/app/hooks/useIsDarkMode'; import { checkDb, useMigrations } from '@tloncorp/app/lib/webDb'; -import { RootStack } from '@tloncorp/app/navigation/RootStack'; -import { TopLevelDrawer } from '@tloncorp/app/navigation/desktop/TopLevelDrawer'; +import { BasePathNavigator } from '@tloncorp/app/navigation/BasePathNavigator'; +import { + getDesktopLinkingConfig, + getMobileLinkingConfig, +} from '@tloncorp/app/navigation/linking'; import { Provider as TamaguiProvider } from '@tloncorp/app/provider'; import { AppDataProvider } from '@tloncorp/app/provider/AppDataProvider'; import { sync } from '@tloncorp/shared'; @@ -85,10 +87,8 @@ function AppRoutes({ isLoaded }: { isLoaded: boolean }) { } }, [calmSettingsQuery, isLoaded]); - const isDarkMode = useIsDarkMode(); const isMobile = useIsMobile(); - - const navigationContainerRef = useNavigationContainerRef(); + const isDarkMode = useIsDarkMode(); if (!isLoaded) { return null; @@ -99,12 +99,21 @@ function AppRoutes({ isLoaded }: { isLoaded: boolean }) { webAppNeedsUpdate={needsUpdate} triggerWebAppUpdate={triggerUpdate} > - - {isMobile ? : } - + {isMobile ? ( + + + + ) : ( + + + + )} ); } @@ -174,7 +183,7 @@ const App = React.memo(function AppComponent() { - + {dbIsLoaded && } diff --git a/apps/tlon-web-new/src/main.tsx b/apps/tlon-web-new/src/main.tsx index 798b503683..c4b46fb04a 100644 --- a/apps/tlon-web-new/src/main.tsx +++ b/apps/tlon-web-new/src/main.tsx @@ -3,17 +3,17 @@ // } /* eslint-disable */ +// At some point recently, we started getting a "regeneratorRuntime is not defined" error +// when running the app in development mode. This is a workaround for that issue. +// This is a temporary fix until we can figure out why this is happening. +// This was most likely caused by a recent dependency change. +import regeneratorRuntime from '@babel/runtime/regenerator'; import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; import { EditorView } from '@tiptap/pm/view'; import { setupDb } from '@tloncorp/app/lib/webDb'; import { PostHogProvider } from 'posthog-js/react'; import React from 'react'; import { createRoot } from 'react-dom/client'; -// At some point recently, we started getting a "regeneratorRuntime is not defined" error -// when running the app in development mode. This is a workaround for that issue. -// This is a temporary fix until we can figure out why this is happening. -// This was most likely caused by a recent dependency change. -import regeneratorRuntime from '@babel/runtime/regenerator'; import _api from './api'; import App from './app'; @@ -52,18 +52,19 @@ setupDb().then(() => { const container = document.getElementById('app') as HTMLElement; const root = createRoot(container); root.render( - - - - - - - + // Strict mode disabled as it breaks react-navigation on web + // + + + + + + // ); }); diff --git a/packages/app/features/top/ActivityScreen.tsx b/packages/app/features/top/ActivityScreen.tsx index 050a01c954..7c63524f95 100644 --- a/packages/app/features/top/ActivityScreen.tsx +++ b/packages/app/features/top/ActivityScreen.tsx @@ -32,7 +32,10 @@ export function ActivityScreen(props: Props) { const handleGoToChannel = useCallback( (channel: db.Channel, selectedPostId?: string) => { - props.navigation.navigate('Channel', { channel, selectedPostId }); + props.navigation.navigate('Channel', { + channelId: channel.id, + selectedPostId, + }); }, [props.navigation] ); @@ -42,7 +45,11 @@ export function ActivityScreen(props: Props) { const handleGoToThread = useCallback( (post: db.Post) => { // TODO: we have no way to route to specific thread message rn - props.navigation.navigate('Post', { post }); + props.navigation.navigate('Post', { + postId: post.id, + authorId: post.authorId, + channelId: post.channelId, + }); }, [props.navigation] ); diff --git a/packages/app/features/top/ChannelScreen.tsx b/packages/app/features/top/ChannelScreen.tsx index 2d7ea16700..d3eb92a304 100644 --- a/packages/app/features/top/ChannelScreen.tsx +++ b/packages/app/features/top/ChannelScreen.tsx @@ -1,5 +1,4 @@ -import { useFocusEffect } from '@react-navigation/native'; -import { useIsFocused } from '@react-navigation/native'; +import { useFocusEffect, useIsFocused } from '@react-navigation/native'; import type { NativeStackScreenProps } from '@react-navigation/native-stack'; import { createDevLogger } from '@tloncorp/shared'; import * as db from '@tloncorp/shared/db'; @@ -33,11 +32,12 @@ const logger = createDevLogger('ChannelScreen', false); type Props = NativeStackScreenProps; export default function ChannelScreen(props: Props) { - const channelFromParams = props.route.params.channel; - const selectedPostId = props.route.params.selectedPostId; - const [currentChannelId, setCurrentChannelId] = React.useState( - channelFromParams.id - ); + const { channelId, selectedPostId } = props.route.params; + const [currentChannelId, setCurrentChannelId] = React.useState(channelId); + + useEffect(() => { + setCurrentChannelId(channelId); + }, [channelId]); const { negotiationStatus, @@ -62,23 +62,22 @@ export default function ChannelScreen(props: Props) { if (group?.isNew) { store.markGroupVisited(group); } - - if (!channelFromParams.isPendingChannel) { - store.syncChannelThreadUnreads(channelFromParams.id, { + }, [group]) + ); + useFocusEffect( + useCallback(() => { + if (channel && !channel.isPendingChannel) { + store.syncChannelThreadUnreads(channel.id, { priority: store.SyncPriority.High, }); } - }, [channelFromParams, group]) - ); - useFocusEffect( - useCallback( - () => - // Mark the channel as visited when we unfocus/leave this screen - () => { - store.markChannelVisited(channelFromParams); - }, - [channelFromParams] - ) + // Mark the channel as visited when we unfocus/leave this screen + () => { + if (channel) { + store.markChannelVisited(channel); + } + }; + }, [channel]) ); const [channelNavOpen, setChannelNavOpen] = React.useState(false); @@ -292,7 +291,7 @@ export default function ChannelScreen(props: Props) { const dmChannel = await store.upsertDmChannel({ participants, }); - props.navigation.push('Channel', { channel: dmChannel }); + props.navigation.push('Channel', { channelId: dmChannel.id }); }, [props.navigation] ); @@ -319,7 +318,7 @@ export default function ChannelScreen(props: Props) { const handleGoToUserProfile = useCallback( (userId: string) => { - props.navigation.push('UserProfile', { userId }); + props.navigation.navigate('UserProfile', { userId }); }, [props.navigation] ); @@ -336,7 +335,7 @@ export default function ChannelScreen(props: Props) { return ( { @@ -345,6 +344,7 @@ export default function ChannelScreen(props: Props) { {...chatOptionsNavProps} > ; export default function ChannelSearchScreen(props: Props) { - const channel = props.route.params.channel; + const channelId = props.route.params.channelId; + const channelQuery = useChannelWithRelations({ + id: channelId, + }); const [query, setQuery] = useState(''); const { posts, loading, errored, hasMore, loadMore, searchedThroughDate } = - useChannelSearch(channel, query); + useChannelSearch(channelId, query); const navigateToPost = useCallback( (post: db.Post) => { if (post.parentId) { props.navigation.replace('Post', { - post: { - id: post.parentId, - channelId: post.channelId, - authorId: post.authorId, - }, + postId: post.parentId, + channelId: post.channelId, + authorId: post.authorId, }); } else { props.navigation.navigate('Channel', { - channel, + channelId: post.channelId, selectedPostId: post.id, }); } }, - [channel, props.navigation] + [props.navigation] ); return ( @@ -42,7 +43,7 @@ export default function ChannelSearchScreen(props: Props) {