From 5fb37c326ac9c40d2f748b79abb7c5f7c125b052 Mon Sep 17 00:00:00 2001 From: M3gA-Mind Date: Wed, 18 Mar 2026 15:10:05 +0530 Subject: [PATCH] feat: enhance billing panel with auto-recharge and credit management features - Added auto-recharge settings management, including fetching, updating, and toggling auto-recharge functionality. - Integrated credit balance and team usage retrieval to provide users with real-time financial insights. - Implemented card management features, allowing users to add, update, and delete saved payment methods. - Updated API interactions to support new endpoints for credits and auto-recharge functionalities. - Improved user experience with loading states and error handling for credit-related operations. --- package.json | 5 + .../settings/panels/BillingPanel.tsx | 715 ++++++++++++++++-- src/services/api/creditsApi.ts | 206 ++++- yarn.lock | 83 +- 4 files changed, 891 insertions(+), 118 deletions(-) diff --git a/package.json b/package.json index f155e5099..18ace5854 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,12 @@ "prepare": "husky" }, "dependencies": { + "@heroicons/react": "^2.2.0", + "@noble/hashes": "^2.0.1", + "@noble/secp256k1": "^3.0.0", "@reduxjs/toolkit": "^2.11.2", + "@scure/bip32": "^2.0.1", + "@scure/bip39": "^2.0.1", "@sentry/react": "^10.38.0", "@tauri-apps/api": "^2", "@tauri-apps/plugin-deep-link": "^2", diff --git a/src/components/settings/panels/BillingPanel.tsx b/src/components/settings/panels/BillingPanel.tsx index 0d704211b..844175125 100644 --- a/src/components/settings/panels/BillingPanel.tsx +++ b/src/components/settings/panels/BillingPanel.tsx @@ -1,6 +1,13 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { billingApi } from '../../../services/api/billingApi'; +import { + type AutoRechargeSettings, + type CreditBalance, + creditsApi, + type SavedCard, + type TeamUsage, +} from '../../../services/api/creditsApi'; import { useAppDispatch, useAppSelector } from '../../../store/hooks'; import { fetchCurrentUser } from '../../../store/userSlice'; import type { PlanTier } from '../../../types/api'; @@ -15,6 +22,25 @@ import { PLANS, } from './billingHelpers'; +// ── Constants ──────────────────────────────────────────────────────────────── +const THRESHOLD_OPTIONS = [5, 10, 20] as const; +const RECHARGE_OPTIONS = [10, 20, 50, 100] as const; +const WEEKLY_LIMIT_OPTIONS = [25, 50, 100, 200, 500] as const; + +const CARD_BRAND_LABELS: Record = { + visa: 'Visa', + mastercard: 'Mastercard', + amex: 'Amex', + discover: 'Discover', + jcb: 'JCB', + diners: 'Diners', + unionpay: 'UnionPay', +}; + +function cardBrandLabel(brand: string) { + return CARD_BRAND_LABELS[brand.toLowerCase()] ?? brand.charAt(0).toUpperCase() + brand.slice(1); +} + // ── Component ─────────────────────────────────────────────────────────── const BillingPanel = () => { const { navigateBack } = useSettingsNavigation(); @@ -31,7 +57,12 @@ const BillingPanel = () => { const currentTier: PlanTier = activeTeam?.team.subscription?.plan ?? 'FREE'; const hasActive = activeTeam?.team.subscription?.hasActiveSubscription ?? false; const planExpiry = activeTeam?.team.subscription?.planExpiry; - const usage = user?.usage; + + // Credits & usage state + const [creditBalance, setCreditBalance] = useState(null); + const [teamUsage, setTeamUsage] = useState(null); + const [isLoadingCredits, setIsLoadingCredits] = useState(false); + const [isToppingUp, setIsToppingUp] = useState(false); // Local state const [billingInterval, setBillingInterval] = useState<'monthly' | 'annual'>('monthly'); @@ -43,9 +74,45 @@ const BillingPanel = () => { const pollStartRef = useRef(0); const timeoutRef = useRef(null); - // Fetch current plan on mount + // ── Auto-recharge state ────────────────────────────────────────────────── + const [arSettings, setArSettings] = useState(null); + const [arLoading, setArLoading] = useState(true); + const [arError, setArError] = useState(null); + const [arSaving, setArSaving] = useState(false); + const [arThreshold, setArThreshold] = useState(5); + const [arAmount, setArAmount] = useState(20); + const [arWeeklyLimit, setArWeeklyLimit] = useState(50); + const [arDirty, setArDirty] = useState(false); + + // Recompute dirty flag whenever local settings or server settings change + useEffect(() => { + if (!arSettings) return; + setArDirty( + arThreshold !== arSettings.thresholdUsd || + arAmount !== arSettings.rechargeAmountUsd || + arWeeklyLimit !== arSettings.weeklyLimitUsd + ); + }, [arThreshold, arAmount, arWeeklyLimit, arSettings]); + + // ── Cards state ────────────────────────────────────────────────────────── + const [cards, setCards] = useState([]); + const [cardsLoading, setCardsLoading] = useState(true); + const [confirmDeleteId, setConfirmDeleteId] = useState(null); + const [deletingCardId, setDeletingCardId] = useState(null); + const [settingDefaultId, setSettingDefaultId] = useState(null); + + // Fetch current plan, credits balance, and team usage on mount useEffect(() => { billingApi.getCurrentPlan().catch(console.error); + + setIsLoadingCredits(true); + Promise.all([creditsApi.getBalance(), creditsApi.getTeamUsage()]) + .then(([balance, usage]) => { + setCreditBalance(balance); + setTeamUsage(usage); + }) + .catch(console.error) + .finally(() => setIsLoadingCredits(false)); }, []); // When crypto is selected, force annual @@ -62,6 +129,130 @@ const BillingPanel = () => { }; }, []); + // ── Fetch auto-recharge settings + cards on mount ──────────────────────── + useEffect(() => { + let cancelled = false; + + const load = async () => { + try { + const [settings, cardsData] = await Promise.all([ + creditsApi.getAutoRecharge(), + creditsApi.getCards(), + ]); + if (cancelled) return; + setArSettings(settings); + setArThreshold(settings.thresholdUsd); + setArAmount(settings.rechargeAmountUsd); + setArWeeklyLimit(settings.weeklyLimitUsd); + setCards(cardsData.cards); + } catch { + if (!cancelled) setArError('Failed to load auto-recharge settings.'); + } finally { + if (!cancelled) { + setArLoading(false); + setCardsLoading(false); + } + } + }; + + load().catch(console.error); + return () => { + cancelled = true; + }; + }, []); + + // ── Auto-recharge handlers ─────────────────────────────────────────────── + const handleArToggle = async () => { + if (!arSettings || arSaving) return; + const nextEnabled = !arSettings.enabled; + + // Prevent enabling without a saved card + if (nextEnabled && !arSettings.hasSavedPaymentMethod && cards.length === 0) { + setArError('Add a payment card before enabling auto-recharge.'); + return; + } + + setArSaving(true); + setArError(null); + try { + const updated = await creditsApi.updateAutoRecharge({ enabled: nextEnabled }); + setArSettings(updated); + } catch (err) { + const msg = + err && typeof err === 'object' && 'error' in err + ? String((err as { error: unknown }).error) + : 'Failed to update auto-recharge.'; + setArError(msg); + } finally { + setArSaving(false); + } + }; + + const handleArSave = async () => { + if (!arSettings || arSaving) return; + setArSaving(true); + setArError(null); + try { + const updated = await creditsApi.updateAutoRecharge({ + thresholdUsd: arThreshold, + rechargeAmountUsd: arAmount, + weeklyLimitUsd: arWeeklyLimit, + }); + setArSettings(updated); + setArDirty(false); + } catch (err) { + const msg = + err && typeof err === 'object' && 'error' in err + ? String((err as { error: unknown }).error) + : 'Failed to save settings.'; + setArError(msg); + } finally { + setArSaving(false); + } + }; + + // ── Card handlers ──────────────────────────────────────────────────────── + const handleSetDefault = async (paymentMethodId: string) => { + if (settingDefaultId) return; + setSettingDefaultId(paymentMethodId); + try { + const updated = await creditsApi.updateCard(paymentMethodId, { isDefault: true }); + setCards(updated.cards); + } catch { + setArError('Failed to update default card.'); + } finally { + setSettingDefaultId(null); + } + }; + + const handleDeleteCard = async (paymentMethodId: string) => { + if (deletingCardId) return; + setDeletingCardId(paymentMethodId); + setConfirmDeleteId(null); + try { + const updated = await creditsApi.deleteCard(paymentMethodId); + setCards(updated.cards); + // Refresh auto-recharge settings (hasSavedPaymentMethod may change) + const refreshed = await creditsApi.getAutoRecharge(); + setArSettings(refreshed); + } catch { + setArError('Failed to remove card.'); + } finally { + setDeletingCardId(null); + } + }; + + const handleAddCard = async () => { + // Card setup requires Stripe.js confirmation. + // Use the Stripe Customer Portal as the secure entry point. + try { + const { portalUrl } = await billingApi.createPortalSession(); + await openUrl(portalUrl); + } catch { + setArError('Could not open payment portal. Please try again.'); + } + }; + // Handle payment:success deep link event useEffect(() => { const onPaymentSuccess = async () => { @@ -102,7 +293,6 @@ const BillingPanel = () => { currentTierRef.current = currentTier; }, [currentTier]); - // eslint-disable-next-line react-hooks/preserve-manual-memoization const startPolling = useCallback(() => { if (pollRef.current) clearInterval(pollRef.current); pollStartRef.current = Date.now(); @@ -162,6 +352,18 @@ const BillingPanel = () => { } }; + const handleTopUp = async (amountUsd: number) => { + setIsToppingUp(true); + try { + const result = await creditsApi.topUp(amountUsd, 'stripe'); + await openUrl(result.url); + } catch (err) { + console.error('Top-up failed:', err); + } finally { + setIsToppingUp(false); + } + }; + // ── JSX ───────────────────────────────────────────────────────────── return (
@@ -174,40 +376,20 @@ const BillingPanel = () => { {/*
*/}
-
-
+
+ {/* ── Current Plan Header ───────────────────────────────── */} +
-

- Your Current Plan {currentTier} -

- {usage && ( - - {Math.round((usage.spentThisCycleUsd / usage.cycleBudgetUsd) * 100)}% used - - )} -
- - {hasActive && ( -
- {planExpiry && ( -

- Renews{' '} - {new Date(planExpiry).toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - year: 'numeric', - })} -

- )} +

Current Plan — {currentTier}

+ {hasActive && ( -
- )} - {/* Renewal date (for non-active subscriptions) */} - {!hasActive && planExpiry && ( + )} +
+ {planExpiry && (

Renews{' '} {new Date(planExpiry).toLocaleDateString('en-US', { @@ -217,20 +399,131 @@ const BillingPanel = () => { })}

)} - {usage && ( -
-
-
+
+ + {/* ── Inference Budget (Team Usage) ─────────────────────── */} +
+
+

Inference Budget

+ {isLoadingCredits && Loading…} + {teamUsage && !isLoadingCredits && ( + + ${teamUsage.remainingUsd.toFixed(2)} / ${teamUsage.cycleBudgetUsd.toFixed(2)}{' '} + remaining + + )} +
+ {teamUsage ? ( + <> +
+
+
+
+ + Daily usage: ${teamUsage.dailyUsage.toFixed(3)} + + + {( + (teamUsage.totalInputTokensThisCycle + + teamUsage.totalOutputTokensThisCycle) / + 1000 + ).toFixed(1)} + k tokens this cycle + +
+ {teamUsage.remainingUsd <= 0 && ( +

+ Budget exhausted — top up your credits to continue using AI features. +

+ )} + + ) : isLoadingCredits ? ( +
+ ) : ( +

Unable to load usage data

)}
+ + {/* ── Credits Balance & Top-up ──────────────────────────── */} +
+

Credits Balance

+ {creditBalance ? ( +
+
+ General credits + + ${creditBalance.balanceUsd.toFixed(2)} + +
+
+
+ Top-up credits + + ${creditBalance.topUpBalanceUsd.toFixed(2)} + {creditBalance.topUpBaselineUsd != null && + creditBalance.topUpBaselineUsd > 0 && ( + + {' '} + / ${creditBalance.topUpBaselineUsd.toFixed(2)} + + )} + +
+ {creditBalance.topUpBaselineUsd != null && + creditBalance.topUpBaselineUsd > 0 && ( +
+
+
+ )} +
+
+ ) : isLoadingCredits ? ( +
+
+
+
+ ) : ( +

Unable to load balance

+ )} +
+ {[5, 10, 25].map(amount => ( + + ))} +
+
{/* ── Interval toggle ──────────────────────────────────── */} @@ -407,6 +700,340 @@ const BillingPanel = () => {
+ {/* ── Auto-Recharge Credits ─────────────────────────────── */} +
+
+ {/* Header row */} +
+
+

Auto-Recharge Credits

+

+ Automatically top up when your balance runs low +

+
+ {arLoading ? ( +
+ ) : ( + + )} +
+ + {/* Error banner */} + {arError && ( +
+ + + +

{arError}

+ +
+ )} + + {/* Settings — only shown when enabled */} + {!arLoading && arSettings?.enabled && ( +
+ {/* Status row */} +
+ {arSettings.inFlight && ( + + + + + + Recharge in progress + + )} + {arSettings.spentThisWeekUsd > 0 && ( + + ${arSettings.spentThisWeekUsd.toFixed(2)} of ${arSettings.weeklyLimitUsd}{' '} + used this week + + )} + {arSettings.lastRechargeAt && ( + + Last recharged{' '} + {new Date(arSettings.lastRechargeAt).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + })} + + )} +
+ + {/* Last error from recharge attempt */} + {arSettings.lastError && ( +
+ + + +

+ Last recharge failed: {arSettings.lastError} +

+
+ )} + + {/* Trigger threshold */} +
+

+ Recharge when balance drops below +

+
+ {THRESHOLD_OPTIONS.map(v => ( + + ))} +
+
+ + {/* Recharge amount */} +
+

Add this amount

+
+ {RECHARGE_OPTIONS.map(v => ( + + ))} +
+
+ + {/* Weekly limit */} +
+

Weekly spending limit

+
+ {WEEKLY_LIMIT_OPTIONS.map(v => ( + + ))} +
+
+ + {/* Validation hint */} + {arAmount <= arThreshold && ( +

+ Recharge amount should be greater than the trigger threshold. +

+ )} + + {/* Save button */} + {arDirty && ( + + )} +
+ )} + + {/* Payment methods */} +
+
+

Payment Methods

+ +
+ + {cardsLoading ? ( +
+ {[0, 1].map(i => ( +
+ ))} +
+ ) : cards.length === 0 ? ( +
+ + + +

+ No saved cards. Add one to enable auto-recharge. +

+
+ ) : ( +
+ {cards.map(card => { + const isDeleting = deletingCardId === card.id; + const isSettingDefault = settingDefaultId === card.id; + const isConfirming = confirmDeleteId === card.id; + + return ( +
+ {/* Card icon */} + + + + + {/* Card info */} +
+
+ + {cardBrandLabel(card.brand)} ••••{card.last4} + + {card.isDefault && ( + + Default + + )} +
+

+ Expires {String(card.expMonth).padStart(2, '0')}/ + {String(card.expYear).slice(-2)} +

+
+ + {/* Actions */} +
+ {!card.isDefault && ( + + )} + + {isConfirming ? ( +
+ + +
+ ) : ( + + )} +
+
+ ); + })} +
+ )} +
+
+
+ {/* ── Upgrade benefits ───────────────────────────────────── */}
diff --git a/src/services/api/creditsApi.ts b/src/services/api/creditsApi.ts index 05375a5a6..b75b334fd 100644 --- a/src/services/api/creditsApi.ts +++ b/src/services/api/creditsApi.ts @@ -1,25 +1,104 @@ import type { ApiResponse } from '../../types/api'; import { apiClient } from '../apiClient'; -interface CreditBalance { - balance: number; - currency: string; +export interface CreditBalance { + balanceUsd: number; + topUpBalanceUsd: number; + topUpBaselineUsd: number | null; } -interface CreditTransaction { +export interface TeamUsage { + remainingUsd: number; + cycleBudgetUsd: number; + dailyUsage: number; + totalInputTokensThisCycle: number; + totalOutputTokensThisCycle: number; +} + +export interface TopUpResult { + url: string; + gatewayTransactionId: string; + amountUsd: number; + gateway: string; +} + +export interface CreditTransaction { id: string; - amount: number; - type: 'credit' | 'debit'; - description: string; + type: 'EARN' | 'SPEND'; + action: string; + amountUsd: number; + balanceAfterUsd: number; createdAt: string; - // Add other fields based on backend schema } -interface PaginatedTransactions { +export interface PaginatedTransactions { transactions: CreditTransaction[]; - totalCount: number; - page: number; - limit: number; + total: number; +} + +// ── Auto-Recharge types ────────────────────────────────────────────────────── + +export interface AutoRechargeSettings { + enabled: boolean; + thresholdUsd: number; + rechargeAmountUsd: number; + weeklyLimitUsd: number; + spentThisWeekUsd: number; + weekStartDate: string; + inFlight: boolean; + hasSavedPaymentMethod: boolean; + lastTriggeredAt: string | null; + lastRechargeAt: string | null; + lastPaymentIntentId: string | null; + lastError: string | null; +} + +export interface AutoRechargeUpdatePayload { + enabled?: boolean; + thresholdUsd?: number; + rechargeAmountUsd?: number; + weeklyLimitUsd?: number; +} + +export interface BillingAddress { + line1?: string; + city?: string; + state?: string; + postalCode?: string; + country?: string; +} + +export interface CardBillingDetails { + name?: string; + email?: string; + address?: BillingAddress; +} + +export interface SavedCard { + id: string; + brand: string; + expMonth: number; + expYear: number; + isDefault: boolean; + last4: string; + billingDetails: CardBillingDetails; +} + +export interface CardsData { + customerId: string; + defaultPaymentMethodId: string; + cards: SavedCard[]; +} + +export interface SetupIntentData { + clientSecret: string; + customerId: string; + setupIntentId: string; +} + +export interface UpdateCardPayload { + isDefault?: boolean; + billingDetails?: CardBillingDetails; } /** @@ -27,11 +106,35 @@ interface PaginatedTransactions { */ export const creditsApi = { /** - * Get the current user's credit balance + * Get the current user's credit balance (general + top-up) * GET /credits/balance */ getBalance: async (): Promise => { - const response = await apiClient.get>('/credits/balance'); + const response = await apiClient.get>('/payments/credits/balance'); + return response.data; + }, + + /** + * Get team inference budget usage for the current billing cycle + * GET /teams/me/usage + */ + getTeamUsage: async (): Promise => { + const response = await apiClient.get>('/teams/me/usage'); + return response.data; + }, + + /** + * Start a top-up (get Stripe or Coinbase payment URL) + * POST /credits/top-up + */ + topUp: async ( + amountUsd: number, + gateway: 'stripe' | 'coinbase' = 'stripe' + ): Promise => { + const response = await apiClient.post>('/payments/credits/top-up', { + amountUsd, + gateway, + }); return response.data; }, @@ -39,9 +142,80 @@ export const creditsApi = { * Get paginated credit transaction history * GET /credits/transactions */ - getTransactions: async (page = 1, limit = 50): Promise => { + getTransactions: async (limit = 20, offset = 0): Promise => { const response = await apiClient.get>( - `/credits/transactions?page=${page}&limit=${limit}` + `/credits/transactions?limit=${limit}&offset=${offset}` + ); + return response.data; + }, + + // ── Auto-Recharge ────────────────────────────────────────────────────────── + + /** + * Get auto-recharge settings + * GET /payments/credits/auto-recharge + */ + getAutoRecharge: async (): Promise => { + const response = await apiClient.get>( + '/payments/credits/auto-recharge' + ); + return response.data; + }, + + /** + * Update auto-recharge settings. Enabling requires a saved card. + * PATCH /payments/credits/auto-recharge + */ + updateAutoRecharge: async (payload: AutoRechargeUpdatePayload): Promise => { + const response = await apiClient.patch>( + '/payments/credits/auto-recharge', + payload + ); + return response.data; + }, + + /** + * List saved cards for auto-recharge + * GET /payments/credits/auto-recharge/cards + */ + getCards: async (): Promise => { + const response = await apiClient.get>( + '/payments/credits/auto-recharge/cards' + ); + return response.data; + }, + + /** + * Create a Stripe SetupIntent for adding a new card. + * The returned clientSecret must be confirmed with Stripe.js. + * POST /payments/credits/auto-recharge/cards/setup-intent + */ + createSetupIntent: async (): Promise => { + const response = await apiClient.post>( + '/payments/credits/auto-recharge/cards/setup-intent' + ); + return response.data; + }, + + /** + * Update a saved card (set as default or update billing details) + * PATCH /payments/credits/auto-recharge/cards/:paymentMethodId + */ + updateCard: async (paymentMethodId: string, payload: UpdateCardPayload): Promise => { + const response = await apiClient.patch>( + `/payments/credits/auto-recharge/cards/${encodeURIComponent(paymentMethodId)}`, + payload + ); + return response.data; + }, + + /** + * Remove a saved card. If it was the default, another card becomes default. + * DELETE /payments/credits/auto-recharge/cards/:paymentMethodId + */ + deleteCard: async (paymentMethodId: string): Promise => { + const response = await apiClient.delete>( + `/payments/credits/auto-recharge/cards/${encodeURIComponent(paymentMethodId)}` ); return response.data; }, diff --git a/yarn.lock b/yarn.lock index c3a7965bc..c5a6ce27b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -654,7 +654,7 @@ "@heroicons/react@^2.2.0": version "2.2.0" - resolved "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.2.0.tgz#0c05124af50434a800773abec8d3af6a297d904b" integrity sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ== "@humanfs/core@^0.19.1": @@ -928,27 +928,22 @@ outvariant "^1.4.3" strict-event-emitter "^0.5.1" -"@noble/curves@~1.9.0": - version "1.9.7" - resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz" - integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== +"@noble/curves@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-2.0.1.tgz#64ba8bd5e8564a02942655602515646df1cdb3ad" + integrity sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw== dependencies: - "@noble/hashes" "1.8.0" - -"@noble/hashes@1.8.0", "@noble/hashes@~1.8.0": - version "1.8.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz" - integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + "@noble/hashes" "2.0.1" "@noble/hashes@2.0.1", "@noble/hashes@^2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-2.0.1.tgz#fc1a928061d1232b0a52bb754393c37a5216c89e" integrity sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw== -"@noble/secp256k1@^2.0.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-2.3.0.tgz" - integrity sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw== +"@noble/secp256k1@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-3.0.0.tgz#29711361db8f37b1b7e0b8d80c933013fc887475" + integrity sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1181,26 +1176,21 @@ "@scure/base@2.0.0": version "2.0.0" - resolved "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-2.0.0.tgz#ba6371fddf92c2727e88ad6ab485db6e624f9a98" integrity sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w== -"@scure/base@~1.2.5": - version "1.2.6" - resolved "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz" - integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== - -"@scure/bip32@^1.5.1": - version "1.7.0" - resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz" - integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== +"@scure/bip32@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-2.0.1.tgz#4ceea207cee8626d3fe8f0b6ab68b6af8f81c482" + integrity sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA== dependencies: - "@noble/curves" "~1.9.0" - "@noble/hashes" "~1.8.0" - "@scure/base" "~1.2.5" + "@noble/curves" "2.0.1" + "@noble/hashes" "2.0.1" + "@scure/base" "2.0.0" "@scure/bip39@^2.0.1": version "2.0.1" - resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-2.0.1.tgz#47a6dc15e04faf200041239d46ae3bb7c3c96add" integrity sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg== dependencies: "@noble/hashes" "2.0.1" @@ -7405,16 +7395,7 @@ strict-event-emitter@^0.5.1: resolved "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz" integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7513,14 +7494,8 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8365,7 +8340,8 @@ workerpool@^6.5.1: resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + name wrap-ansi-cjs version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -8383,15 +8359,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"