diff --git a/apps/desktop/layer/renderer/src/atoms/server-configs.ts b/apps/desktop/layer/renderer/src/atoms/server-configs.ts index 8e1632785..8817d0835 100644 --- a/apps/desktop/layer/renderer/src/atoms/server-configs.ts +++ b/apps/desktop/layer/renderer/src/atoms/server-configs.ts @@ -16,6 +16,10 @@ export const [, , useServerConfigs, , getServerConfigs, setServerConfigs] = crea ), ) +export type ServerConfigs = ExtractResponseData +export type PaymentPlan = ServerConfigs["PAYMENT_PLAN_LIST"][number] +export type PaymentFeature = PaymentPlan["limit"] + export const useIsInMASReview = () => { const serverConfigs = useServerConfigs() return ( @@ -24,3 +28,12 @@ export const useIsInMASReview = () => { serverConfigs?.MAS_IN_REVIEW_VERSION === PKG.version ) } + +export const getIsInMASReview = () => { + const serverConfigs = getServerConfigs() + return ( + typeof process !== "undefined" && + process.mas && + serverConfigs?.MAS_IN_REVIEW_VERSION === PKG.version + ) +} diff --git a/apps/desktop/layer/renderer/src/components/ui/ai-summary-card/AISummaryCardBase.tsx b/apps/desktop/layer/renderer/src/components/ui/ai-summary-card/AISummaryCardBase.tsx index d3885ca3d..12b7dd6c2 100644 --- a/apps/desktop/layer/renderer/src/components/ui/ai-summary-card/AISummaryCardBase.tsx +++ b/apps/desktop/layer/renderer/src/components/ui/ai-summary-card/AISummaryCardBase.tsx @@ -1,12 +1,15 @@ import { AutoResizeHeight } from "@follow/components/ui/auto-resize-height/index.js" import { MotionButtonBase } from "@follow/components/ui/button/index.js" import { cn } from "@follow/utils/utils" +import { isNeedUpgradeError } from "@follow-app/client-sdk" import type { ReactNode } from "react" import { useTranslation } from "react-i18next" +import { useIsInMASReview } from "~/atoms/server-configs" import { CopyButton } from "~/components/ui/button/CopyButton" import { Markdown } from "~/components/ui/markdown/Markdown" import { useFeature } from "~/hooks/biz/useFeature" +import { useSettingModal } from "~/modules/settings/modal/useSettingModal" interface AISummaryCardBaseProps { /** Summary content to display */ @@ -21,8 +24,6 @@ interface AISummaryCardBaseProps { footerContent?: ReactNode /** Custom loading state component */ loadingComponent?: ReactNode - /** Custom empty state component */ - emptyComponent?: ReactNode /** Title text for the AI Summary header */ title?: string /** Whether to show the copy button */ @@ -31,6 +32,8 @@ interface AISummaryCardBaseProps { showAskAIButton?: boolean /** Callback when Ask AI button is clicked */ onAskAI?: () => void + /** Error code returned when requesting the summary */ + errorCode?: number } const DefaultLoadingState = () => ( @@ -41,12 +44,24 @@ const DefaultLoadingState = () => ( ) -const DefaultEmptyState = ({ message }: { message: string }) => ( -
- -

{message}

-
-) +const DefaultEmptyState = ({ + message, + shouldSuggestUpgrade, +}: { + message: string + shouldSuggestUpgrade?: boolean +}) => { + const settingModalPresent = useSettingModal() + + return ( +
settingModalPresent("plan") : undefined} + > +

{message}

+
+ ) +} export const AISummaryCardBase: React.FC = ({ content, @@ -55,16 +70,20 @@ export const AISummaryCardBase: React.FC = ({ headerContent, footerContent, loadingComponent, - emptyComponent, title = "AI Summary", showCopyButton = true, showAskAIButton = false, onAskAI, + errorCode, }) => { const { t } = useTranslation("app") const aiEnabled = useFeature("ai") + const isInMASReview = useIsInMASReview() const hasContent = !isLoading && content + const normalizedErrorCode = typeof errorCode === "number" ? errorCode : undefined + const shouldSuggestUpgrade = + normalizedErrorCode !== undefined && !isInMASReview && isNeedUpgradeError(normalizedErrorCode) return (
= ({ loadingComponent || ) : hasContent ? ( {String(content)} + ) : shouldSuggestUpgrade ? ( + ) : ( - emptyComponent || + )} - {/* Footer */} {footerContent}
) diff --git a/apps/desktop/layer/renderer/src/hooks/biz/useEntryActions.tsx b/apps/desktop/layer/renderer/src/hooks/biz/useEntryActions.tsx index e8ee82f16..246b2d82b 100644 --- a/apps/desktop/layer/renderer/src/hooks/biz/useEntryActions.tsx +++ b/apps/desktop/layer/renderer/src/hooks/biz/useEntryActions.tsx @@ -357,7 +357,6 @@ export const useEntryActions = ({ entryId, view }: { entryId: string; view: Feed view, ), active: isShowAISummaryOnce, - disabled: userRole === UserRole.Free || userRole === UserRole.Trial, entryId, }), new EntryActionMenuItem({ diff --git a/apps/desktop/layer/renderer/src/hooks/biz/useFollow.tsx b/apps/desktop/layer/renderer/src/hooks/biz/useFollow.tsx index 26e821224..220099203 100644 --- a/apps/desktop/layer/renderer/src/hooks/biz/useFollow.tsx +++ b/apps/desktop/layer/renderer/src/hooks/biz/useFollow.tsx @@ -1,63 +1,17 @@ -import { UserRole } from "@follow/constants" import { getFeedByIdOrUrl } from "@follow/store/feed/getter" import { getSubscriptionByFeedId } from "@follow/store/subscription/getter" -import { - useFeedSubscriptionCount, - useListSubscriptionCount, -} from "@follow/store/subscription/hooks" -import { useUserRole } from "@follow/store/user/hooks" import { t } from "i18next" import { useCallback } from "react" import { useNavigate } from "react-router" import { withoutTrailingSlash, withTrailingSlash } from "ufo" -import { useEventCallback } from "usehooks-ts" import { previewBackPath } from "~/atoms/preview" -import { useServerConfigs } from "~/atoms/server-configs" import { useModalStack } from "~/components/ui/modal/stacked/hooks" -import { CustomSafeError } from "~/errors/CustomSafeError" -import { useActivationModal } from "~/modules/activation" import type { FeedFormDataValuesType } from "~/modules/discover/FeedForm" import { FeedForm } from "~/modules/discover/FeedForm" import type { ListFormDataValuesType } from "~/modules/discover/ListForm" import { ListForm } from "~/modules/discover/ListForm" -const useCanFollowMoreInboxAndNotify = () => { - const role = useUserRole() - const listCurrentCount = useListSubscriptionCount() - const feedCurrentCount = useFeedSubscriptionCount() - const presentActivationModal = useActivationModal() - const serverConfigs = useServerConfigs() - - return useEventCallback((type: "list" | "feed") => { - if (role === UserRole.Free || role === UserRole.Trial) { - const LIMIT = - (type !== "list" - ? serverConfigs?.MAX_TRIAL_USER_FEED_SUBSCRIPTION - : serverConfigs?.MAX_TRIAL_USER_LIST_SUBSCRIPTION) || 50 - const CURRENT = type === "list" ? listCurrentCount : feedCurrentCount - const can = CURRENT < LIMIT - if (!can) { - presentActivationModal() - - throw new CustomSafeError( - `Trial user cannot create more ${type}, limit: ${LIMIT}, current: ${CURRENT}`, - true, - ) - } - return can - } else { - // const can = currentInboxCount < MAX_INBOX_COUNT - // if (!can) { - // // TODO - // } - // return can - - return true - } - }) -} - export interface FollowOptions { isList: boolean id?: string @@ -68,17 +22,10 @@ export interface FollowOptions { } export const useFollow = () => { const { present } = useModalStack() - const canFollowMoreInboxAndNotify = useCanFollowMoreInboxAndNotify() const navigate = useNavigate() return useCallback( (options?: FollowOptions) => { - if (options?.isList) { - canFollowMoreInboxAndNotify("list") - } else { - canFollowMoreInboxAndNotify("feed") - } - // Some feeds redirect xxx.com/feed to xxx.com/feed/ // Try to get a valid feed, then we can check isFollowed correctly const feed = @@ -117,6 +64,6 @@ export const useFollow = () => { }, }) }, - [canFollowMoreInboxAndNotify, present], + [present], ) } diff --git a/apps/desktop/layer/renderer/src/lib/api-client.ts b/apps/desktop/layer/renderer/src/lib/api-client.ts index 7f500e3bf..c5e00da9a 100644 --- a/apps/desktop/layer/renderer/src/lib/api-client.ts +++ b/apps/desktop/layer/renderer/src/lib/api-client.ts @@ -3,12 +3,9 @@ import { userActions } from "@follow/store/user/store" import { createDesktopAPIHeaders } from "@follow/utils/headers" import { FollowClient } from "@follow-app/client-sdk" import PKG from "@pkg" -import { createElement } from "react" -import { toast } from "sonner" import { NetworkStatus, setApiStatus } from "~/atoms/network" import { setLoginModalShow } from "~/atoms/user" -import { NeedActivationToast } from "~/modules/activation/NeedActivationToast" import { getClientId, getSessionId } from "./client-session" @@ -78,25 +75,6 @@ followClient.addResponseInterceptor(async ({ response }) => { if (response.status === 400 && json.code === 1003) { router.navigate("/invitation") } - if (json.code.toString().startsWith("11")) { - setTimeout(() => { - const toastId = toast.error( - createElement(NeedActivationToast, { - dimiss: () => { - toast.dismiss(toastId) - }, - }), - { - closeButton: true, - duration: 10e4, - - classNames: { - content: tw`w-full`, - }, - }, - ) - }, 500) - } } catch { // ignore } diff --git a/apps/desktop/layer/renderer/src/lib/api-fetch.ts b/apps/desktop/layer/renderer/src/lib/api-fetch.ts index e2c8918b2..ef89ed855 100644 --- a/apps/desktop/layer/renderer/src/lib/api-fetch.ts +++ b/apps/desktop/layer/renderer/src/lib/api-fetch.ts @@ -1,16 +1,11 @@ -import { DEV } from "@follow/shared/constants" import { env } from "@follow/shared/env.desktop" import { userActions } from "@follow/store/user/store" import { createDesktopAPIHeaders } from "@follow/utils/headers" import PKG from "@pkg" import { ofetch } from "ofetch" -import { createElement } from "react" -import { toast } from "sonner" import { NetworkStatus, setApiStatus } from "~/atoms/network" import { setLoginModalShow } from "~/atoms/user" -import { NeedActivationToast } from "~/modules/activation/NeedActivationToast" -import { DebugRegistry } from "~/modules/debug/registry" import { getClientId, getSessionId } from "./client-session" @@ -57,48 +52,8 @@ export const apiFetch = ofetch.create({ if (context.response.status === 400 && json.code === 1003) { router.navigate("/invitation") } - if (json.code.toString().startsWith("11")) { - setTimeout(() => { - const toastId = toast.error( - createElement(NeedActivationToast, { - dimiss: () => { - toast.dismiss(toastId) - }, - }), - { - closeButton: true, - duration: 10e4, - - classNames: { - content: tw`w-full`, - }, - }, - ) - }, 500) - } } catch { // ignore } }, }) - -if (DEV) { - DebugRegistry.add("Activation Toast", () => { - setTimeout(() => { - const toastId = toast.error( - createElement(NeedActivationToast, { - dimiss: () => { - toast.dismiss(toastId) - }, - }), - { - closeButton: true, - duration: 10e4, - classNames: { - content: tw`w-full`, - }, - }, - ) - }, 500) - }) -} diff --git a/apps/desktop/layer/renderer/src/lib/error-parser.ts b/apps/desktop/layer/renderer/src/lib/error-parser.ts index 5aad15db8..e0ab80df7 100644 --- a/apps/desktop/layer/renderer/src/lib/error-parser.ts +++ b/apps/desktop/layer/renderer/src/lib/error-parser.ts @@ -1,11 +1,13 @@ import { DEV } from "@follow/shared/constants" import { cn } from "@follow/utils/utils" +import { FollowAPIError, isNeedUpgradeError } from "@follow-app/client-sdk" import { t } from "i18next" import { FetchError } from "ofetch" import { createElement } from "react" import type { ExternalToast } from "sonner" import { toast } from "sonner" +import { getIsInMASReview } from "~/atoms/server-configs" import { CopyButton } from "~/components/ui/button/CopyButton" import { Markdown } from "~/components/ui/markdown/Markdown" import { DebugRegistry } from "~/modules/debug/registry" @@ -32,6 +34,20 @@ export const getFetchErrorInfo = ( } } + if (error instanceof FollowAPIError && error.code) { + const code = Number(error.code) + try { + const i18nKey = `errors:${code}` as any + const i18nMessage = t(i18nKey) === i18nKey ? error.message : t(i18nKey) + return { + message: i18nMessage, + code, + } + } catch { + return { message: error.message } + } + } + return { message: error.message } } @@ -78,6 +94,17 @@ export const toastFetchError = ( } } + if ("code" in error && error.code) { + code = Number(error.code) + try { + const tValue = t(`errors:${code}` as any) + const i18nMessage = tValue === code?.toString() ? error.message : tValue + message = i18nMessage + } catch { + message = error.message + } + } + // 2fa errors are handled by the form if (code === 4007 || code === 4008) { return @@ -94,9 +121,24 @@ export const toastFetchError = ( } if (!_reason) { - const title = _title || message - toastOptions.description = _title ? message : undefined - return toast.error(title, toastOptions) + const title = _title || message || "Unknown error occurred" + toastOptions.description = _title ? message : "" + const isInMASReview = getIsInMASReview() + const needUpgradeError = code && !isInMASReview ? isNeedUpgradeError(code) : false + if (needUpgradeError) { + toastOptions.description = "Please upgrade your plan." + } + return toast.error(title, { + ...toastOptions, + action: needUpgradeError + ? { + label: "Upgrade", + onClick: () => { + window.router.showSettings({ tab: "plan" }) + }, + } + : undefined, + }) } else { return toast.error(message || _title, { duration: 5000, diff --git a/apps/desktop/layer/renderer/src/modules/action/action-setting.tsx b/apps/desktop/layer/renderer/src/modules/action/action-setting.tsx index b87494f81..c3ea06729 100644 --- a/apps/desktop/layer/renderer/src/modules/action/action-setting.tsx +++ b/apps/desktop/layer/renderer/src/modules/action/action-setting.tsx @@ -32,6 +32,7 @@ import { useDialog } from "~/components/ui/modal/stacked/hooks" import { useContextMenu } from "~/hooks/common/useContextMenu" import { getI18n } from "~/i18n" import { copyToClipboard, readFromClipboard } from "~/lib/clipboard" +import { toastFetchError } from "~/lib/error-parser" import { downloadJsonFile, selectJsonFile } from "~/lib/export" import { RuleCard } from "~/modules/action/rule-card" import { @@ -421,7 +422,7 @@ const ActionButtonGroup = ({ onCreateRule }: { onCreateRule: () => void }) => { toast(t("actions.saveSuccess")) }, onError: (error) => { - toast.error(error) + toastFetchError(error) }, }) diff --git a/apps/desktop/layer/renderer/src/modules/activation/NeedActivationToast.tsx b/apps/desktop/layer/renderer/src/modules/activation/NeedActivationToast.tsx deleted file mode 100644 index c9370c41b..000000000 --- a/apps/desktop/layer/renderer/src/modules/activation/NeedActivationToast.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { toastStyles } from "@follow/components/ui/toast/styles.js" -import { stopPropagation } from "@follow/utils/dom" -import { useCallback } from "react" -import { useTranslation } from "react-i18next" - -import { useSettingModal } from "../settings/modal/use-setting-modal-hack" - -export const NeedActivationToast = (props: { dimiss: () => void }) => { - const settingModalPresent = useSettingModal() - - const { t } = useTranslation() - return ( -
-
{t("activation.plan.description")}
- - -
- ) -} diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/RateLimitNotice.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/RateLimitNotice.tsx index 09056ddec..ffd4946bc 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/RateLimitNotice.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/RateLimitNotice.tsx @@ -2,6 +2,8 @@ import { cn } from "@follow/utils" import { m } from "motion/react" import * as React from "react" +import { useSettingModal } from "~/modules/settings/modal/useSettingModal" + import { parseAIError } from "../../utils/error" interface RateLimitNoticeProps { @@ -16,6 +18,7 @@ interface RateLimitNoticeProps { export const RateLimitNotice: React.FC = ({ error, className }) => { const parsedError = React.useMemo(() => parseAIError(error), [error]) const { isRateLimitError, errorData } = parsedError + const settingModalPresent = useSettingModal() // Only render for rate limit errors if (!isRateLimitError || !errorData) { @@ -57,7 +60,7 @@ export const RateLimitNotice: React.FC = ({ error, classNa parts.push(`${remainingTokens.toLocaleString()} tokens left`) } } else { - parts.push("AI usage limit reached") + parts.push("Upgrade plan to get more AI credits.") } // Reset time @@ -79,9 +82,10 @@ export const RateLimitNotice: React.FC = ({ error, classNa exit={{ opacity: 0, y: -10 }} transition={{ duration: 0.2 }} className={cn("mb-3", className)} + onClick={() => settingModalPresent("plan")} >
- + {buildMessage()} diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/welcome/EntrySummaryCard.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/welcome/EntrySummaryCard.tsx index 934eb9057..8b6015281 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/welcome/EntrySummaryCard.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/welcome/EntrySummaryCard.tsx @@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next" import { useEntryIsInReadabilitySuccess } from "~/atoms/readability" import { useActionLanguage } from "~/atoms/settings/general" import { AISummaryCardBase } from "~/components/ui/ai-summary-card" +import { getFetchErrorInfo } from "~/lib/error-parser" interface EntrySummaryCardProps { entryId: string @@ -22,6 +23,8 @@ export const EntrySummaryCard: React.FC = ({ entryId, cla actionLanguage, enabled: true, }) + const summaryErrorCode = + summary.error instanceof Error ? getFetchErrorInfo(summary.error).code : undefined return ( = ({ entryId, cla isLoading={summary.isLoading} className={className} title={t("ai_summary")} + errorCode={summaryErrorCode} /> ) diff --git a/apps/desktop/layer/renderer/src/modules/command/commands/entry.tsx b/apps/desktop/layer/renderer/src/modules/command/commands/entry.tsx index 51dce0851..3a02ef6a6 100644 --- a/apps/desktop/layer/renderer/src/modules/command/commands/entry.tsx +++ b/apps/desktop/layer/renderer/src/modules/command/commands/entry.tsx @@ -399,10 +399,6 @@ export const useRegisterEntryCommands = () => { icon: , category, run: () => { - if (role === UserRole.Free || role === UserRole.Trial) { - presentActivationModal() - return - } toggleShowAISummaryOnce() }, }, diff --git a/apps/desktop/layer/renderer/src/modules/discover/DiscoverInboxList.tsx b/apps/desktop/layer/renderer/src/modules/discover/DiscoverInboxList.tsx index a44089763..86df9214f 100644 --- a/apps/desktop/layer/renderer/src/modules/discover/DiscoverInboxList.tsx +++ b/apps/desktop/layer/renderer/src/modules/discover/DiscoverInboxList.tsx @@ -1,48 +1,17 @@ import { Button } from "@follow/components/ui/button/index.js" -import { UserRole } from "@follow/constants" -import { useUserRole } from "@follow/store/user/hooks" import { repository } from "@pkg" import { useTranslation } from "react-i18next" -import { useEventCallback } from "usehooks-ts" import { useModalStack } from "~/components/ui/modal/stacked/hooks" -import { CustomSafeError } from "~/errors/CustomSafeError" -import { useActivationModal } from "../activation" import { InboxTable } from "./Inbox" import { InboxForm } from "./InboxForm" -const useCanCreateMoreInboxAndNotify = () => { - const role = useUserRole() - const presentActivationModal = useActivationModal() - - return useEventCallback(() => { - if (role === UserRole.Free || role === UserRole.Trial) { - const can = false - if (!can) { - presentActivationModal() - - throw new CustomSafeError(`Trial user cannot create more inboxes`, true) - } - return can - } else { - // const can = currentInboxCount < MAX_INBOX_COUNT - // if (!can) { - // // TODO - // } - // return can - - return true - } - }) -} export function DiscoverInboxList() { const { t } = useTranslation() const { present } = useModalStack() - const preCheck = useCanCreateMoreInboxAndNotify() - return (
@@ -63,7 +32,6 @@ export function DiscoverInboxList() {
@@ -174,111 +171,119 @@ export function SettingPlan() { {/* Plans Grid */}
- {PLAN_CONFIGS.map((plan) => ( + {plans.map((plan) => ( ))}
+ + {/* Comparison Table */} + ) } // Reusable PlanCard Component interface PlanCardProps { - plan: Plan + plan: PaymentPlan billingPeriod: "monthly" | "yearly" - currentUserRole: UserRole | null isCurrentPlan: boolean + currentTier: number daysLeft: number | null } -const PlanCard = ({ - plan, - billingPeriod, - currentUserRole, - isCurrentPlan, - daysLeft, -}: PlanCardProps) => { - const getPlanActionType = (): "current" | "upgrade" | "coming-soon" | "in-trial" | null => { +const PlanCard = ({ plan, billingPeriod, isCurrentPlan, currentTier, daysLeft }: PlanCardProps) => { + const { t } = useTranslation("settings") + const getPlanActionType = (): + | "current" + | "upgrade" + | "coming-soon" + | "in-trial" + | "switch" + | null => { if (plan.isComingSoon) return "coming-soon" - - if (!currentUserRole) { - return plan.tier > PLAN_TIER_MAP[UserRole.Free] ? "upgrade" : "current" - } - - const currentTier = PLAN_TIER_MAP[currentUserRole] - const targetTier = plan.tier - - if (currentTier === targetTier) { - // if (currentUserRole === UserRole.PreProTrial) { - // return "in-trial" - // } else { - // return "current" + switch (true) { + case isCurrentPlan: { + return "current" + } + case plan.tier > currentTier && !!plan.planID: { + return "upgrade" + } + // case plan.tier < currentTier && !!plan.planID: { + // return "switch" // } - return "current" + default: { + return null + } } - if (targetTier > currentTier) return "upgrade" - return null } const actionType = getPlanActionType() const upgradePlanMutation = useUpgradePlan({ - plan: "folo pro", + plan: plan.planID, annual: billingPeriod === "yearly", }) const cancelPlanMutation = useCancelPlan() // Calculate price and period based on billing period - const price = billingPeriod === "yearly" ? plan.yearlyPrice : plan.monthlyPrice - const formattedPrice = price === 0 ? "$0" : `$${price}` - const period = plan.role === UserRole.Free ? "" : billingPeriod === "yearly" ? "year" : "month" + const regularPrice = + billingPeriod === "yearly" ? plan.priceInDollarsAnnual / 12 : plan.priceInDollars + const discountPrice = + billingPeriod === "yearly" + ? (plan.priceInDollarsInDiscountAnnual || 0) / 12 + : plan.priceInDollarsInDiscount + const period = plan.role === UserRole.Free ? "" : "month" - // Calculate savings for yearly plan - const yearlyTotalPrice = plan.yearlyPrice - const monthlyTotalPrice = plan.monthlyPrice * 12 - const savingsPercentage = - plan.monthlyPrice > 0 && plan.yearlyPrice > 0 - ? Math.round(((monthlyTotalPrice - yearlyTotalPrice) / monthlyTotalPrice) * 100) - : 0 + // Calculate discount percentage from prices + const hasDiscount = + discountPrice && + discountPrice > 0 && + discountPrice < regularPrice && + discountPrice !== regularPrice + const discountPercentage = hasDiscount + ? Math.round(((regularPrice - discountPrice) / regularPrice) * 100) + : 0 + + // Use discount price if available, otherwise use regular price + const finalPrice = hasDiscount ? discountPrice : regularPrice + const formattedPrice = finalPrice === 0 ? "$0" : `$${finalPrice.toFixed(2)}` + const formattedRegularPrice = + hasDiscount && regularPrice > 0 ? `$${regularPrice.toFixed(2)}` : undefined + + // Get plan description from i18n + const planDescriptionKey = `plan.descriptions.${plan.role}` as const + const planDescription = t(planDescriptionKey, { defaultValue: "" }) return (
-
-
- - -
-
+
+ { cancelPlanMutation.mutate() } @@ -321,70 +326,48 @@ const PlanBadges = ({ isPopular }: { isPopular: boolean }) => ( const PlanHeader = ({ title, price, + regularPrice, period, - billingPeriod, - monthlyPrice, - yearlyPrice, - savingsPercentage, + description, + discountPercentage, }: { title: string price: string + regularPrice?: string period: string - billingPeriod: "monthly" | "yearly" - monthlyPrice: number - yearlyPrice: number - savingsPercentage: number + description?: string + discountPercentage?: number }) => ( -
+

{title}

-
- {price} - {period && /{period}} -
-
- {billingPeriod === "yearly" && - monthlyPrice > 0 && - yearlyPrice > 0 && - savingsPercentage > 0 && ( -
- - ${(monthlyPrice * 12).toFixed(0)}/year - - Save {savingsPercentage}% -
+
+
+ {price} + {period && /{period}} + {regularPrice && ( + {regularPrice} )} - {billingPeriod === "yearly" && monthlyPrice > 0 && yearlyPrice > 0 && ( -
- ${(yearlyPrice / 12).toFixed(1)}/month billed annually +
+ {!!discountPercentage && discountPercentage > 0 && ( +
+ -{discountPercentage}% OFF
)}
-
-) - -const PlanFeatures = ({ features }: { features: string[] }) => ( -
- {features.map((feature) => ( -
-
- -
- {feature} -
- ))} + {description && ( +

{description}

+ )}
) const PlanAction = ({ - isPopular, actionType, onSelect, onCancel, isLoading, daysLeft, }: { - isPopular: boolean - actionType: "current" | "upgrade" | "coming-soon" | "in-trial" | null + actionType: "current" | "upgrade" | "coming-soon" | "in-trial" | "switch" | null onSelect?: () => void onCancel?: () => void isLoading?: boolean @@ -396,33 +379,37 @@ const PlanAction = ({ return { text: "Coming Soon", variant: "outline" as const, - className: "w-full h-9 @md:h-10 text-xs @md:text-sm", disabled: true, } } case "current": { return { - text: typeof daysLeft === "number" ? `${daysLeft} days left` : "Current Plan", + text: `${typeof daysLeft === "number" ? `${daysLeft} days left` : "Current Plan"}${onCancel ? " | Cancel" : ""}`, variant: "outline" as const, - className: "w-full h-9 @md:h-10 text-xs @md:text-sm text-text-secondary", - disabled: true, + className: onCancel ? "" : "text-text-secondary", + disabled: onCancel ? false : true, } } case "in-trial": { return { text: `In Trial (${daysLeft} days left)`, variant: "outline" as const, - className: "w-full h-9 @md:h-10 text-xs @md:text-sm", disabled: false, } } case "upgrade": { return { text: "Upgrade", - variant: isPopular ? undefined : ("outline" as const), - className: isPopular - ? "w-full h-9 @md:h-10 text-xs @md:text-sm bg-gradient-to-r from-accent to-accent/80 hover:from-accent/90 hover:to-accent/70" - : "w-full h-9 @md:h-10 text-xs @md:text-sm", + className: + "bg-gradient-to-r from-accent to-accent/80 hover:from-accent/90 hover:to-accent/70", + disabled: false, + } + } + case "switch": { + return { + text: "Switch", + className: + "bg-gradient-to-r from-accent to-accent/80 hover:from-accent/90 hover:to-accent/70", disabled: false, } } @@ -439,27 +426,92 @@ const PlanAction = ({ } return ( -
- + + ) +} - {actionType === "current" && typeof daysLeft === "number" && onCancel && ( - - )} +const PlanComparisonTable = ({ plans }: { plans: PaymentPlan[] }) => { + const { t } = useTranslation("settings") + + // Get all unique feature keys + const allFeatureKeys = Array.from( + new Set(plans.flatMap((plan) => Object.keys(plan.limit))), + ) as (keyof PaymentFeature)[] + + // Filter out features that are all false/0/null + const visibleFeatureKeys = allFeatureKeys.filter((key) => + plans.some((plan) => { + const value = plan.limit[key] + if (value == null) return false + if (typeof value === "boolean" && !value) return false + if (typeof value === "number" && value === 0) return false + return true + }), + ) + + return ( +
+
+ + + + + {plans.map((plan) => ( + + ))} + + + + {visibleFeatureKeys.map((featureKey, index) => ( + + + {plans.map((plan) => { + const value = plan.limit[featureKey] + const formattedValue = formatFeatureValue(featureKey, value) + + return ( + + ) + })} + + ))} + +
+ Features + + {plan.name} +
+ {t(`plan.features.${featureKey}` as any)} + + + {formattedValue} + +
+
) } diff --git a/apps/desktop/layer/renderer/src/modules/user/ProfileButton.tsx b/apps/desktop/layer/renderer/src/modules/user/ProfileButton.tsx index 4280c1a83..75593b744 100644 --- a/apps/desktop/layer/renderer/src/modules/user/ProfileButton.tsx +++ b/apps/desktop/layer/renderer/src/modules/user/ProfileButton.tsx @@ -2,7 +2,6 @@ import { ActionButton } from "@follow/components/ui/button/index.js" import { RSSHubLogo } from "@follow/components/ui/platform-icon/icons.js" import { RootPortal } from "@follow/components/ui/portal/index.js" import { EllipsisHorizontalTextWithTooltip } from "@follow/components/ui/typography/EllipsisWithTooltip.js" -import { UserRole } from "@follow/constants" import { useMeasure } from "@follow/hooks" import { useUserRole } from "@follow/store/user/hooks" import { cn } from "@follow/utils/utils" @@ -28,7 +27,6 @@ import { usePresentUserProfileModal } from "~/modules/profile/hooks" import { useSettingModal } from "~/modules/settings/modal/use-setting-modal-hack" import { signOut, useSession } from "~/queries/auth" -import { useActivationModal } from "../activation" import type { LoginProps } from "./LoginButton" import { LoginButton } from "./LoginButton" import { UserAvatar } from "./UserAvatar" @@ -53,7 +51,6 @@ export const ProfileButton: FC = memo((props) => { const navigate = useNavigate() const role = useUserRole() - const presentActivationModal = useActivationModal() const isInMASReview = useIsInMASReview() if (status === "unauthenticated") { @@ -83,7 +80,7 @@ export const ProfileButton: FC = memo((props) => { {user?.name} - {serverConfig?.REFERRAL_ENABLED ? ( + {!isInMASReview && serverConfig?.PAYMENT_ENABLED ? ( = memo((props) => { { - if (role !== UserRole.Trial && role !== UserRole.Free) { - presentAchievement() - } else { - presentActivationModal() - } + presentAchievement() }} icon={} > {t("user_button.achievement")} - {!isInMASReview && ( + {!isInMASReview && serverConfig?.PAYMENT_ENABLED && ( { - navigate("/power") + settingModalPresent("plan") }} icon={} > - {t("user_button.power")} + {t("activation.plan.title")} )} diff --git a/apps/desktop/layer/renderer/src/modules/user/UserAvatar.tsx b/apps/desktop/layer/renderer/src/modules/user/UserAvatar.tsx index 0a237a67a..f1da1458c 100644 --- a/apps/desktop/layer/renderer/src/modules/user/UserAvatar.tsx +++ b/apps/desktop/layer/renderer/src/modules/user/UserAvatar.tsx @@ -82,7 +82,7 @@ export const UserAvatar = ({ {renderUserData?.name?.[0]} - {serverConfig?.REFERRAL_ENABLED && + {serverConfig?.PAYMENT_ENABLED && !userId && role !== UserRole.Free && role !== UserRole.Trial && ( diff --git a/apps/desktop/layer/renderer/src/modules/user/UserProBadge.tsx b/apps/desktop/layer/renderer/src/modules/user/UserProBadge.tsx index 09f07617e..4a3a8684e 100644 --- a/apps/desktop/layer/renderer/src/modules/user/UserProBadge.tsx +++ b/apps/desktop/layer/renderer/src/modules/user/UserProBadge.tsx @@ -27,7 +27,7 @@ export const UserProBadge = ({ )} onClick={onClick} > - + {withText && {UserRoleName[role]}}
) diff --git a/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx b/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx index 436a092ad..61b5df46c 100644 --- a/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx +++ b/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx @@ -2,16 +2,12 @@ import { Divider } from "@follow/components/ui/divider/Divider.js" import { useScrollElementUpdate } from "@follow/components/ui/scroll-area/hooks.js" import { ScrollArea } from "@follow/components/ui/scroll-area/index.js" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@follow/components/ui/tabs/index.jsx" -import { UserRole } from "@follow/constants" -import { useUserRole } from "@follow/store/user/hooks" -import { cn } from "@follow/utils/utils" import { createElement } from "react" import { useTranslation } from "react-i18next" import { useSearchParams } from "react-router" import { AppErrorBoundary } from "~/components/common/AppErrorBoundary" import { ErrorComponentType } from "~/components/errors/enum" -import { useActivationModal } from "~/modules/activation" import { useSubViewTitle } from "~/modules/app-layout/subview/hooks" import { DiscoverForm } from "~/modules/discover/DiscoverForm" import { DiscoverImport } from "~/modules/discover/DiscoverImport" @@ -24,7 +20,6 @@ import { Trending } from "~/modules/trending" const tabs: { name: I18nKeys value: string - disableForTrial?: boolean }[] = [ { name: "words.search", @@ -41,7 +36,6 @@ const tabs: { { name: "words.inbox", value: "inbox", - disableForTrial: true, }, { name: "words.user", @@ -62,18 +56,8 @@ export function Component() { const { t } = useTranslation() useSubViewTitle("words.discover") - const presentActivationModal = useActivationModal() - const role = useUserRole() const { onUpdateMaxScroll } = useScrollElementUpdate() - const currentTabs = tabs.map((tab) => { - const disabled = tab.disableForTrial && (role === UserRole.Free || role === UserRole.Trial) - return { - ...tab, - disabled, - } - }) - return (
{/* Simple Header */} @@ -100,17 +84,12 @@ export function Component() {
- {currentTabs.map((tab) => ( + {tabs.map((tab) => ( { - if (tab.disabled) { - presentActivationModal() - } else { - onUpdateMaxScroll?.() - } + onUpdateMaxScroll?.() }} > {t(tab.name)} @@ -122,7 +101,7 @@ export function Component() { {/* Tab Content */}
- {currentTabs.map((tab) => ( + {tabs.map((tab) => (
{createElement(TabComponent[tab.value]! || TabComponent.default, { diff --git a/apps/desktop/layer/renderer/src/pages/settings/(settings)/list.tsx b/apps/desktop/layer/renderer/src/pages/settings/(settings)/list.tsx index 54c9fee64..87dcda6a7 100644 --- a/apps/desktop/layer/renderer/src/pages/settings/(settings)/list.tsx +++ b/apps/desktop/layer/renderer/src/pages/settings/(settings)/list.tsx @@ -1,8 +1,6 @@ -import { UserRole } from "@follow/constants" - import { SettingLists } from "~/modules/settings/tabs/lists" import { SettingsTitle } from "~/modules/settings/title" -import { defineSettingPageData, DisableWhy } from "~/modules/settings/utils" +import { defineSettingPageData } from "~/modules/settings/utils" const iconName = "i-mgc-rada-cute-re" const priority = (1000 << 2) + 10 @@ -11,10 +9,6 @@ export const loader = defineSettingPageData({ icon: iconName, name: "titles.lists", priority, - disableIf: (ctx) => [ - ctx.role === UserRole.Free || ctx.role === UserRole.Trial, - DisableWhy.NotActivation, - ], hideIf: (ctx) => ctx.isInMASReview, }) diff --git a/apps/desktop/layer/renderer/src/pages/settings/(settings)/notifications.tsx b/apps/desktop/layer/renderer/src/pages/settings/(settings)/notifications.tsx index 2cc901417..3d202519e 100644 --- a/apps/desktop/layer/renderer/src/pages/settings/(settings)/notifications.tsx +++ b/apps/desktop/layer/renderer/src/pages/settings/(settings)/notifications.tsx @@ -1,8 +1,6 @@ -import { UserRole } from "@follow/constants" - import { SettingNotifications } from "~/modules/settings/tabs/notifications" import { SettingsTitle } from "~/modules/settings/title" -import { defineSettingPageData, DisableWhy } from "~/modules/settings/utils" +import { defineSettingPageData } from "~/modules/settings/utils" const iconName = "i-mgc-notification-cute-re" const priority = (1000 << 1) + 50 @@ -11,10 +9,6 @@ export const loader = defineSettingPageData({ icon: iconName, name: "titles.notifications", priority, - disableIf: (ctx) => [ - ctx.role === UserRole.Free || ctx.role === UserRole.Trial, - DisableWhy.NotActivation, - ], }) export function Component() { diff --git a/apps/desktop/layer/renderer/src/pages/settings/(settings)/plan.tsx b/apps/desktop/layer/renderer/src/pages/settings/(settings)/plan.tsx index 4493c4b13..405ff286e 100644 --- a/apps/desktop/layer/renderer/src/pages/settings/(settings)/plan.tsx +++ b/apps/desktop/layer/renderer/src/pages/settings/(settings)/plan.tsx @@ -3,14 +3,14 @@ import { SettingsTitle } from "~/modules/settings/title" import { defineSettingPageData } from "~/modules/settings/utils" const iconName = "i-mgc-power-outline" -const priority = (1000 << 2) + 30 +const priority = (1000 << 1) + 17 export const loader = defineSettingPageData({ icon: iconName, name: "titles.plan.short", title: "titles.plan.long", priority, - hideIf: (ctx, serverConfigs) => ctx.isInMASReview || !serverConfigs?.REFERRAL_ENABLED, + hideIf: (ctx, serverConfigs) => ctx.isInMASReview || !serverConfigs?.PAYMENT_ENABLED, }) export function Component() { diff --git a/apps/desktop/layer/renderer/src/providers/user-provider.tsx b/apps/desktop/layer/renderer/src/providers/user-provider.tsx index d2cba04f9..0cbb7079d 100644 --- a/apps/desktop/layer/renderer/src/providers/user-provider.tsx +++ b/apps/desktop/layer/renderer/src/providers/user-provider.tsx @@ -1,67 +1,16 @@ -import { UserRole, UserRoleName } from "@follow/constants" -import { getStorageNS } from "@follow/utils/ns" -import { useEffect, useMemo } from "react" -import { toast } from "sonner" +import { useEffect } from "react" import { setIntegrationIdentify } from "~/initialize/helper" -import { useSettingModal } from "~/modules/settings/modal/useSettingModal" import { useSession } from "~/queries/auth" export const UserProvider = () => { const { session } = useSession() - const settingModalPresent = useSettingModal() - useEffect(() => { if (!session?.user) return setIntegrationIdentify(session.user) }, [session?.user]) - const roleEndDate = useMemo( - () => - session?.roleEndAt - ? typeof session.roleEndAt === "string" - ? new Date(session.roleEndAt) - : session.roleEndAt - : undefined, - [session?.roleEndAt], - ) - useEffect(() => { - if (!session?.role) return - - const itemKey = getStorageNS("pro-preview-toast-dismissed") - - const isToastDismissed = localStorage.getItem(itemKey) - - const sessionRole = session.role as string - - if (sessionRole && sessionRole !== UserRole.Pro && !isToastDismissed) { - const message = - sessionRole === UserRole.Free || sessionRole === UserRole.Trial - ? `You are currently on the ${UserRoleName[UserRole.Free]} plan. Some features may be limited.` - : sessionRole === UserRole.PreProTrial - ? `You are currently on the ${UserRoleName[UserRole.PreProTrial]} plan.${roleEndDate ? ` It will end on ${roleEndDate.toLocaleDateString()}.` : ""}` - : "" - if (!message) { - localStorage.setItem(itemKey, "true") - return - } - toast.warning(message, { - duration: Number.POSITIVE_INFINITY, - action: { - label: "More", - onClick: () => { - settingModalPresent("plan") - localStorage.setItem(itemKey, "true") - }, - }, - onDismiss: () => { - localStorage.setItem(itemKey, "true") - }, - }) - } - }, [roleEndDate, session?.role, settingModalPresent]) - return null } diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 0822fd8fa..1133aa751 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -21,6 +21,7 @@ "@better-auth/expo": "1.3.28", "@expo/metro-runtime": "5.0.4", "@expo/react-native-action-sheet": "4.1.1", + "@follow-app/client-sdk": "catalog:", "@follow/components": "workspace:*", "@follow/constants": "workspace:*", "@follow/database": "workspace:*", diff --git a/apps/mobile/src/lib/error-parser.ts b/apps/mobile/src/lib/error-parser.ts index aa06abfc8..d4f09a9cf 100644 --- a/apps/mobile/src/lib/error-parser.ts +++ b/apps/mobile/src/lib/error-parser.ts @@ -1,3 +1,4 @@ +import { FollowAPIError } from "@follow-app/client-sdk" import { t } from "i18next" import { FetchError } from "ofetch" @@ -25,6 +26,20 @@ export const getFetchErrorInfo = ( } } + if (error instanceof FollowAPIError && error.code) { + const code = Number(error.code) + try { + const i18nKey = `errors:${code}` as any + const i18nMessage = t(i18nKey) === i18nKey ? error.message : t(i18nKey) + return { + message: i18nMessage, + code, + } + } catch { + return { message: error.message } + } + } + return { message: error.message } } @@ -67,6 +82,17 @@ export const toastFetchError = (error: Error, { title: _title }: { title?: strin } } + if (error instanceof FollowAPIError && error.code) { + code = Number(error.code) + try { + const tValue = t(`errors:${code}` as any) + const i18nMessage = tValue === code?.toString() ? error.message : tValue + message = i18nMessage + } catch { + message = error.message + } + } + // 2fa errors are handled by the form if (code === 4007 || code === 4008) { return diff --git a/apps/mobile/src/modules/settings/routes/Actions.tsx b/apps/mobile/src/modules/settings/routes/Actions.tsx index 6dce7435f..95089908c 100644 --- a/apps/mobile/src/modules/settings/routes/Actions.tsx +++ b/apps/mobile/src/modules/settings/routes/Actions.tsx @@ -31,6 +31,7 @@ import { Switch } from "@/src/components/ui/switch/Switch" import { Text } from "@/src/components/ui/typography/Text" import { Book6CuteReIcon } from "@/src/icons/book_6_cute_re" import { Magic2CuteFiIcon } from "@/src/icons/magic_2_cute_fi" +import { toastFetchError } from "@/src/lib/error-parser" import { useNavigation } from "@/src/lib/navigation/hooks" import { toast } from "@/src/lib/toast" import { accentColor } from "@/src/theme/colors" @@ -129,8 +130,8 @@ const SaveRuleButton = ({ disabled }: { disabled?: boolean }) => { navigation.back() toast.success("Actions saved") }, - onError(errorMessage) { - toast.error(errorMessage) + onError(error) { + toastFetchError(error) }, }) return ( diff --git a/apps/mobile/src/modules/settings/routes/Plan.tsx b/apps/mobile/src/modules/settings/routes/Plan.tsx index 2fe8c1c26..9233becca 100644 --- a/apps/mobile/src/modules/settings/routes/Plan.tsx +++ b/apps/mobile/src/modules/settings/routes/Plan.tsx @@ -7,22 +7,17 @@ import type { ProductPurchase } from "expo-iap" import { useIAP } from "expo-iap" import { openURL } from "expo-linking" import { useEffect } from "react" -import { Trans, useTranslation } from "react-i18next" -import { Linking, Pressable, View } from "react-native" +import { useTranslation } from "react-i18next" +import { Pressable, View } from "react-native" import { useServerConfigs } from "@/src/atoms/server-configs" import { NavigationBlurEffectHeaderView, SafeNavigationScrollView, } from "@/src/components/layouts/views/SafeNavigationScrollView" -import { - GroupedInformationCell, - GroupedInsetListCard, -} from "@/src/components/ui/grouped/GroupedList" // Plan configuration types import { Text } from "@/src/components/ui/typography/Text" import { CheckLineIcon } from "@/src/icons/check_line" -import { PowerOutlineIcon } from "@/src/icons/power_outline" import { TimeCuteReIcon } from "@/src/icons/time_cute_re" import { followClient } from "@/src/lib/api-client" import { authClient } from "@/src/lib/auth" @@ -30,7 +25,6 @@ import { useNavigation } from "@/src/lib/navigation/hooks" import type { NavigationControllerView } from "@/src/lib/navigation/types" import { isIOS } from "@/src/lib/platform" import { proxyEnv } from "@/src/lib/proxy-env" -import { accentColor } from "@/src/theme/colors" import { ReferralScreen } from "./Referral" @@ -55,6 +49,7 @@ const PLAN_TIER_MAP: Record = { // Same as Free (deprecated) [UserRole.PreProTrial]: 2, [UserRole.Pro]: 3, + [UserRole.Plus]: 4, } // Plan configurations @@ -129,7 +124,6 @@ export const PlanScreen: NavigationControllerView = () => { const navigation = useNavigation() const { t } = useTranslation("settings") const serverConfigs = useServerConfigs() - const ruleLink = serverConfigs?.REFERRAL_RULE_LINK const requiredInvitationsAmount = serverConfigs?.REFERRAL_REQUIRED_INVITATIONS || 3 const { data: referralInfo } = useReferralInfoQuery() const validInvitationsAmount = referralInfo?.invitations.filter((i) => i.usedAt).length || 0 @@ -165,40 +159,6 @@ export const PlanScreen: NavigationControllerView = () => { className="bg-system-grouped-background" Header={} > - - - } - iconBackgroundColor={accentColor} - > - ( - - {children} - - )} - components={{ - Link: ( - { - if (ruleLink) { - Linking.openURL(ruleLink) - } - }} - > - Learn more - - ), - }} - /> - - - - {PLAN_CONFIGS.map((plan) => { const isProPreview = plan.id === "pro-preview" diff --git a/locales/app/en.json b/locales/app/en.json index b884c6a01..603f67432 100644 --- a/locales/app/en.json +++ b/locales/app/en.json @@ -25,6 +25,7 @@ "activation.plan.upgrade": "Upgrade", "activation.title": "Invitation Code", "ai.summary_not_available": "Summary not available", + "ai.summary_upgrade_required_title": "Upgrade plan to continue using AI summary", "app.copy_logo_svg": "Copy Logo SVG", "app.copy_logo_text_svg": "Copy Logo Text SVG", "app.toggle_sidebar": "Toggle Sidebar", diff --git a/locales/settings/en.json b/locales/settings/en.json index 9c63cc1ec..8bdc81330 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -212,6 +212,8 @@ "appearance.use_pointer_cursor.label": "Use Hand Cursor", "appearance.words.customize": "Customize", "common.give_star": "Love our product? Give us a star on GitHub!", + "control.paid_badge.free_limited": "This feature is limited for free plan", + "control.paid_badge.plus_or_higher": "This feature requires a Plus plan or higher to use", "customizeToolbar.more_actions.description": "Will be shown in the dropdown menu.", "customizeToolbar.more_actions.title": "More Actions", "customizeToolbar.quick_actions.description": "Customize and reorder your frequently used actions.", @@ -553,7 +555,23 @@ "notifications.test": "Test Notification", "notifications.test_success": "Test notification sent successfully.", "notifications.token": "Client Token", - "plan.description": "Enjoy every Pro feature from day one—new users get a full‑access trial, and you can keep those perks simply by inviting friends or making a small support contribution. Learn more.", + "plan.descriptions.free": "Great for beginners.", + "plan.descriptions.plus": "Unlock AI features and more feeds.", + "plan.descriptions.pro": "Full access to the best of Folo.", + "plan.features.AI_CREDIT": "AI Credits", + "plan.features.AI_ENTRY_TRANSLATION": "AI Entry Translation", + "plan.features.BOOSTS": "Feed Boosts", + "plan.features.INTEGRATION_SUPPORTED": "Third-Party Integrations", + "plan.features.MAX_ACTIONS": "Actions", + "plan.features.MAX_AI_ENTRY_SUMMARY_PER_DAY": "AI Summaries Per Day", + "plan.features.MAX_AI_REQUESTS_PER_DAY": "AI Requests Per Day", + "plan.features.MAX_AI_TASKS": "AI Tasks", + "plan.features.MAX_INBOXES": "Inbox", + "plan.features.MAX_LISTS": "List", + "plan.features.MAX_RSSHUB_SUBSCRIPTIONS": "RSSHub Subscriptions", + "plan.features.MAX_SUBSCRIPTIONS": "Feed Subscriptions", + "plan.features.PRIORITY_SUPPORT": "Priority Support", + "plan.features.PRIVATE_SUBSCRIPTION": "Private Subscriptions", "privacy.privacy": "Privacy", "privacy.terms": "Terms", "profile.avatar.cropInstructions": "Drag the crop area to adjust your avatar", diff --git a/locales/settings/ja.json b/locales/settings/ja.json index 7321ac9ae..d58ac133f 100644 --- a/locales/settings/ja.json +++ b/locales/settings/ja.json @@ -208,6 +208,8 @@ "appearance.use_pointer_cursor.description": "マウスがインタラクティブな要素の上にあるとき、カーソルは手の形になります。", "appearance.use_pointer_cursor.label": "手の形のカーソルを使用する", "common.give_star": "私たちの製品が好きですか?GitHub で Star を付けましょう!", + "control.paid_badge.free_limited": "この機能は無料プランでは制限されています", + "control.paid_badge.plus_or_higher": "この機能を利用するには Plus プラン以上が必要です", "customizeToolbar.more_actions.description": "ドロップダウンメニューに表示されます", "customizeToolbar.more_actions.title": "その他のアクション", "customizeToolbar.quick_actions.description": "よく使用するアクションをカスタマイズして並べ替える。", @@ -549,7 +551,20 @@ "notifications.test": "テスト通知", "notifications.test_success": "テスト通知が正常に送信されました。", "notifications.token": "クライアントトークン", - "plan.description": "すべての Pro 機能を初日から利用できます。新しいユーザーはフルアクセスのトライアルを受け取ります。友達を招待するか、少額のサポート寄付をすることで、その特典を維持できます。詳細はこちら。", + "plan.features.AI_CREDIT": "AI クレジット", + "plan.features.AI_ENTRY_TRANSLATION": "AI エントリ翻訳", + "plan.features.BOOSTS": "購読フィードの加速", + "plan.features.INTEGRATION_SUPPORTED": "サードパーティ統合", + "plan.features.MAX_ACTIONS": "自動化アクション", + "plan.features.MAX_AI_ENTRY_SUMMARY_PER_DAY": "1日あたりのAI要約数", + "plan.features.MAX_AI_REQUESTS_PER_DAY": "1日あたりのAIリクエスト数", + "plan.features.MAX_AI_TASKS": "AI タスク", + "plan.features.MAX_INBOXES": "受信トレイフィード", + "plan.features.MAX_LISTS": "カスタムリスト", + "plan.features.MAX_RSSHUB_SUBSCRIPTIONS": "RSSHub サブスクリプション", + "plan.features.MAX_SUBSCRIPTIONS": "フィードサブスクリプション", + "plan.features.PRIORITY_SUPPORT": "優先サポート", + "plan.features.PRIVATE_SUBSCRIPTION": "プライベートサブスクリプション", "privacy.privacy": "プライバシー", "privacy.terms": "利用規約", "profile.avatar.cropInstructions": "ドラッグしてトリミングエリアを調整します", diff --git a/locales/settings/zh-CN.json b/locales/settings/zh-CN.json index e576fdf7b..52026381c 100644 --- a/locales/settings/zh-CN.json +++ b/locales/settings/zh-CN.json @@ -208,6 +208,8 @@ "appearance.use_pointer_cursor.description": "当鼠标悬停在任何可交互元素上时,光标会显示为手型光标。", "appearance.use_pointer_cursor.label": "使用手型光标", "common.give_star": "喜欢我们的产品吗? 在 GitHub 上给我们「Star」吧!", + "control.paid_badge.free_limited": "此功能在免费计划中有限制", + "control.paid_badge.plus_or_higher": "此功能需要 Plus 计划或更高级别才能使用", "customizeToolbar.more_actions.description": "将显示在下拉菜单中", "customizeToolbar.more_actions.title": "更多操作", "customizeToolbar.quick_actions.description": "自定义并重新排列您常用的操作", @@ -549,7 +551,20 @@ "notifications.test": "测试通知", "notifications.test_success": "测试通知发送成功。", "notifications.token": "客户端令牌", - "plan.description": "从第一天起享受所有专业版功能——新用户可获得完整试用,只需邀请朋友或小额支持贡献即可保留这些权益。了解更多。", + "plan.features.AI_CREDIT": "AI 积分", + "plan.features.AI_ENTRY_TRANSLATION": "AI 条目翻译", + "plan.features.BOOSTS": "订阅源加速", + "plan.features.INTEGRATION_SUPPORTED": "第三方集成", + "plan.features.MAX_ACTIONS": "自动化操作", + "plan.features.MAX_AI_ENTRY_SUMMARY_PER_DAY": "每日 AI 摘要次数", + "plan.features.MAX_AI_REQUESTS_PER_DAY": "每日 AI 请求次数", + "plan.features.MAX_AI_TASKS": "AI 任务", + "plan.features.MAX_INBOXES": "收件箱订阅源", + "plan.features.MAX_LISTS": "自定义列表", + "plan.features.MAX_RSSHUB_SUBSCRIPTIONS": "RSSHub 订阅", + "plan.features.MAX_SUBSCRIPTIONS": "订阅源数量", + "plan.features.PRIORITY_SUPPORT": "优先支持", + "plan.features.PRIVATE_SUBSCRIPTION": "私有订阅", "privacy.privacy": "隐私政策", "privacy.terms": "服务条款", "profile.avatar.cropInstructions": "拖动裁剪区域以调整头像", diff --git a/locales/settings/zh-TW.json b/locales/settings/zh-TW.json index 170d06a6d..8379295ae 100644 --- a/locales/settings/zh-TW.json +++ b/locales/settings/zh-TW.json @@ -212,6 +212,8 @@ "appearance.use_pointer_cursor.label": "使用手指遊標", "appearance.words.customize": "自訂", "common.give_star": "喜歡我們的產品嗎? 在 GitHub 上給我們 Star 吧!", + "control.paid_badge.free_limited": "此功能在免費方案中受限", + "control.paid_badge.plus_or_higher": "此功能需要 Plus 方案或更高級別才能使用", "customizeToolbar.more_actions.description": "將顯示在下拉選單中", "customizeToolbar.more_actions.title": "更多操作", "customizeToolbar.quick_actions.description": "自訂並重新排列您常用的操作", @@ -553,7 +555,6 @@ "notifications.test": "測試通知", "notifications.test_success": "測試通知發送成功。", "notifications.token": "客户端令牌", - "plan.description": "享受每個專業功能,從第一天開始 — 新用戶獲得完整訪問試用,您可以通過邀請朋友或進行小額支持貢獻來保留這些特權。了解更多。", "privacy.privacy": "隱私政策", "privacy.terms": "服務條款", "profile.avatar.cropInstructions": "拖曳裁切區域以調整你的頭像", diff --git a/packages/internal/atoms/package.json b/packages/internal/atoms/package.json index 185a0a057..8c982271a 100644 --- a/packages/internal/atoms/package.json +++ b/packages/internal/atoms/package.json @@ -17,7 +17,10 @@ }, "dependencies": { "@follow/configs": "workspace:*", + "@follow/constants": "workspace:*", "@follow/hooks": "workspace:*", + "@follow/shared": "workspace:*", + "@follow/store": "workspace:*", "@follow/types": "workspace:*", "@follow/utils": "workspace:*", "jotai": "2.15.0" diff --git a/packages/internal/atoms/src/helper/setting.ts b/packages/internal/atoms/src/helper/setting.ts index 3c7a8f899..2f314f995 100644 --- a/packages/internal/atoms/src/helper/setting.ts +++ b/packages/internal/atoms/src/helper/setting.ts @@ -1,4 +1,7 @@ +import { UserRole } from "@follow/constants" import { useRefValue } from "@follow/hooks" +import { getSettingPaidLevel, SettingPaidLevels } from "@follow/shared/settings/constants" +import { useUserStore } from "@follow/store/user/store" import { EventBus } from "@follow/utils/event-bus" import { createAtomHooks } from "@follow/utils/jotai" import { getStorageNS } from "@follow/utils/ns" @@ -25,21 +28,66 @@ export const createSettingAtom = ( getOnInit: true, }) - const [, , useSettingValue, , getSettings, setSettings] = createAtomHooks(atom) + const [, , useSettingValueRaw, , getSettingsRaw, setSettings] = createAtomHooks(atom) const initializeDefaultSettings = () => { - const currentSettings = getSettings() + const currentSettings = getSettingsRaw() const defaultSettings = createDefaultSettings() if (typeof currentSettings !== "object") setSettings(defaultSettings) const newSettings = { ...defaultSettings, ...currentSettings } setSettings(newSettings) } - const selectAtomCacheMap = {} as Record, any> + const selectAtomCacheMap = {} as Record, any> const noopAtom = jotaiAtom(null) - const useMaybeSettingKey = >(key: Nullable) => { + const canUpdatePaidSetting = (requiredLevel?: SettingPaidLevels) => { + if (requiredLevel === undefined) return true + if ( + requiredLevel === SettingPaidLevels.Free || + requiredLevel === SettingPaidLevels.FreeLimited + ) { + return true + } + const role = useUserStore.getState().role ?? UserRole.Free + return role !== UserRole.Free && role !== UserRole.Trial + } + + const resolveAccessibleValue = ( + key: string, + value: unknown, + defaults: Record, + ) => { + const requiredLevel = getSettingPaidLevel(settingKey, key) + if (requiredLevel === undefined || canUpdatePaidSetting(requiredLevel)) { + return value + } + if (Object.prototype.hasOwnProperty.call(defaults, key)) { + return defaults[key] + } + return value + } + + const sanitizeSettingsSnapshot = (settings: ReturnType) => { + const defaults = createDefaultSettings() as Record + const raw = settings as Record + let sanitized: Record | null = null + + for (const key of Object.keys(defaults)) { + const safeValue = resolveAccessibleValue(key, raw[key], defaults) + if (safeValue !== raw[key]) { + if (!sanitized) sanitized = { ...raw } + sanitized[key] = safeValue + } + } + + return (sanitized ?? raw) as ReturnType + } + + const useMaybeSettingKey = >( + key: Nullable, + ) => { // @ts-expect-error let selectedAtom: Record[T] | null = null if (key) { @@ -52,15 +100,20 @@ export const createSettingAtom = ( selectedAtom = noopAtom } - return useAtomValue(selectedAtom) as ReturnType[T] + const value = useAtomValue(selectedAtom) as ReturnType[T] + if (!key) return value + const defaults = createDefaultSettings() as Record + return resolveAccessibleValue(String(key), value, defaults) as ReturnType< + typeof getSettingsRaw + >[T] } - const useSettingKey = >(key: T) => { - return useMaybeSettingKey(key) as ReturnType[T] + const useSettingKey = >(key: T) => { + return useMaybeSettingKey(key) as ReturnType[T] } function useSettingKeys< - T extends keyof ReturnType, + T extends keyof ReturnType, K1 extends T, K2 extends T, K3 extends T, @@ -84,22 +137,22 @@ export const createSettingAtom = ( useMaybeSettingKey(keys[8]), useMaybeSettingKey(keys[9]), ] as [ - ReturnType[K1], - ReturnType[K2], - ReturnType[K3], - ReturnType[K4], - ReturnType[K5], - ReturnType[K6], - ReturnType[K7], - ReturnType[K8], - ReturnType[K9], - ReturnType[K10], + ReturnType[K1], + ReturnType[K2], + ReturnType[K3], + ReturnType[K4], + ReturnType[K5], + ReturnType[K6], + ReturnType[K7], + ReturnType[K8], + ReturnType[K9], + ReturnType[K10], ] } const useSettingSelector = < - T extends keyof ReturnType, - S extends ReturnType, + T extends keyof ReturnType, + S extends ReturnType, R = S[T], >( selector: (s: S) => R, @@ -107,18 +160,29 @@ export const createSettingAtom = ( const stableSelector = useRefValue(selector) return useAtomValue( - // @ts-expect-error - useMemo(() => selectAtom(atom, stableSelector.current, shallow), [stableSelector]), + useMemo( + () => + selectAtom( + atom, + (state) => stableSelector.current(sanitizeSettingsSnapshot(state) as S), + shallow, + ), + [stableSelector], + ), ) } - const setSetting = >( + const setSetting = >( key: K, - value: ReturnType[K], + value: ReturnType[K], ) => { + const requiredLevel = getSettingPaidLevel(settingKey, String(key)) + if (!canUpdatePaidSetting(requiredLevel)) { + return + } const updated = Date.now() setSettings({ - ...getSettings(), + ...getSettingsRaw(), [key]: value, updated, @@ -135,6 +199,15 @@ export const createSettingAtom = ( setSettings(createDefaultSettings()) } + const useSettingValue = () => { + const value = useSettingValueRaw() + return useMemo(() => sanitizeSettingsSnapshot(value), [value]) + } + + const getSettings = () => { + return sanitizeSettingsSnapshot(getSettingsRaw()) + } + Object.defineProperty(useSettingValue, "select", { value: useSettingSelector, }) diff --git a/packages/internal/constants/src/enums.ts b/packages/internal/constants/src/enums.ts index 2cd116221..e1b51392e 100644 --- a/packages/internal/constants/src/enums.ts +++ b/packages/internal/constants/src/enums.ts @@ -15,6 +15,7 @@ export enum UserRole { // TODO: remove this Trial = "trial", Pro = "pro", + Plus = "plus", } export const UserRoleName: Record = { @@ -27,4 +28,5 @@ export const UserRoleName: Record = { */ [UserRole.Trial]: "Free", [UserRole.Pro]: "Pro", + [UserRole.Plus]: "Plus", } as const diff --git a/packages/internal/shared/src/settings/constants.ts b/packages/internal/shared/src/settings/constants.ts index 88e7800ba..34e2b6c66 100644 --- a/packages/internal/shared/src/settings/constants.ts +++ b/packages/internal/shared/src/settings/constants.ts @@ -1,4 +1,57 @@ -import type { AccentColor } from "./interface" +import type { + AccentColor, + AISettings, + GeneralSettings, + IntegrationSettings, + UISettings, +} from "./interface" + +export enum SettingPaidLevels { + Free, + FreeLimited, + Plus, +} + +type PartialRecord = Partial> + +export const PAID_SETTINGS = { + general: { + summary: SettingPaidLevels.FreeLimited, + translation: SettingPaidLevels.Plus, + translationMode: SettingPaidLevels.Plus, + hidePrivateSubscriptionsInTimeline: SettingPaidLevels.Plus, + }, + ui: { + hideExtraBadge: SettingPaidLevels.Plus, + hideRecentReader: SettingPaidLevels.Plus, + }, + integration: { + enableCubox: SettingPaidLevels.Plus, + enableObsidian: SettingPaidLevels.Plus, + enableOutline: SettingPaidLevels.Plus, + enableReadwise: SettingPaidLevels.Plus, + enableZotero: SettingPaidLevels.Plus, + enableInstapaper: SettingPaidLevels.Plus, + enableReadeck: SettingPaidLevels.Plus, + enableEagle: SettingPaidLevels.Plus, + enableQBittorrent: SettingPaidLevels.Plus, + enableCustomIntegration: SettingPaidLevels.Plus, + }, + ai: {}, +} as const satisfies { + general: PartialRecord + ui: PartialRecord + integration: PartialRecord + ai: PartialRecord +} + +export type SettingNamespace = keyof typeof PAID_SETTINGS + +export const getSettingPaidLevel = (namespace: string, key: string) => { + const group = PAID_SETTINGS[namespace as keyof typeof PAID_SETTINGS] + if (!group) return + return group[key as keyof typeof group] +} const ACCENT_COLOR_MAP = { orange: { @@ -40,5 +93,6 @@ export const getAccentColorValue = (color: AccentColor) => { if (color.startsWith("#")) { return { light: color, dark: color } } - return ACCENT_COLOR_MAP[color] || ACCENT_COLOR_MAP.orange + const preset = ACCENT_COLOR_MAP[color as keyof typeof ACCENT_COLOR_MAP] + return preset || ACCENT_COLOR_MAP.orange } diff --git a/packages/internal/store/src/modules/action/hooks.ts b/packages/internal/store/src/modules/action/hooks.ts index 448e7703a..c9a25b586 100644 --- a/packages/internal/store/src/modules/action/hooks.ts +++ b/packages/internal/store/src/modules/action/hooks.ts @@ -1,6 +1,5 @@ import type { ActionConditionIndex } from "@follow-app/client-sdk" import { useMutation, useQuery } from "@tanstack/react-query" -import { FetchError } from "ofetch" import { useCallback } from "react" import type { GeneralMutationOptions } from "../../types" @@ -16,19 +15,8 @@ export const usePrefetchActions = () => { export const useUpdateActionsMutation = (options?: GeneralMutationOptions) => { return useMutation({ + ...options, mutationFn: () => actionSyncService.saveRules(), - onSuccess() { - options?.onSuccess?.() - }, - onError(err) { - if (err instanceof FetchError && err.response?._data) { - const { message } = err.response._data - options?.onError?.(message) - return - } - - options?.onError?.("Error saving actions") - }, }) } diff --git a/packages/internal/store/src/types.ts b/packages/internal/store/src/types.ts index 6c8c36fff..913f363f8 100644 --- a/packages/internal/store/src/types.ts +++ b/packages/internal/store/src/types.ts @@ -2,7 +2,7 @@ import type { ModuleAPIs } from "@follow-app/client-sdk" export type GeneralMutationOptions = { onSuccess?: () => void - onError?: (errorMessage: string) => void + onError?: (errorMessage: Error) => void } export type GeneralQueryOptions = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d13248dd5..d1a01d279 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ settings: catalogs: default: '@follow-app/client-sdk': - specifier: 0.3.76 - version: 0.3.76 + specifier: 0.3.77 + version: 0.3.77 tailwindcss-uikit-colors: specifier: 1.0.0 version: 1.0.0 @@ -339,7 +339,7 @@ importers: version: 4.3.0 '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow-app/readability': specifier: workspace:* version: link:../../../../packages/readability @@ -457,7 +457,7 @@ importers: version: 3.0.2(electron@38.3.0) '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/database': specifier: workspace:* version: link:../../../../packages/internal/database @@ -807,6 +807,9 @@ importers: '@expo/react-native-action-sheet': specifier: 4.1.1 version: 4.1.1(react@19.0.0) + '@follow-app/client-sdk': + specifier: 'catalog:' + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/components': specifier: workspace:* version: link:../../packages/internal/components @@ -1187,7 +1190,7 @@ importers: version: 6.2.1 '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/tracker': specifier: workspace:* version: link:../../packages/internal/tracker @@ -1427,9 +1430,18 @@ importers: '@follow/configs': specifier: workspace:* version: link:../../configs + '@follow/constants': + specifier: workspace:* + version: link:../constants '@follow/hooks': specifier: workspace:* version: link:../hooks + '@follow/shared': + specifier: workspace:* + version: link:../shared + '@follow/store': + specifier: workspace:* + version: link:../store '@follow/types': specifier: workspace:* version: link:../types @@ -1673,7 +1685,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/configs': specifier: workspace:* version: link:../../configs @@ -1685,7 +1697,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/constants': specifier: workspace:* version: link:../constants @@ -1757,7 +1769,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/constants': specifier: workspace:* version: link:../constants @@ -1788,7 +1800,7 @@ importers: version: 2.0.0(@types/node@24.8.1) '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@folo-services/drizzle': specifier: 0.1.34 version: 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) @@ -1818,7 +1830,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/configs': specifier: workspace:* version: link:../../configs @@ -1867,7 +1879,7 @@ importers: devDependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@follow/configs': specifier: workspace:* version: link:../../configs @@ -4343,23 +4355,29 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@follow-app/client-sdk@0.3.76': - resolution: {integrity: sha512-cVZgG8BTXoqEomE+WzxrT47O1SYJEY1YDLI+InQuku/L2mQcwZCxxYJbPUicNIcH4b3smj7c+E4qr7QJGwgchg==} + '@follow-app/client-sdk@0.3.77': + resolution: {integrity: sha512-zr1FneNho5/wdDn2UWcjixlUf29kxbUqKXGnlvjJ6TOUJrygF8bh8GshgoHEkNj+4JUwMKo+WUtimyx6QpRrag==} '@folo-services/ai-tools@0.2.49': resolution: {integrity: sha512-QsKTW8N18812Thkdcc7wDTff3QkQxxTYHxHi1RM321jk4DbCq+mHlAr10Krwj0mRtKuULtqFHPm13udmfIv1Bw==} - '@folo-services/constants@0.1.40': - resolution: {integrity: sha512-sAYr/I+dlBrgQKTy085Xjler64wawOneeqvU5SYOugwf36RpWvVtz1aTo0KdiF1+M7gM1W+G1vkfnXAzOeBEaA==} + '@folo-services/constants@0.1.41': + resolution: {integrity: sha512-fXJ5DVWMgc4czW8i9JmVx3WckKhUksiwXkzzOClH0GePEOeS+DQ08o21UfZl1pBvhvhZm0pS+klHLljeBaRb1g==} '@folo-services/drizzle@0.1.34': resolution: {integrity: sha512-p6dsveNwXwNxmy+8+FHHKiFjVFXwc7yx7c4902k13hd1vcBihxiWUD4MdCwAcQTAPSJ3dYx1UZojHSdyiXwqnw==} + '@folo-services/drizzle@0.1.35': + resolution: {integrity: sha512-b+5OPwjKW3gnf0lkLj7PuhjLCldD9TItXNWRwIvJrPYmIGlrQmUiKgQIuLR8dsksF9L7w8IcIi4Vt40Qppx7nQ==} + '@folo-services/exceptions@0.1.19': resolution: {integrity: sha512-rXgLssE3r3w2WzC3knCX9nYe0cszHXpYwAllrYOsPpzjQSHWRwJ6LuJyt0xlvdeX/9i8KQ/UYgf4to6Abt2whg==} - '@folo-services/shared@0.0.33': - resolution: {integrity: sha512-fN4tp7Euum0XyTfrNLPdkxqUwTxHOOYq15vSJm/xqVGZxMQx9DTwtZasydEGVzns9zqnb7HlrkjjvG7kxlJdXA==} + '@folo-services/exceptions@0.1.20': + resolution: {integrity: sha512-iuV6F22XI6kvSSVQRTCoS/wfJnPGvI3XQbA3YQGgXa8fT28SE+8LBGCyAj0rqbfnXlXdpxZE/IooXdpJyxkp0Q==} + + '@folo-services/shared@0.0.34': + resolution: {integrity: sha512-T0gZRBlDVP9WLG0Dg8tLgWdk+TVjbdKfSvRHEyBY+YioQ1LO4vulN8ddCv1oBvMQxl0iESY9mnmB4ua9iGGkyQ==} '@fontsource/sn-pro@5.2.5': resolution: {integrity: sha512-rBdBv/0ygj6bkO7xDMMFpwobLdSrcQ2Jncb6DIwdeYGoAgeWkQRwVYhGDKasfLjEYCNYxrqr6wsXsM9+aU39RA==} @@ -21312,12 +21330,12 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@follow-app/client-sdk@0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@follow-app/client-sdk@0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@folo-services/constants': 0.1.40 - '@folo-services/drizzle': 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) - '@folo-services/exceptions': 0.1.19 - '@folo-services/shared': 0.0.33(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/exceptions': 0.1.20 + '@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) zod: 4.1.12 transitivePeerDependencies: @@ -21361,12 +21379,12 @@ snapshots: - svelte - vue - '@follow-app/client-sdk@0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@follow-app/client-sdk@0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@folo-services/constants': 0.1.40 - '@folo-services/drizzle': 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) - '@folo-services/exceptions': 0.1.19 - '@folo-services/shared': 0.0.33(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/exceptions': 0.1.20 + '@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) zod: 4.1.12 transitivePeerDependencies: @@ -21410,12 +21428,61 @@ snapshots: - svelte - vue - '@follow-app/client-sdk@0.3.76(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@follow-app/client-sdk@0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@folo-services/constants': 0.1.40 - '@folo-services/drizzle': 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) - '@folo-services/exceptions': 0.1.19 - '@folo-services/shared': 0.0.33(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/exceptions': 0.1.20 + '@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) + better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + zod: 4.1.12 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@lynx-js/react' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@sveltejs/kit' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - hono + - knex + - kysely + - mysql2 + - next + - pg + - pg-native + - postgres + - prisma + - react + - react-dom + - solid-js + - sql.js + - sqlite3 + - svelte + - vue + + '@follow-app/client-sdk@0.3.77(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/exceptions': 0.1.20 + '@folo-services/shared': 0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3) better-auth: 1.3.28(better-sqlite3@12.4.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) zod: 4.1.12 transitivePeerDependencies: @@ -21499,7 +21566,7 @@ snapshots: - sql.js - sqlite3 - '@folo-services/constants@0.1.40': + '@folo-services/constants@0.1.41': dependencies: zod: 4.1.12 @@ -21544,47 +21611,6 @@ snapshots: - sql.js - sqlite3 - '@folo-services/drizzle@0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)': - dependencies: - '@folo-services/exceptions': 0.1.19 - '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) - drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) - drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) - nanoid: 5.1.6 - pg: 8.16.3 - zod: 4.1.12 - transitivePeerDependencies: - - '@aws-sdk/client-rds-data' - - '@cloudflare/workers-types' - - '@electric-sql/pglite' - - '@libsql/client' - - '@libsql/client-wasm' - - '@neondatabase/serverless' - - '@op-engineering/op-sqlite' - - '@opentelemetry/api' - - '@planetscale/database' - - '@prisma/client' - - '@tidbcloud/serverless' - - '@types/better-sqlite3' - - '@types/pg' - - '@types/sql.js' - - '@upstash/redis' - - '@vercel/postgres' - - '@xata.io/client' - - better-sqlite3 - - bun-types - - expo-sqlite - - gel - - hono - - knex - - kysely - - mysql2 - - pg-native - - postgres - - prisma - - sql.js - - sqlite3 - '@folo-services/drizzle@0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)': dependencies: '@folo-services/exceptions': 0.1.19 @@ -21626,11 +21652,178 @@ snapshots: - sql.js - sqlite3 + '@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)': + dependencies: + '@folo-services/exceptions': 0.1.20 + '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) + drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) + drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) + nanoid: 5.1.6 + pg: 8.16.3 + zod: 4.1.12 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - hono + - knex + - kysely + - mysql2 + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + + '@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)': + dependencies: + '@folo-services/exceptions': 0.1.20 + '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) + drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) + drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) + nanoid: 5.1.6 + pg: 8.16.3 + zod: 4.1.12 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - hono + - knex + - kysely + - mysql2 + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + + '@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)': + dependencies: + '@folo-services/exceptions': 0.1.20 + '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) + drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) + drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) + nanoid: 5.1.6 + pg: 8.16.3 + zod: 4.1.12 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - hono + - knex + - kysely + - mysql2 + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + + '@folo-services/drizzle@0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)': + dependencies: + '@folo-services/exceptions': 0.1.20 + '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) + drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) + drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) + nanoid: 5.1.6 + pg: 8.16.3 + zod: 4.1.12 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - hono + - knex + - kysely + - mysql2 + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + '@folo-services/exceptions@0.1.19': {} - '@folo-services/shared@0.0.33(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': + '@folo-services/exceptions@0.1.20': {} + + '@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': dependencies: - '@folo-services/drizzle': 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) @@ -21668,9 +21861,51 @@ snapshots: - sql.js - sqlite3 - '@folo-services/shared@0.0.33(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': + '@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': dependencies: - '@folo-services/drizzle': 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) + drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) + drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) + zod: 4.1.12 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - hono + - knex + - kysely + - mysql2 + - pg + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + + '@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': + dependencies: + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) @@ -21708,9 +21943,10 @@ snapshots: - sql.js - sqlite3 - '@folo-services/shared@0.0.33(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': + '@folo-services/shared@0.0.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8)(pg@8.16.3)': dependencies: - '@folo-services/drizzle': 0.1.34(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) + '@folo-services/constants': 0.1.41 + '@folo-services/drizzle': 0.1.35(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(hono@4.9.8)(kysely@0.28.8) '@hono/zod-openapi': 1.1.4(hono@4.9.8)(zod@4.1.12) drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) drizzle-zod: 0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12) @@ -24103,7 +24339,7 @@ snapshots: debug: 2.6.9 invariant: 2.2.4 metro: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) - metro-config: 0.82.4(bufferutil@4.0.9) + metro-config: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) metro-core: 0.82.4 semver: 7.7.3 transitivePeerDependencies: @@ -27953,6 +28189,15 @@ snapshots: kysely: 0.28.8 pg: 8.16.3 + drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3): + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/pg': 8.15.5 + better-sqlite3: 12.4.1 + expo-sqlite: 15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0) + kysely: 0.28.8 + pg: 8.16.3 + drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3): optionalDependencies: '@opentelemetry/api': 1.9.0 @@ -27994,6 +28239,11 @@ snapshots: drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.0)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) zod: 4.1.12 + drizzle-zod@0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12): + dependencies: + drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.4)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) + zod: 4.1.12 + drizzle-zod@0.8.3(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3))(zod@4.1.12): dependencies: drizzle-orm: 0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(better-sqlite3@12.4.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.5)(@expo/metro-runtime@5.0.4(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.16.0(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0)(utf-8-validate@6.0.5))(react-native@0.79.6(@babel/core@7.28.5)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@6.0.5))(react@19.0.0))(kysely@0.28.8)(pg@8.16.3) @@ -32222,6 +32472,22 @@ snapshots: - supports-color - utf-8-validate + metro-config@0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5): + dependencies: + connect: 3.7.0 + cosmiconfig: 5.2.1 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) + metro-cache: 0.82.4 + metro-core: 0.82.4 + metro-runtime: 0.82.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + optional: true + metro-core@0.82.4: dependencies: flow-enums-runtime: 0.0.6 @@ -32407,7 +32673,7 @@ snapshots: metro-babel-transformer: 0.82.4 metro-cache: 0.82.4 metro-cache-key: 0.82.4 - metro-config: 0.82.4(bufferutil@4.0.9) + metro-config: 0.82.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) metro-core: 0.82.4 metro-file-map: 0.82.4 metro-resolver: 0.82.4 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a65e47652..3cf6dba2a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,7 +8,7 @@ packages: - "!**/example/**" catalog: - "@follow-app/client-sdk": 0.3.76 + "@follow-app/client-sdk": 0.3.77 tailwindcss-uikit-colors: 1.0.0 typescript: 5.9.3