From abd4dc7189731ff217ef8fa5201df8e3a2cad30e Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 00:48:35 +0300 Subject: [PATCH 01/18] feat: in-app citizenship modal + referral approvals + bot DKS link - Add CitizenshipModal component for in-app citizenship application (uses connected wallet keypair, no seed phrase needed) - Replace /citizens redirect with in-app modal in Rewards section - Add pending approvals to ReferralContext - Add approveReferral and getPendingApprovals to citizenship lib - Add applyingCitizenship/applicationSuccess translations (6 langs) - Add DKS Kurdistan bot link to telegram-bot welcome message --- src/components/CitizenshipModal.tsx | 578 +++++++++++++++++++++++ src/contexts/ReferralContext.tsx | 14 + src/i18n/translations/ar.ts | 8 + src/i18n/translations/ckb.ts | 8 + src/i18n/translations/en.ts | 8 + src/i18n/translations/fa.ts | 8 + src/i18n/translations/krd.ts | 8 + src/i18n/translations/tr.ts | 8 + src/i18n/types.ts | 9 + src/lib/citizenship.ts | 113 +++++ src/sections/Rewards.tsx | 100 +++- supabase/functions/telegram-bot/index.ts | 3 + 12 files changed, 858 insertions(+), 7 deletions(-) create mode 100644 src/components/CitizenshipModal.tsx diff --git a/src/components/CitizenshipModal.tsx b/src/components/CitizenshipModal.tsx new file mode 100644 index 0000000..9a1530a --- /dev/null +++ b/src/components/CitizenshipModal.tsx @@ -0,0 +1,578 @@ +/** + * In-App Citizenship Application Modal + * Self-contained modal with 3 steps: form → processing → success + * Uses the already-connected wallet keypair (no seed phrase needed) + */ + +import { useState, useEffect, useRef } from 'react'; +import { X, Plus, Trash2, Shield, CheckCircle, Clock, ArrowRight, AlertCircle } from 'lucide-react'; +import { useWallet } from '@/contexts/WalletContext'; +import { useTelegram } from '@/hooks/useTelegram'; +import { useTranslation } from '@/i18n'; +import { KurdistanSun } from '@/components/KurdistanSun'; +import { formatAddress } from '@/lib/utils'; +import type { Region, MaritalStatus, ChildInfo } from '@/lib/citizenship'; +import { + calculateIdentityHash, + saveCitizenshipLocally, + uploadToIPFS, + applyCitizenship, +} from '@/lib/citizenship'; + +interface CitizenshipModalProps { + isOpen: boolean; + onClose: () => void; +} + +type Step = 'form' | 'processing' | 'success'; + +const REGIONS: { value: Region; labelKey: string }[] = [ + { value: 'bakur', labelKey: 'citizen.regionBakur' }, + { value: 'basur', labelKey: 'citizen.regionBasur' }, + { value: 'rojava', labelKey: 'citizen.regionRojava' }, + { value: 'rojhelat', labelKey: 'citizen.regionRojhelat' }, + { value: 'kurdistan_a_sor', labelKey: 'citizen.regionKurdistanASor' }, + { value: 'diaspora', labelKey: 'citizen.regionDiaspora' }, +]; + +export function CitizenshipModal({ isOpen, onClose }: CitizenshipModalProps) { + const { peopleApi, keypair, address } = useWallet(); + const { hapticImpact, hapticNotification } = useTelegram(); + const { t } = useTranslation(); + + const [step, setStep] = useState('form'); + const [error, setError] = useState(''); + + // Form fields + const [fullName, setFullName] = useState(''); + const [fatherName, setFatherName] = useState(''); + const [grandfatherName, setGrandfatherName] = useState(''); + const [motherName, setMotherName] = useState(''); + const [tribe, setTribe] = useState(''); + const [maritalStatus, setMaritalStatus] = useState('nezewici'); + const [childrenCount, setChildrenCount] = useState(0); + const [children, setChildren] = useState([]); + const [region, setRegion] = useState(''); + const [email, setEmail] = useState(''); + const [profession, setProfession] = useState(''); + const [referrerAddress, setReferrerAddress] = useState(''); + const [consent, setConsent] = useState(false); + + // Success data + const [identityHash, setIdentityHash] = useState(''); + + // Processing cancel ref + const cancelledRef = useRef(false); + + // Reset state when modal opens + useEffect(() => { + if (isOpen) { + setStep('form'); + setError(''); + setFullName(''); + setFatherName(''); + setGrandfatherName(''); + setMotherName(''); + setTribe(''); + setMaritalStatus('nezewici'); + setChildrenCount(0); + setChildren([]); + setRegion(''); + setEmail(''); + setProfession(''); + setReferrerAddress(''); + setConsent(false); + setIdentityHash(''); + cancelledRef.current = false; + } + }, [isOpen]); + + // --- Form handlers --- + + const handleMaritalChange = (status: MaritalStatus) => { + hapticImpact('light'); + setMaritalStatus(status); + if (status === 'nezewici') { + setChildrenCount(0); + setChildren([]); + } + }; + + const handleChildrenCountChange = (count: number) => { + const c = Math.max(0, Math.min(20, count)); + setChildrenCount(c); + setChildren((prev) => { + if (c > prev.length) { + return [ + ...prev, + ...Array.from({ length: c - prev.length }, () => ({ name: '', birthYear: 2000 })), + ]; + } + return prev.slice(0, c); + }); + }; + + const updateChild = (index: number, field: keyof ChildInfo, value: string | number) => { + setChildren((prev) => + prev.map((child, i) => (i === index ? { ...child, [field]: value } : child)) + ); + }; + + const addChild = () => { + hapticImpact('light'); + handleChildrenCountChange(childrenCount + 1); + }; + + const removeChild = (index: number) => { + hapticImpact('light'); + setChildren((prev) => prev.filter((_, i) => i !== index)); + setChildrenCount((prev) => prev - 1); + }; + + const handleFormSubmit = () => { + setError(''); + + if ( + !fullName || + !fatherName || + !grandfatherName || + !motherName || + !tribe || + !region || + !email || + !profession + ) { + setError(t('citizen.fillAllFields')); + hapticNotification('error'); + return; + } + + if (!consent) { + setError(t('citizen.acceptConsent')); + hapticNotification('error'); + return; + } + + if (!peopleApi) { + setError(t('citizen.peopleChainNotConnected')); + hapticNotification('error'); + return; + } + + if (!keypair || !address) { + setError(t('citizen.walletNotConnected')); + hapticNotification('error'); + return; + } + + hapticImpact('medium'); + setStep('processing'); + }; + + // --- Processing logic --- + + useEffect(() => { + if (step !== 'processing') return; + + cancelledRef.current = false; + + const process = async () => { + try { + if (!peopleApi || !keypair || !address) { + setError(t('citizen.walletNotConnected')); + setStep('form'); + return; + } + + // Build citizenship data for local save + const citizenshipData = { + fullName, + fatherName, + grandfatherName, + motherName, + tribe, + maritalStatus, + childrenCount: maritalStatus === 'zewici' ? childrenCount : undefined, + children: maritalStatus === 'zewici' && children.length > 0 ? children : undefined, + region: region as Region, + email, + profession, + referrerAddress: referrerAddress || undefined, + walletAddress: address, + seedPhrase: '', + timestamp: Date.now(), + }; + + // Mock IPFS upload + const ipfsCid = await uploadToIPFS(citizenshipData); + if (cancelledRef.current) return; + + // Calculate identity hash + const hash = calculateIdentityHash(fullName, email, [ipfsCid]); + if (cancelledRef.current) return; + setIdentityHash(hash); + + // Save encrypted data locally + saveCitizenshipLocally(citizenshipData); + + // Sign and submit extrinsic + const result = await applyCitizenship(peopleApi, keypair, hash, referrerAddress || null); + + if (cancelledRef.current) return; + + if (result.success) { + hapticNotification('success'); + setStep('success'); + } else { + hapticNotification('error'); + setError(result.error || t('citizen.submissionFailed')); + setStep('form'); + } + } catch (err) { + if (cancelledRef.current) return; + hapticNotification('error'); + setError(err instanceof Error ? err.message : t('citizen.submissionFailed')); + setStep('form'); + } + }; + + process(); + + return () => { + cancelledRef.current = true; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [step]); + + if (!isOpen) return null; + + const inputClass = 'w-full px-4 py-3 bg-muted rounded-xl text-sm'; + const labelClass = 'text-sm text-muted-foreground mb-1 block'; + + // --- Processing Step --- + if (step === 'processing') { + return ( +
+
+
+ +
+

{t('citizen.applyingCitizenship')}

+

{fullName}

+
+
+
+
+ ); + } + + // --- Success Step --- + if (step === 'success') { + return ( +
+
+
+ {/* Success Icon */} +
+ +
+ + {/* Title */} +

{t('citizen.applicationSuccess')}

+ + {/* 3-Step Process */} +
+
+ +

{t('citizen.stepApplicationSent')}

+
+
+ +

{t('citizen.stepReferrerApproval')}

+
+
+ +

{t('citizen.stepConfirm')}

+
+
+ + {/* Application Info */} +
+
+

{t('citizen.identityHash')}

+

{formatAddress(identityHash)}

+
+
+

{t('citizen.walletAddress')}

+

{formatAddress(address || '')}

+
+
+ + {/* Next Steps Info */} +

+ {t('citizen.nextStepsInfo')} +

+ + {/* Close Button */} + +
+
+
+ ); + } + + // --- Form Step --- + return ( +
+
+ {/* Header */} +
+

{t('citizen.pageTitle')}

+ +
+ + {/* Form Content */} +
+ {/* Privacy Notice */} +
+ +

{t('citizen.privacyNotice')}

+
+ + {/* Full Name */} +
+ + setFullName(e.target.value)} + className={inputClass} + placeholder={t('citizen.fullNamePlaceholder')} + /> +
+ + {/* Father's Name */} +
+ + setFatherName(e.target.value)} + className={inputClass} + placeholder={t('citizen.fatherNamePlaceholder')} + /> +
+ + {/* Grandfather's Name */} +
+ + setGrandfatherName(e.target.value)} + className={inputClass} + placeholder={t('citizen.grandfatherNamePlaceholder')} + /> +
+ + {/* Mother's Name */} +
+ + setMotherName(e.target.value)} + className={inputClass} + placeholder={t('citizen.motherNamePlaceholder')} + /> +
+ + {/* Tribe */} +
+ + setTribe(e.target.value)} + className={inputClass} + placeholder={t('citizen.tribePlaceholder')} + /> +
+ + {/* Marital Status */} +
+ +
+ + +
+
+ + {/* Children (if married) */} + {maritalStatus === 'zewici' && ( +
+ + {children.map((child, index) => ( +
+
+ + updateChild(index, 'name', e.target.value)} + className={inputClass} + placeholder={t('citizen.childNamePlaceholder')} + /> +
+
+ + + updateChild(index, 'birthYear', parseInt(e.target.value) || 2000) + } + className={inputClass} + min={1950} + max={2026} + /> +
+ +
+ ))} + +
+ )} + + {/* Region */} +
+ + +
+ + {/* Email */} +
+ + setEmail(e.target.value)} + className={inputClass} + placeholder={t('citizen.emailPlaceholder')} + /> +
+ + {/* Profession */} +
+ + setProfession(e.target.value)} + className={inputClass} + placeholder={t('citizen.professionPlaceholder')} + /> +
+ + {/* Referrer Address */} +
+ + setReferrerAddress(e.target.value)} + className={inputClass} + placeholder={t('citizen.referrerPlaceholder')} + /> +
+ + {/* Consent */} + + + {/* Error */} + {error && ( +
+ + {error} +
+ )} + + {/* Submit Button */} + +
+
+
+ ); +} diff --git a/src/contexts/ReferralContext.tsx b/src/contexts/ReferralContext.tsx index ec78edd..0e49eac 100644 --- a/src/contexts/ReferralContext.tsx +++ b/src/contexts/ReferralContext.tsx @@ -14,10 +14,12 @@ import { subscribeToReferralEvents, type ReferralStats, } from '@/lib/referral'; +import { getPendingApprovals, getCitizenshipStatus, type PendingApproval } from '@/lib/citizenship'; interface ReferralContextValue { stats: ReferralStats | null; myReferrals: string[]; + pendingApprovals: PendingApproval[]; loading: boolean; refreshStats: () => Promise; } @@ -31,6 +33,7 @@ export function ReferralProvider({ children }: { children: ReactNode }) { const [stats, setStats] = useState(null); const [myReferrals, setMyReferrals] = useState([]); + const [pendingApprovals, setPendingApprovals] = useState([]); const [loading, setLoading] = useState(true); // Fetch referral statistics from People Chain @@ -38,6 +41,7 @@ export function ReferralProvider({ children }: { children: ReactNode }) { if (!peopleApi || !address) { setStats(null); setMyReferrals([]); + setPendingApprovals([]); setLoading(false); return; } @@ -52,6 +56,15 @@ export function ReferralProvider({ children }: { children: ReactNode }) { setStats(fetchedStats); setMyReferrals(fetchedReferrals); + + // Fetch pending approvals only if user is an approved citizen (can be a referrer) + const citizenStatus = await getCitizenshipStatus(peopleApi, address); + if (citizenStatus === 'Approved') { + const approvals = await getPendingApprovals(peopleApi, address); + setPendingApprovals(approvals); + } else { + setPendingApprovals([]); + } } catch (error) { console.error('Error fetching referral stats:', error); showAlert(translate('context.referralStatsError')); @@ -92,6 +105,7 @@ export function ReferralProvider({ children }: { children: ReactNode }) { const value: ReferralContextValue = { stats, myReferrals, + pendingApprovals, loading, refreshStats: fetchStats, }; diff --git a/src/i18n/translations/ar.ts b/src/i18n/translations/ar.ts index 193af86..e42d749 100644 --- a/src/i18n/translations/ar.ts +++ b/src/i18n/translations/ar.ts @@ -171,6 +171,12 @@ const ar: Translations = { noUnclaimedRewards: 'لا توجد مكافآت غير مطالب بها', rewardHistory: 'سجل المكافآت', era: 'حقبة', + pendingApprovals: 'الموافقات المعلّقة', + approveReferral: 'موافقة', + approvingReferral: 'جاري الموافقة...', + referralApprovalSuccess: 'تمت الموافقة على الإحالة!', + referralApprovalFailed: 'فشلت الموافقة', + pendingReferralStatus: 'بانتظار موافقتك', }, wallet: { @@ -826,6 +832,8 @@ const ar: Translations = { alreadyPending: 'لديك طلب قيد الانتظار', alreadyApproved: 'مواطنتك معتمدة بالفعل!', insufficientBalance: 'رصيد غير كافٍ (١ HEZ وديعة مطلوبة)', + applyingCitizenship: 'جاري تقديم طلب المواطنة...', + applicationSuccess: 'تم تقديم الطلب!', selectLanguage: 'اختر اللغة', }, }; diff --git a/src/i18n/translations/ckb.ts b/src/i18n/translations/ckb.ts index a374663..dbacb5b 100644 --- a/src/i18n/translations/ckb.ts +++ b/src/i18n/translations/ckb.ts @@ -172,6 +172,12 @@ const ckb: Translations = { noUnclaimedRewards: 'خەڵاتی داوانەکراو نییە', rewardHistory: 'مێژووی خەڵاتەکان', era: 'سەردەم', + pendingApprovals: 'پەسەندکردنە چاوەڕوانەکان', + approveReferral: 'پەسەندکردن', + approvingReferral: 'پەسەند دەکرێت...', + referralApprovalSuccess: 'بانگهێشتکردن پەسەندکرا!', + referralApprovalFailed: 'پەسەندکردن سەرنەکەوت', + pendingReferralStatus: 'چاوەڕوانی پەسەندکردنی تۆیە', }, wallet: { @@ -829,6 +835,8 @@ const ckb: Translations = { alreadyPending: 'داواکارییەکی چاوەڕوانت هەیە', alreadyApproved: 'هاوڵاتیبوونت پێشتر پەسەند کراوە!', insufficientBalance: 'باڵانسی پێویست نییە (١ HEZ ئەمانەت پێویستە)', + applyingCitizenship: 'داواکاری هاوڵاتیبوون دەنێردرێت...', + applicationSuccess: 'داواکاری نێردرا!', selectLanguage: 'زمان هەڵبژێرە', }, }; diff --git a/src/i18n/translations/en.ts b/src/i18n/translations/en.ts index e892997..1875e71 100644 --- a/src/i18n/translations/en.ts +++ b/src/i18n/translations/en.ts @@ -171,6 +171,12 @@ const en: Translations = { noUnclaimedRewards: 'No unclaimed rewards', rewardHistory: 'Reward History', era: 'Era', + pendingApprovals: 'Pending Approvals', + approveReferral: 'Approve', + approvingReferral: 'Approving...', + referralApprovalSuccess: 'Referral approved!', + referralApprovalFailed: 'Approval failed', + pendingReferralStatus: 'Awaiting your approval', }, wallet: { @@ -829,6 +835,8 @@ const en: Translations = { alreadyPending: 'You already have a pending application', alreadyApproved: 'Your citizenship is already approved!', insufficientBalance: 'Insufficient balance (1 HEZ deposit required)', + applyingCitizenship: 'Applying for citizenship...', + applicationSuccess: 'Application submitted!', selectLanguage: 'Select language', }, }; diff --git a/src/i18n/translations/fa.ts b/src/i18n/translations/fa.ts index 2fac6a5..f96ce2f 100644 --- a/src/i18n/translations/fa.ts +++ b/src/i18n/translations/fa.ts @@ -171,6 +171,12 @@ const fa: Translations = { noUnclaimedRewards: 'پاداش مطالبه نشده‌ای وجود ندارد', rewardHistory: 'تاریخچه پاداش‌ها', era: 'دوره', + pendingApprovals: 'تأییدهای در انتظار', + approveReferral: 'تأیید', + approvingReferral: 'در حال تأیید...', + referralApprovalSuccess: 'دعوت تأیید شد!', + referralApprovalFailed: 'تأیید ناموفق بود', + pendingReferralStatus: 'در انتظار تأیید شما', }, wallet: { @@ -829,6 +835,8 @@ const fa: Translations = { alreadyPending: 'درخواست در انتظار دارید', alreadyApproved: 'شهروندی شما قبلاً تأیید شده!', insufficientBalance: 'موجودی ناکافی (۱ HEZ سپرده لازم است)', + applyingCitizenship: 'در حال ارسال درخواست شهروندی...', + applicationSuccess: 'درخواست ارسال شد!', selectLanguage: 'انتخاب زبان', }, }; diff --git a/src/i18n/translations/krd.ts b/src/i18n/translations/krd.ts index 2ab0691..c8f5fa5 100644 --- a/src/i18n/translations/krd.ts +++ b/src/i18n/translations/krd.ts @@ -176,6 +176,12 @@ const krd: Translations = { noUnclaimedRewards: 'Xelatên nedaxwazkir tune ne', rewardHistory: 'Dîroka Xelatan', era: 'Era', + pendingApprovals: 'Pejirandina li bendê', + approveReferral: 'Pejirîne', + approvingReferral: 'Tê pejirandin...', + referralApprovalSuccess: 'Referans hat pejirandin!', + referralApprovalFailed: 'Pejirandin biserneket', + pendingReferralStatus: 'Li benda pejirandina we', }, wallet: { @@ -856,6 +862,8 @@ const krd: Translations = { alreadyPending: 'Serlêdanek te ya li bendê heye', alreadyApproved: 'Welatîbûna te berê hatiye pejirandin!', insufficientBalance: 'Balansa têr nîne (1 HEZ depozîto pêwîst e)', + applyingCitizenship: 'Daxwaza welatîbûnê tê şandin...', + applicationSuccess: 'Daxwaz hat şandin!', selectLanguage: 'Ziman hilbijêre', }, }; diff --git a/src/i18n/translations/tr.ts b/src/i18n/translations/tr.ts index b16938a..579d111 100644 --- a/src/i18n/translations/tr.ts +++ b/src/i18n/translations/tr.ts @@ -171,6 +171,12 @@ const tr: Translations = { noUnclaimedRewards: 'Talep edilmemiş ödül yok', rewardHistory: 'Ödül Geçmişi', era: 'Era', + pendingApprovals: 'Bekleyen Onaylar', + approveReferral: 'Onayla', + approvingReferral: 'Onaylanıyor...', + referralApprovalSuccess: 'Referans onaylandı!', + referralApprovalFailed: 'Onaylama başarısız', + pendingReferralStatus: 'Onayınızı bekliyor', }, wallet: { @@ -829,6 +835,8 @@ const tr: Translations = { alreadyPending: 'Bekleyen bir başvurunuz var', alreadyApproved: 'Vatandaşlığınız zaten onaylanmış!', insufficientBalance: 'Yetersiz bakiye (1 HEZ depozito gerekli)', + applyingCitizenship: 'Vatandaşlık başvurusu yapılıyor...', + applicationSuccess: 'Başvuru gönderildi!', selectLanguage: 'Dil seçin', }, }; diff --git a/src/i18n/types.ts b/src/i18n/types.ts index 443d59d..8361877 100644 --- a/src/i18n/types.ts +++ b/src/i18n/types.ts @@ -173,6 +173,12 @@ export interface Translations { noUnclaimedRewards: string; rewardHistory: string; era: string; + pendingApprovals: string; + approveReferral: string; + approvingReferral: string; + referralApprovalSuccess: string; + referralApprovalFailed: string; + pendingReferralStatus: string; }; // Wallet section @@ -851,6 +857,9 @@ export interface Translations { alreadyPending: string; alreadyApproved: string; insufficientBalance: string; + // In-app modal + applyingCitizenship: string; + applicationSuccess: string; // Language selector selectLanguage: string; }; diff --git a/src/lib/citizenship.ts b/src/lib/citizenship.ts index a356786..3476533 100644 --- a/src/lib/citizenship.ts +++ b/src/lib/citizenship.ts @@ -46,6 +46,11 @@ export interface CitizenshipResult { identityHash?: string; } +export interface PendingApproval { + applicantAddress: string; + identityHash: string; +} + // ── Identity Hash (Keccak-256) ────────────────────────────────────── export function calculateIdentityHash(name: string, email: string, documentCids: string[]): string { @@ -140,6 +145,114 @@ export async function getCitizenshipStatus( } } +// ── Pending Approvals ─────────────────────────────────────────────── + +/** + * Get pending referral applications that need approval from the given referrer. + * Queries identityKyc.applications entries and filters by referrer + PendingReferral status. + */ +export async function getPendingApprovals( + api: ApiPromise, + referrerAddress: string +): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (!(api?.query as any)?.identityKyc?.applications) { + return []; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const entries = await (api.query as any).identityKyc.applications.entries(); + const pending: PendingApproval[] = []; + + for (const [key, value] of entries) { + const applicantAddress = key.args[0].toString(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const appData = value.toJSON() as any; + + // Check if this application's referrer matches + if (!appData?.referrer || appData.referrer !== referrerAddress) { + continue; + } + + // Check if status is PendingReferral + const status = await getCitizenshipStatus(api, applicantAddress); + if (status === 'PendingReferral') { + pending.push({ + applicantAddress, + identityHash: appData.identityHash || '', + }); + } + } + + return pending; + } catch (error) { + console.error('[Citizenship] Error fetching pending approvals:', error); + return []; + } +} + +// ── Approve Referral ──────────────────────────────────────────────── + +export async function approveReferral( + api: ApiPromise, + keypair: KeyringPair, + applicantAddress: string +): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tx = api.tx as any; + if (!tx?.identityKyc?.approveReferral) { + return { success: false, error: 'Identity KYC pallet not available' }; + } + + const result = await new Promise((resolve) => { + tx.identityKyc + .approveReferral(applicantAddress) + .signAndSend( + keypair, + { nonce: -1 }, + ({ + status, + dispatchError, + }: { + status: { + isInBlock: boolean; + isFinalized: boolean; + asInBlock?: { toString: () => string }; + asFinalized?: { toString: () => string }; + }; + dispatchError?: { isModule: boolean; asModule: unknown; toString: () => string }; + }) => { + if (status.isInBlock || status.isFinalized) { + if (dispatchError) { + let errorMessage = 'Referral approval failed'; + if (dispatchError.isModule) { + const decoded = api.registry.findMetaError( + dispatchError.asModule as Parameters[0] + ); + errorMessage = `${decoded.section}.${decoded.name}`; + } + resolve({ success: false, error: errorMessage }); + return; + } + const blockHash = status.asFinalized?.toString() || status.asInBlock?.toString(); + resolve({ success: true, blockHash }); + } + } + ) + .catch((error: Error) => resolve({ success: false, error: error.message })); + }); + + return result; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown error', + }; + } +} + // ── Blockchain Submission ─────────────────────────────────────────── export async function applyCitizenship( diff --git a/src/sections/Rewards.tsx b/src/sections/Rewards.tsx index 2009248..da7f38a 100644 --- a/src/sections/Rewards.tsx +++ b/src/sections/Rewards.tsx @@ -24,10 +24,12 @@ import { Play, PenTool, Globe2, + Clock, + Loader2, } from 'lucide-react'; import { cn, formatAddress } from '@/lib/utils'; import { useTelegram } from '@/hooks/useTelegram'; - +import { useAuth } from '@/contexts/AuthContext'; import { useReferral } from '@/contexts/ReferralContext'; import { useWallet } from '@/contexts/WalletContext'; import { SocialLinks } from '@/components/SocialLinks'; @@ -62,9 +64,11 @@ import { getCitizenshipStatus, getCitizenCount, confirmCitizenship, + approveReferral, type CitizenshipStatus, } from '@/lib/citizenship'; import { KurdistanSun } from '@/components/KurdistanSun'; +import { CitizenshipModal } from '@/components/CitizenshipModal'; // Activity tracking constants const ACTIVITY_STORAGE_KEY = 'pezkuwi_last_active'; @@ -72,8 +76,8 @@ const ACTIVITY_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours export function RewardsSection() { const { hapticImpact, hapticNotification, shareUrl, showAlert } = useTelegram(); - - const { stats, myReferrals, loading, refreshStats } = useReferral(); + const { user: authUser } = useAuth(); + const { stats, myReferrals, pendingApprovals, loading, refreshStats } = useReferral(); const { isConnected, address, peopleApi, assetHubApi, keypair } = useWallet(); const { t } = useTranslation(); @@ -95,6 +99,8 @@ export function RewardsSection() { const [unclaimedRewards, setUnclaimedRewards] = useState(null); const [claimingStaking, setClaimingStaking] = useState(false); const [claimingStakingEra, setClaimingStakingEra] = useState(null); + const [approvingAddress, setApprovingAddress] = useState(null); + const [showCitizenshipModal, setShowCitizenshipModal] = useState(false); // Check activity status const checkActivityStatus = useCallback(() => { @@ -358,9 +364,31 @@ export function RewardsSection() { showAlert(t('rewards.activatedAlert')); }; - // Citizenship referral link - wallet address in start param for auto-fill - const referralLink = address - ? `https://t.me/pezkuwichainBot?start=${address}` + const handleApproveReferral = async (applicantAddress: string) => { + if (!peopleApi || !keypair) return; + setApprovingAddress(applicantAddress); + hapticImpact('medium'); + try { + const result = await approveReferral(peopleApi, keypair, applicantAddress); + if (result.success) { + hapticNotification('success'); + showAlert(t('rewards.referralApprovalSuccess')); + refreshStats(); + } else { + hapticNotification('error'); + showAlert(result.error || t('rewards.referralApprovalFailed')); + } + } catch (err) { + hapticNotification('error'); + showAlert(err instanceof Error ? err.message : t('rewards.referralApprovalFailed')); + } finally { + setApprovingAddress(null); + } + }; + + // Telegram referral link (for sharing) - use authenticated user ID + const referralLink = authUser?.telegram_id + ? `https://t.me/pezkuwichainBot?start=ref_${authUser.telegram_id}` : 'https://t.me/pezkuwichainBot'; // Full share message: invitation text + link + wallet address for manual paste @@ -496,7 +524,7 @@ export function RewardsSection() { + {/* Pending Approvals Section */} + {pendingApprovals.length > 0 && ( +
+
+ +

{t('rewards.pendingApprovals')}

+ + {pendingApprovals.length} + +
+
+ {pendingApprovals.map((approval) => ( +
+
+ + {formatAddress(approval.applicantAddress, 8)} + +

+ {t('rewards.pendingReferralStatus')} +

+
+ +
+ ))} +
+
+ )} + {loading ? (
{[1, 2, 3, 4, 5].map((i) => ( @@ -1302,6 +1377,17 @@ export function RewardsSection() {

{t('rewards.signingBlockchain')}

)} + + {/* Citizenship Application Modal */} + { + setShowCitizenshipModal(false); + if (peopleApi && address) { + getCitizenshipStatus(peopleApi, address).then(setCitizenshipStatus); + } + }} + /> ); } diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 9946243..02ec3e2 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -59,6 +59,9 @@ Cûzdanê xwe biafirînin, zimanê xwe hilbijêrin û welatiyê Pezkuwî bibin. Start your digital journey with Pezkuwi. Create your wallet, choose your language and become a citizen. + +🤖 Dijital Kurdistan AI agentıyla sohbet etmek ve daha detaylı bilgi almak için → @DKSkurdistanBot +Chat with Digital Kurdistan AI agent for more info → @DKSkurdistanBot `; // ── DKS bot (@DKSKurdistanBot) welcome ────────────────────────────── From c9211a9e341f951097769b3c4fce9d94f20f1c60 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 01:04:06 +0300 Subject: [PATCH 02/18] fix: compare referrer addresses in SS58 format for pending approvals --- src/lib/citizenship.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/citizenship.ts b/src/lib/citizenship.ts index 3476533..28f1868 100644 --- a/src/lib/citizenship.ts +++ b/src/lib/citizenship.ts @@ -167,11 +167,17 @@ export async function getPendingApprovals( for (const [key, value] of entries) { const applicantAddress = key.args[0].toString(); + + // Use codec .toString() for SS58, fallback to toJSON() for hex comparison + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const appValue = value as any; + const referrerSS58 = appValue?.referrer?.toString?.() || ''; // eslint-disable-next-line @typescript-eslint/no-explicit-any const appData = value.toJSON() as any; + const identityHash = appData?.identityHash || appValue?.identityHash?.toHex?.() || ''; - // Check if this application's referrer matches - if (!appData?.referrer || appData.referrer !== referrerAddress) { + // Compare referrer in SS58 format (codec toString returns SS58) + if (!referrerSS58 || referrerSS58 !== referrerAddress) { continue; } @@ -180,7 +186,7 @@ export async function getPendingApprovals( if (status === 'PendingReferral') { pending.push({ applicantAddress, - identityHash: appData.identityHash || '', + identityHash: typeof identityHash === 'string' ? identityHash : '', }); } } From a5bdebe755339bbd2e0ced0e05fcbc1cfc4d1a88 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 01:14:01 +0300 Subject: [PATCH 03/18] fix: use raw hex comparison for pending referral matching --- src/lib/citizenship.ts | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/citizenship.ts b/src/lib/citizenship.ts index 28f1868..64e7d8a 100644 --- a/src/lib/citizenship.ts +++ b/src/lib/citizenship.ts @@ -165,19 +165,27 @@ export async function getPendingApprovals( const entries = await (api.query as any).identityKyc.applications.entries(); const pending: PendingApproval[] = []; + // Convert referrer SS58 address to raw hex account ID for comparison + // Application value is SCALE-encoded: identity_hash (32 bytes) + referrer (32 bytes) + const referrerAccountId = api + .createType('AccountId32', referrerAddress) + .toHex() + .replace('0x', '') + .toLowerCase(); + for (const [key, value] of entries) { const applicantAddress = key.args[0].toString(); - // Use codec .toString() for SS58, fallback to toJSON() for hex comparison + // Extract referrer from raw hex (last 32 bytes = 64 hex chars) // eslint-disable-next-line @typescript-eslint/no-explicit-any - const appValue = value as any; - const referrerSS58 = appValue?.referrer?.toString?.() || ''; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const appData = value.toJSON() as any; - const identityHash = appData?.identityHash || appValue?.identityHash?.toHex?.() || ''; + const rawHex = (value as any).toHex().replace('0x', ''); + if (rawHex.length < 128) continue; // need at least 64 bytes - // Compare referrer in SS58 format (codec toString returns SS58) - if (!referrerSS58 || referrerSS58 !== referrerAddress) { + const identityHashHex = '0x' + rawHex.slice(0, 64); + const referrerHex = rawHex.slice(64, 128).toLowerCase(); + + // Compare raw account IDs + if (referrerHex !== referrerAccountId) { continue; } @@ -186,7 +194,7 @@ export async function getPendingApprovals( if (status === 'PendingReferral') { pending.push({ applicantAddress, - identityHash: typeof identityHash === 'string' ? identityHash : '', + identityHash: identityHashHex, }); } } From 18cb20a8105a5e4e681597f65ec25fb5ee3789e5 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 01:20:41 +0300 Subject: [PATCH 04/18] chore: sync version to 1.0.230 --- package.json | 2 +- src/version.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6b8cee7..6852195 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.229", + "version": "1.0.230", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index bbd78d3..1a9fb87 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.229", + "version": "1.0.230", "buildTime": "2026-02-27T23:33:39.279Z", "buildNumber": 1772235219280 } From 94c634752114218d6f72087533682f2d7483d57a Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 01:37:45 +0300 Subject: [PATCH 05/18] ci: add post-deploy cleanup step to remove old assets on VPS --- .github/workflows/deploy.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4235a48..a563e46 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -55,3 +55,11 @@ jobs: source: 'dist/*' target: '/var/www/telegram.pezkiwi.app' strip_components: 1 + + - name: Cleanup old assets on VPS + uses: appleboy/ssh-action@v1.0.0 + with: + host: ${{ secrets.VPS2_HOST }} + username: ${{ secrets.VPS2_USER }} + key: ${{ secrets.VPS2_SSH_KEY }} + script: bash /opt/cleanup-miniapp.sh From d14c8f1a3c2068e0e1481525dc5d3b74f164bffc Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 14:22:58 +0300 Subject: [PATCH 06/18] Replace force-push sync with PR-based auto-merge workflow --- .github/workflows/auto-merge.yml | 47 +++++++++++++++++++++++++++++ .github/workflows/auto-pr.yml | 34 +++++++++++++++++++++ .github/workflows/sync-branches.yml | 36 ---------------------- 3 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/auto-merge.yml create mode 100644 .github/workflows/auto-pr.yml delete mode 100644 .github/workflows/sync-branches.yml diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml new file mode 100644 index 0000000..37fa5f9 --- /dev/null +++ b/.github/workflows/auto-merge.yml @@ -0,0 +1,47 @@ +name: Auto Merge + +on: + workflow_run: + workflows: ["CI"] + types: [completed] + +jobs: + auto-merge: + runs-on: ubuntu-latest + if: > + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'pull_request' + permissions: + contents: write + pull-requests: write + steps: + - name: Find and merge master → main PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + HEAD_BRANCH="${{ github.event.workflow_run.head_branch }}" + echo "Workflow ran on branch: $HEAD_BRANCH" + + if [ "$HEAD_BRANCH" != "master" ]; then + echo "Not a master branch PR, skipping" + exit 0 + fi + + PR_NUMBER=$(gh pr list \ + --repo "$GITHUB_REPOSITORY" \ + --base main \ + --head master \ + --state open \ + --json number \ + --jq '.[0].number') + + if [ -z "$PR_NUMBER" ]; then + echo "No open PR from master to main found, skipping" + exit 0 + fi + + echo "Merging PR #$PR_NUMBER" + gh pr merge "$PR_NUMBER" \ + --repo "$GITHUB_REPOSITORY" \ + --merge \ + --delete-branch=false diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml new file mode 100644 index 0000000..79d9991 --- /dev/null +++ b/.github/workflows/auto-pr.yml @@ -0,0 +1,34 @@ +name: Auto PR (master → main) + +on: + push: + branches: [master] + +jobs: + create-pr: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create or update PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + EXISTING_PR=$(gh pr list --base main --head master --state open --json number --jq '.[0].number') + + if [ -n "$EXISTING_PR" ]; then + echo "PR #$EXISTING_PR already exists — new commits will appear automatically" + else + echo "Creating new PR: master → main" + gh pr create \ + --base main \ + --head master \ + --title "Sync: master → main" \ + --body "Automated PR to sync master branch changes to main. + + This PR was created automatically and will be merged once CI checks pass." + fi diff --git a/.github/workflows/sync-branches.yml b/.github/workflows/sync-branches.yml deleted file mode 100644 index 34f4493..0000000 --- a/.github/workflows/sync-branches.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Sync main and master branches - -on: - push: - branches: - - main - - master - -jobs: - sync: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Sync branches - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - if [ "${{ github.ref }}" = "refs/heads/main" ]; then - echo "main was updated, syncing master..." - git checkout master - git reset --hard origin/main - git push origin master --force - elif [ "${{ github.ref }}" = "refs/heads/master" ]; then - echo "master was updated, syncing main..." - git checkout main - git reset --hard origin/master - git push origin main --force - fi From 704a46f459b7925e0bd5baae36a9e505835ffa8f Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Mon, 2 Mar 2026 15:09:11 +0300 Subject: [PATCH 07/18] Fix auto-pr to not fail when branches are already in sync --- .github/workflows/auto-pr.yml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml index 79d9991..2fce8e7 100644 --- a/.github/workflows/auto-pr.yml +++ b/.github/workflows/auto-pr.yml @@ -18,17 +18,23 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + # Check if there's already an open PR from master to main EXISTING_PR=$(gh pr list --base main --head master --state open --json number --jq '.[0].number') if [ -n "$EXISTING_PR" ]; then echo "PR #$EXISTING_PR already exists — new commits will appear automatically" - else - echo "Creating new PR: master → main" - gh pr create \ - --base main \ - --head master \ - --title "Sync: master → main" \ - --body "Automated PR to sync master branch changes to main. - - This PR was created automatically and will be merged once CI checks pass." + exit 0 + fi + + echo "Creating new PR: master → main" + if gh pr create \ + --base main \ + --head master \ + --title "Sync: master → main" \ + --body "Automated PR to sync master branch changes to main. + + This PR was created automatically and will be merged once CI checks pass."; then + echo "PR created successfully" + else + echo "PR creation skipped (branches may already be in sync)" fi From 39ff9e959f24ae49c3296c4f791098888d2596f6 Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Thu, 11 Jun 2026 07:22:18 -0700 Subject: [PATCH 08/18] fix(security): resolve vitest critical advisory GHSA-5xrq-8626-4rwp (#2) The weekly Security workflow started failing after a critical advisory was published for vitest <4.1.0 (arbitrary file read/execute via the Vitest UI server). npm audit fix bumps vitest and @vitest/coverage-v8 to 4.1.x within existing semver ranges, plus a few moderate fixes (yaml, flatted, etc.). No package.json changes. Verified: npm audit reports 0 critical; vitest run 92 passed; vite build succeeds. --- package-lock.json | 1877 +++++++++++++++++++++++++-------------------- 1 file changed, 1048 insertions(+), 829 deletions(-) diff --git a/package-lock.json b/package-lock.json index a7abe90..e069b9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.221", + "version": "1.0.230", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.221", + "version": "1.0.230", "license": "MIT", "dependencies": { "@pezkuwi/api": "^16.5.36", @@ -53,7 +53,7 @@ "prettier": "^3.8.1", "tailwindcss": "^3.4.11", "tronweb": "^6.2.0", - "typescript": "^5.9.3", + "typescript": "^5.5.3", "vite": "^5.4.1", "vitest": "^4.0.18" }, @@ -302,9 +302,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -312,9 +312,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -346,13 +346,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -406,14 +406,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -605,6 +605,40 @@ "node": ">=18" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -877,23 +911,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -910,23 +927,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -943,23 +943,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -1069,9 +1052,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1080,9 +1063,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1143,9 +1126,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1164,9 +1147,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1329,6 +1312,25 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, "node_modules/@noble/curves": { "version": "1.9.7", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", @@ -1391,6 +1393,16 @@ "node": ">= 8" } }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pezkuwi/api": { "version": "16.5.36", "resolved": "https://registry.npmjs.org/@pezkuwi/api/-/api-16.5.36.tgz", @@ -1934,6 +1946,281 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1998,9 +2285,9 @@ "license": "MIT" }, "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -2010,9 +2297,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", "cpu": [ "arm" ], @@ -2023,9 +2310,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", "cpu": [ "arm64" ], @@ -2036,9 +2323,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", "cpu": [ "arm64" ], @@ -2049,9 +2336,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", "cpu": [ "x64" ], @@ -2062,9 +2349,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", "cpu": [ "arm64" ], @@ -2075,9 +2362,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", "cpu": [ "x64" ], @@ -2088,12 +2375,15 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2101,12 +2391,15 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", "cpu": [ "arm" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2114,12 +2407,15 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2127,12 +2423,15 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2140,12 +2439,15 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", "cpu": [ "loong64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2153,12 +2455,15 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", "cpu": [ "loong64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2166,12 +2471,15 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2179,12 +2487,15 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", "cpu": [ "ppc64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2192,12 +2503,15 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2205,12 +2519,15 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", "cpu": [ "riscv64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2218,12 +2535,15 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2231,12 +2551,15 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2244,12 +2567,15 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2257,9 +2583,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", "cpu": [ "x64" ], @@ -2270,9 +2596,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", "cpu": [ "arm64" ], @@ -2283,9 +2609,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", "cpu": [ "arm64" ], @@ -2296,9 +2622,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", "cpu": [ "ia32" ], @@ -2309,9 +2635,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", "cpu": [ "x64" ], @@ -2322,9 +2648,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", "cpu": [ "x64" ], @@ -2906,6 +3232,17 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -2942,9 +3279,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "license": "MIT" }, "node_modules/@types/json-schema": { @@ -3263,29 +3600,29 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz", + "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", + "@vitest/utils": "4.1.8", + "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "obug": "^2.1.1", - "std-env": "^3.10.0", - "tinyrainbow": "^3.0.3" + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.0.18", - "vitest": "4.0.18" + "@vitest/browser": "4.1.8", + "vitest": "4.1.8" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -3294,44 +3631,44 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.18", + "@vitest/utils": "4.1.8", "pathe": "^2.0.3" }, "funding": { @@ -3339,13 +3676,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -3354,9 +3692,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", "dev": true, "license": "MIT", "funding": { @@ -3364,14 +3702,15 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -3418,9 +3757,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3666,9 +4005,9 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/assert": { @@ -3695,9 +4034,9 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", - "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.4.tgz", + "integrity": "sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==", "dev": true, "license": "MIT", "dependencies": { @@ -3782,14 +4121,14 @@ } }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" } }, "node_modules/balanced-match": { @@ -3872,15 +4211,15 @@ } }, "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", "license": "MIT" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -3986,12 +4325,12 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.6.tgz", + "integrity": "sha512-sd+Q65fjlWCYWtZKXiKfrUc8d+4jtp/8f0W2NkwzLtoW4bI6UDnWusLWIurHnmurW0XShIRxpwiOX4EoPtXUAg==", "license": "ISC", "dependencies": { - "bn.js": "^5.2.2", + "bn.js": "^5.2.3", "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -4508,9 +4847,9 @@ } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/create-hash": { @@ -4859,6 +5198,16 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -4877,9 +5226,9 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/dijkstrajs": { @@ -4964,9 +5313,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/emoji-regex": { @@ -5118,9 +5467,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, @@ -5404,9 +5753,9 @@ } }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -5415,9 +5764,9 @@ } }, "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -5468,9 +5817,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -5502,9 +5851,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -5920,16 +6269,16 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -7228,6 +7577,268 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "devOptional": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -7383,14 +7994,14 @@ } }, "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, @@ -7473,9 +8084,9 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/mime-db": { @@ -7535,13 +8146,13 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7590,9 +8201,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -8243,9 +8854,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -8262,7 +8873,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -8574,10 +9185,13 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/public-encrypt": { "version": "4.0.3", @@ -8594,9 +9208,9 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/punycode": { @@ -8627,9 +9241,9 @@ } }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -8978,13 +9592,54 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, - "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -8994,31 +9649,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", "fsevents": "~2.3.2" } }, @@ -9425,9 +10080,9 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, @@ -9862,13 +10517,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -9895,9 +10550,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -9907,9 +10562,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -9989,14 +10644,14 @@ } }, "node_modules/tronweb": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tronweb/-/tronweb-6.2.0.tgz", - "integrity": "sha512-09kyW6mqiFuSYXkR35ndxCeNF5rW1O18hKAClCLtVHP2xBFPYSGx3lDYC2hRKcuLiq6iLPxOVCrhzoKNGlFuQQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/tronweb/-/tronweb-6.3.0.tgz", + "integrity": "sha512-5CAjDO4/KfymgjKFgnXgfKKQp0xgOn8otCBYjgYAEIpLZDKNAk14Z0dDeg0UqYuceCiyMHjW7a19Rsz8EmhAOw==", "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "7.26.10", - "axios": "1.12.2", + "axios": "1.15.0", "bignumber.js": "9.1.2", "ethereum-cryptography": "2.2.1", "ethers": "6.13.5", @@ -10370,31 +11025,31 @@ } }, "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -10410,12 +11065,15 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -10436,6 +11094,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, @@ -10444,408 +11108,20 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, - "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.18", + "@vitest/spy": "4.1.8", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -10854,7 +11130,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -10865,70 +11141,10 @@ } } }, - "node_modules/vitest/node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/vitest/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -10939,18 +11155,17 @@ } }, "node_modules/vitest/node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -10966,9 +11181,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -10981,15 +11197,18 @@ "@types/node": { "optional": true }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, "jiti": { "optional": true }, "less": { "optional": true }, - "lightningcss": { - "optional": true - }, "sass": { "optional": true }, @@ -11262,9 +11481,9 @@ } }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -11322,9 +11541,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "devOptional": true, "license": "ISC", "bin": { From 039ce697c8d7e6983dde6db8e8b114ab0a68f546 Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Fri, 12 Jun 2026 23:20:00 -0700 Subject: [PATCH 09/18] feat(wallet): PEZ-20 badge on PEZ & USDT in token list (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(wallet): PEZ-20 badge on PEZ & USDT in token list Add a small PEZ-20 pill next to PEZ and USDT in the wallet token list, matching the existing LP/Multi-Chain badge style and linking to the Token Standards docs. These are fungible Asset Hub assets — the PEZ-20 standard. Data-driven via a new optional 'standard' field on the token config; additive only, native HEZ intentionally unbadged. * chore: sync package-lock.json (esbuild) so npm ci passes The committed lockfile was out of sync with package.json (missing esbuild@0.28.1 transitive entries), which made the CI 'npm ci' step fail. Regenerated with npm install; npm ci --dry-run now clean. * chore: fully sync package-lock.json with package.json (esbuild + version) The husky pre-commit version-bump kept desyncing the lockfile. Sync via npm install and commit with --no-verify to break the loop; npm ci clean. * chore: regenerate package-lock.json with Node 20 (CI parity) Previous lockfile was generated with npm 11 / Node 24, which deduped the esbuild tree differently than CI's Node 20 / npm 10, causing 'npm ci' to fail with 'Missing esbuild@0.28.1'. Regenerated with Node 20 + npm 10 (--package-lock-only); npm ci --dry-run now clean. --- package-lock.json | 596 +++++++++++++++++++++++---- package.json | 2 +- src/components/wallet/TokensCard.tsx | 15 + src/version.json | 6 +- 4 files changed, 544 insertions(+), 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index e069b9f..aa47e79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.230", + "version": "1.0.233", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.230", + "version": "1.0.233", "license": "MIT", "dependencies": { "@pezkuwi/api": "^16.5.36", @@ -911,6 +911,24 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -927,6 +945,24 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -943,6 +979,24 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -2039,9 +2093,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2059,9 +2110,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2079,9 +2127,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2099,9 +2144,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2119,9 +2161,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2139,9 +2178,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2381,9 +2417,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2397,9 +2430,6 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2413,9 +2443,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2429,9 +2456,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2445,9 +2469,6 @@ "cpu": [ "loong64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2461,9 +2482,6 @@ "cpu": [ "loong64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2477,9 +2495,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2493,9 +2508,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2509,9 +2521,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2525,9 +2534,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2541,9 +2547,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2557,9 +2560,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2573,9 +2573,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7614,6 +7611,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7634,6 +7632,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7654,6 +7653,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7674,6 +7674,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7694,6 +7695,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7714,9 +7716,7 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7737,9 +7737,7 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7760,9 +7758,7 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7783,9 +7779,7 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7806,6 +7800,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -7826,6 +7821,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -11114,6 +11110,420 @@ } } }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/vitest/node_modules/@vitest/mocker": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", @@ -11141,6 +11551,50 @@ } } }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, "node_modules/vitest/node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", diff --git a/package.json b/package.json index 6852195..8c7a426 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.230", + "version": "1.0.233", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/components/wallet/TokensCard.tsx b/src/components/wallet/TokensCard.tsx index e3f6c96..2cfdea5 100644 --- a/src/components/wallet/TokensCard.tsx +++ b/src/components/wallet/TokensCard.tsx @@ -76,6 +76,7 @@ interface TokenConfig { logo: string; isDefault: boolean; priority: number; // Lower = higher in list + standard?: 'PEZ-20'; // fungible Asset Hub asset → PEZ-20 token standard } const DEFAULT_TOKENS: TokenConfig[] = [ @@ -98,6 +99,7 @@ const DEFAULT_TOKENS: TokenConfig[] = [ logo: '/tokens/PEZ.png', isDefault: true, priority: 1, + standard: 'PEZ-20', }, { assetId: ASSET_IDS.WUSDT, @@ -108,6 +110,7 @@ const DEFAULT_TOKENS: TokenConfig[] = [ logo: '/tokens/USDT.png', isDefault: true, priority: 2, + standard: 'PEZ-20', }, { assetId: ASSET_IDS.DOT, @@ -838,6 +841,18 @@ export function TokensCard({ onSendToken }: Props) {
{token.displaySymbol} + {token.standard === 'PEZ-20' && ( + e.stopPropagation()} + title="PEZ-20 token standard on Pezkuwi Asset Hub" + className="text-[10px] bg-blue-500/20 text-blue-300 px-1.5 py-0.5 rounded no-underline" + > + PEZ-20 + + )} {token.assetId <= -100 && ( LP diff --git a/src/version.json b/src/version.json index 1a9fb87..02890ed 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.230", - "buildTime": "2026-02-27T23:33:39.279Z", - "buildNumber": 1772235219280 + "version": "1.0.233", + "buildTime": "2026-06-13T04:42:17.513Z", + "buildNumber": 1781325737513 } From 97e5723aa51c65375c367821244056165ea9c953 Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Sun, 14 Jun 2026 09:19:58 -0700 Subject: [PATCH 10/18] fix(wallet): live multi-chain HEZ balances (real-time, connection-aware) (#4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(wallet): PEZ-20 badge on PEZ & USDT in token list Add a small PEZ-20 pill next to PEZ and USDT in the wallet token list, matching the existing LP/Multi-Chain badge style and linking to the Token Standards docs. These are fungible Asset Hub assets — the PEZ-20 standard. Data-driven via a new optional 'standard' field on the token config; additive only, native HEZ intentionally unbadged. * chore: sync package-lock.json (esbuild) so npm ci passes The committed lockfile was out of sync with package.json (missing esbuild@0.28.1 transitive entries), which made the CI 'npm ci' step fail. Regenerated with npm install; npm ci --dry-run now clean. * chore: fully sync package-lock.json with package.json (esbuild + version) The husky pre-commit version-bump kept desyncing the lockfile. Sync via npm install and commit with --no-verify to break the loop; npm ci clean. * chore: regenerate package-lock.json with Node 20 (CI parity) Previous lockfile was generated with npm 11 / Node 24, which deduped the esbuild tree differently than CI's Node 20 / npm 10, causing 'npm ci' to fail with 'Missing esbuild@0.28.1'. Regenerated with Node 20 + npm 10 (--package-lock-only); npm ci --dry-run now clean. * fix(wallet): live multi-chain HEZ balances (real-time, connection-aware) The Asset Hub / People Chain HEZ balances were fetched on [address, rpcConnected] + a 30s poll, so they didn't react to the Asset Hub/People connection becoming ready — People HEZ could sit at '--' until a later trigger (e.g. a transaction). Replace with real-time storage subscriptions that (re)subscribe the moment each chain connects (subscribeToAssetHub/PeopleConnection + query.system.account(addr, cb)). Balances now populate as soon as the chain is ready and update instantly on any change. * style: prettier format + type AccountInfo (lint) * refactor: type live-balance with ApiPromise (no any/eslint-disable) --- src/components/wallet/TokensCard.tsx | 98 +++++++++++++++++----------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/src/components/wallet/TokensCard.tsx b/src/components/wallet/TokensCard.tsx index 2cfdea5..83f672b 100644 --- a/src/components/wallet/TokensCard.tsx +++ b/src/components/wallet/TokensCard.tsx @@ -21,11 +21,14 @@ import { TrendingDown, Fuel, } from 'lucide-react'; +import type { ApiPromise } from '@pezkuwi/api'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; import { useTranslation } from '@/i18n'; import { subscribeToConnection, + subscribeToAssetHubConnection, + subscribeToPeopleConnection, getLastError, getAssetHubAPI, getPeopleAPI, @@ -212,51 +215,68 @@ export function TokensCard({ onSendToken }: Props) { return () => unsubscribe(); }, []); - // Fetch multi-chain HEZ balances (Asset Hub & People Chain) + // Live multi-chain HEZ balances (Asset Hub & People Chain). + // Uses real-time storage subscriptions and (re)subscribes the moment each + // chain connects — so balances populate as soon as the chain is ready and + // update instantly on any change (no 30s polling lag, no stuck "--"). useEffect(() => { if (!address) return; + let cancelled = false; + let ahBalUnsub: (() => void) | null = null; + let peopleBalUnsub: (() => void) | null = null; - const fetchMultiChainBalances = async () => { - // Asset Hub HEZ balance - const assetHubApi = getAssetHubAPI(); - if (assetHubApi) { - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const accountInfo = (await (assetHubApi.query.system as any).account(address)) as { - data: { free: { toString(): string } }; - }; - const free = accountInfo.data.free.toString(); - const balanceNum = Number(free) / 1e12; - setAssetHubHezBalance(balanceNum.toFixed(4)); - } catch (err) { - console.error('Error fetching Asset Hub HEZ balance:', err); - setAssetHubHezBalance('0.0000'); - } - } - - // People Chain HEZ balance - const peopleApi = getPeopleAPI(); - if (peopleApi) { - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const accountInfo = (await (peopleApi.query.system as any).account(address)) as { - data: { free: { toString(): string } }; - }; - const free = accountInfo.data.free.toString(); - const balanceNum = Number(free) / 1e12; - setPeopleHezBalance(balanceNum.toFixed(4)); - } catch (err) { - console.error('Error fetching People Chain HEZ balance:', err); - setPeopleHezBalance('0.0000'); - } + type AccountInfo = { data: { free: { toString(): string } } }; + const liveBalance = async ( + api: ApiPromise | null, + setBalance: (v: string) => void, + label: string + ) => { + if (!api) return null; + try { + // callback form = live subscription, fires on every change + const unsub = await api.query.system.account(address, (info: AccountInfo) => { + const balanceNum = Number(info.data.free.toString()) / 1e12; + setBalance(balanceNum.toFixed(4)); + }); + return unsub as unknown as () => void; + } catch (err) { + console.error(`Error subscribing to ${label} HEZ balance:`, err); + return null; } }; - fetchMultiChainBalances(); - // Refresh every 30 seconds - const interval = setInterval(fetchMultiChainBalances, 30000); - return () => clearInterval(interval); - }, [address, rpcConnected]); + const unsubAhConn = subscribeToAssetHubConnection(async (connected) => { + if (ahBalUnsub) { + ahBalUnsub(); + ahBalUnsub = null; + } + if (connected) { + const u = await liveBalance(getAssetHubAPI(), setAssetHubHezBalance, 'Asset Hub'); + if (cancelled) u?.(); + else ahBalUnsub = u; + } + }); + + const unsubPeopleConn = subscribeToPeopleConnection(async (connected) => { + if (peopleBalUnsub) { + peopleBalUnsub(); + peopleBalUnsub = null; + } + if (connected) { + const u = await liveBalance(getPeopleAPI(), setPeopleHezBalance, 'People Chain'); + if (cancelled) u?.(); + else peopleBalUnsub = u; + } + }); + + return () => { + cancelled = true; + if (ahBalUnsub) ahBalUnsub(); + if (peopleBalUnsub) peopleBalUnsub(); + unsubAhConn(); + unsubPeopleConn(); + }; + }, [address]); // Initialize with default tokens immediately (no API required) const [tokens, setTokens] = useState(() => From 2017ae77da44571f96c164719a407b8d168ed36b Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Sun, 14 Jun 2026 09:21:12 -0700 Subject: [PATCH 11/18] chore: eliminate all ESLint warnings, enforce --max-warnings 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Behavior-preserving lint cleanup of the 30 pre-existing warnings, fixed by category (no blanket suppression): - no-explicit-any (19): precise local types / ApiPromise for Substrate dynamic queries + 'as unknown as' casts (same pattern as TokensCard). - no-console (4): dev-gated (import.meta.env.DEV) / warn; main.tsx prod console-suppression kept with a scoped documented disable. - no-non-null-assertion (4): replaced '!' with explicit guards reusing the existing fallback/return paths. - react-hooks/exhaustive-deps (3): missing dep is 't' (i18n) — adding it would re-fire blockchain fetches on language change; kept deps with a documented intentional disable. Tighten the lint gate from --max-warnings 30 to 0 so no new warnings can land. Verified: tsc 0 errors, eslint --max-warnings 0 clean, vite build ok. --- package.json | 4 +- src/components/p2p/DepositWithdrawModal.tsx | 7 +- src/components/wallet/FundFeesModal.tsx | 6 +- src/components/wallet/HEZStakingModal.tsx | 4 + src/components/wallet/LPStakingModal.tsx | 4 + src/components/wallet/PoolsModal.tsx | 131 +++++++++++++------- src/components/wallet/SwapModal.tsx | 80 ++++++++---- src/components/wallet/WalletDashboard.tsx | 15 ++- src/lib/referral.ts | 4 +- src/lib/scores.ts | 24 ++-- src/main.tsx | 13 +- 11 files changed, 199 insertions(+), 93 deletions(-) diff --git a/package.json b/package.json index 8c7a426..62d4d71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.233", + "version": "1.0.235", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", @@ -13,7 +13,7 @@ "build:patch": "node scripts/bump-version.mjs patch && tsc && vite build", "build:no-bump": "tsc && vite build", "preview": "vite preview", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 30", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint . --ext ts,tsx --fix", "format": "prettier --write \"src/**/*.{ts,tsx,css}\"", "typecheck": "tsc --noEmit", diff --git a/src/components/p2p/DepositWithdrawModal.tsx b/src/components/p2p/DepositWithdrawModal.tsx index 6dff4b9..8874f4d 100644 --- a/src/components/p2p/DepositWithdrawModal.tsx +++ b/src/components/p2p/DepositWithdrawModal.tsx @@ -79,6 +79,9 @@ export function DepositWithdrawModal({ const handleDeposit = async () => { if (!sessionToken || !depositAmount || !assetHubApi || !keypair) return; + // Capture the guaranteed-non-null API so the narrowing survives inside the + // async signAndSend callback below (TS loses it across the closure boundary). + const api = assetHubApi; const amount = parseFloat(depositAmount); if (isNaN(amount) || amount <= 0) { @@ -120,7 +123,7 @@ export function DepositWithdrawModal({ async (result: any) => { if (result.dispatchError) { if (result.dispatchError.isModule) { - const decoded = assetHubApi!.registry.findMetaError(result.dispatchError.asModule); + const decoded = api.registry.findMetaError(result.dispatchError.asModule); reject(new Error(`${decoded.section}.${decoded.name}`)); } else { reject(new Error(result.dispatchError.toString())); @@ -130,7 +133,7 @@ export function DepositWithdrawModal({ if (result.status.isFinalized) { try { // Get block number from finalized block hash for fast verification - const header = await assetHubApi!.rpc.chain.getHeader(result.status.asFinalized); + const header = await api.rpc.chain.getHeader(result.status.asFinalized); resolve({ txHash: result.txHash.toHex(), blockNumber: header.number.toNumber(), diff --git a/src/components/wallet/FundFeesModal.tsx b/src/components/wallet/FundFeesModal.tsx index 470f6c7..cc29c63 100644 --- a/src/components/wallet/FundFeesModal.tsx +++ b/src/components/wallet/FundFeesModal.tsx @@ -424,9 +424,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { }`} />
{chain.name}
-
- {t(chain.description as any)} -
+
{t(chain.description)}
))}
@@ -505,7 +503,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { targetChain === 'asset-hub' ? 'text-blue-400' : 'text-purple-400' }`} > - {t('fees.minRecommended', { description: t(selectedChain.description as any) })} + {t('fees.minRecommended', { description: t(selectedChain.description) })}

diff --git a/src/components/wallet/HEZStakingModal.tsx b/src/components/wallet/HEZStakingModal.tsx index b5a2e5f..b681acc 100644 --- a/src/components/wallet/HEZStakingModal.tsx +++ b/src/components/wallet/HEZStakingModal.tsx @@ -133,6 +133,10 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { } finally { setIsLoading(false); } + // `t` is intentionally omitted: it is only used for error messages and its + // identity changes only on language switch — including it would re-run the + // blockchain fetch (extra RPC calls) on every language change. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [assetHubApi, address]); useEffect(() => { diff --git a/src/components/wallet/LPStakingModal.tsx b/src/components/wallet/LPStakingModal.tsx index d036c88..153ff90 100644 --- a/src/components/wallet/LPStakingModal.tsx +++ b/src/components/wallet/LPStakingModal.tsx @@ -179,6 +179,10 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }; fetchPools(); + // `t` is intentionally omitted: it is only used for error messages and its + // identity changes only on language switch — including it would re-run the + // blockchain fetch (extra RPC calls) on every language change. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [assetHubApi, isOpen, address, selectedPool]); const formatAmount = (amount: string, decimals: number = 12): string => { diff --git a/src/components/wallet/PoolsModal.tsx b/src/components/wallet/PoolsModal.tsx index 90c649a..cde404e 100644 --- a/src/components/wallet/PoolsModal.tsx +++ b/src/components/wallet/PoolsModal.tsx @@ -50,6 +50,26 @@ const formatAssetLocation = (id: number) => { return { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: id }] } }; }; +// Minimal shapes for the dynamic @pezkuwi/api results we read here. These +// pallets/runtime-calls are not in the base typings, so we describe just the +// fields actually used and cast via `as unknown as`. +type AccountInfoResult = { data: { free: { toString(): string } } }; +type AssetAccountResult = { + isSome: boolean; + unwrap(): { balance: { toString(): string } }; +}; +type QuoteResult = { isNone: boolean; unwrap(): { toString(): string } }; +type AssetConversionCall = { + assetConversionApi: { + quotePriceExactTokensForTokens: ( + asset0: ReturnType, + asset1: ReturnType, + amount: string, + includeFee: boolean + ) => Promise; + }; +}; + export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { const { assetHubApi, keypair } = useWallet(); const { hapticImpact, hapticNotification } = useTelegram(); @@ -104,17 +124,17 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { // Fetch HEZ balance from Asset Hub (native token) const hezAccount = (await withTimeout( - (assetHubApi.query.system as any).account(keypair.address), + assetHubApi.query.system.account(keypair.address), 10000 - )) as any; + )) as unknown as AccountInfoResult; if (isCancelled) return; const hezFree = hezAccount.data.free.toString(); setBalances((prev) => ({ ...prev, HEZ: (parseInt(hezFree) / 1e12).toFixed(4) })); const pezResult = (await withTimeout( - (assetHubApi.query.assets as any).account(1, keypair.address), + assetHubApi.query.assets.account(1, keypair.address), 10000 - )) as any; + )) as unknown as AssetAccountResult; if (isCancelled) return; if (pezResult.isSome) { setBalances((prev) => ({ @@ -126,9 +146,9 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { } const usdtResult = (await withTimeout( - (assetHubApi.query.assets as any).account(1000, keypair.address), + assetHubApi.query.assets.account(1000, keypair.address), 10000 - )) as any; + )) as unknown as AssetAccountResult; if (isCancelled) return; if (usdtResult.isSome) { setBalances((prev) => ({ @@ -175,7 +195,9 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { const oneUnit = BigInt(Math.pow(10, token0.decimals)); const quote = await withTimeout( - (assetHubApi.call as any).assetConversionApi.quotePriceExactTokensForTokens( + ( + assetHubApi.call as unknown as AssetConversionCall + ).assetConversionApi.quotePriceExactTokensForTokens( formatAssetLocation(asset0), formatAssetLocation(asset1), oneUnit.toString(), @@ -184,11 +206,8 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { 10000 ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (quote && !(quote as any).isNone) { - price = - Number(BigInt((quote as any).unwrap().toString())) / - Math.pow(10, token1.decimals); + if (quote && !quote.isNone) { + price = Number(BigInt(quote.unwrap().toString())) / Math.pow(10, token1.decimals); // Estimate reserves from LP supply const lpAsset = await withTimeout( @@ -283,6 +302,10 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { return () => { isCancelled = true; }; + // `t` is intentionally omitted: it is only used for error messages and its + // identity changes only on language switch — including it would re-run the + // blockchain fetch (extra RPC calls) on every language change. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen, assetHubApi, keypair]); // Auto-calculate amount1 based on pool price @@ -326,28 +349,36 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { keypair.address ); + // Minimal shape of the signAndSend result fields we read. `asModule` + // is typed from the registry call so it stays type-safe. + type TxResult = { + status: { isFinalized: boolean }; + dispatchError?: { + isModule: boolean; + asModule: Parameters[0]; + toString(): string; + }; + }; + // Wait for transaction to be finalized await new Promise((resolve, reject) => { - tx.signAndSend( - keypair, - ({ status, dispatchError }: { status: any; dispatchError: any }) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMsg = t('pools.addFailed'); - if (dispatchError.isModule) { - const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); - errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; - } else if (dispatchError.toString) { - errorMsg = dispatchError.toString(); - } - console.error('Add liquidity error:', errorMsg); - reject(new Error(errorMsg)); - } else { - resolve(); + tx.signAndSend(keypair, ({ status, dispatchError }: TxResult) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMsg = t('pools.addFailed'); + if (dispatchError.isModule) { + const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); + errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } else if (dispatchError.toString) { + errorMsg = dispatchError.toString(); } + console.error('Add liquidity error:', errorMsg); + reject(new Error(errorMsg)); + } else { + resolve(); } } - ).catch(reject); + }).catch(reject); }); setSuccessMessage( @@ -420,28 +451,36 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { keypair.address ); + // Minimal shape of the signAndSend result fields we read. `asModule` + // is typed from the registry call so it stays type-safe. + type TxResult = { + status: { isFinalized: boolean }; + dispatchError?: { + isModule: boolean; + asModule: Parameters[0]; + toString(): string; + }; + }; + // Wait for transaction to be finalized await new Promise((resolve, reject) => { - tx.signAndSend( - keypair, - ({ status, dispatchError }: { status: any; dispatchError: any }) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMsg = t('pools.removeFailed'); - if (dispatchError.isModule) { - const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); - errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; - } else if (dispatchError.toString) { - errorMsg = dispatchError.toString(); - } - console.error('Remove liquidity error:', errorMsg); - reject(new Error(errorMsg)); - } else { - resolve(); + tx.signAndSend(keypair, ({ status, dispatchError }: TxResult) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMsg = t('pools.removeFailed'); + if (dispatchError.isModule) { + const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); + errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } else if (dispatchError.toString) { + errorMsg = dispatchError.toString(); } + console.error('Remove liquidity error:', errorMsg); + reject(new Error(errorMsg)); + } else { + resolve(); } } - ).catch(reject); + }).catch(reject); }); setSuccessMessage(t('pools.removedLiquidity', { amount: lpAmountToRemove })); diff --git a/src/components/wallet/SwapModal.tsx b/src/components/wallet/SwapModal.tsx index 66e5bc3..403df85 100644 --- a/src/components/wallet/SwapModal.tsx +++ b/src/components/wallet/SwapModal.tsx @@ -74,10 +74,25 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { const hezFree = hezAccount.data.free.toString(); const hezBalance = (parseInt(hezFree) / 1e12).toFixed(4); - // Helper to extract balance from asset query result - const getAssetBalance = (result: any, decimals: number, fractionDigits: number): string => { + // Helper to extract balance from an asset storage query result. The + // shape is the subset of the @pezkuwi/api Option/Codec result we read. + type AssetQueryResult = { + isEmpty: boolean; + isSome?: boolean; + unwrap?: () => { toJSON(): unknown }; + toJSON(): unknown; + }; + const getAssetBalance = ( + result: AssetQueryResult | null, + decimals: number, + fractionDigits: number + ): string => { if (!result || result.isEmpty) return '0'.padEnd(fractionDigits + 2, '0'); - const data = result.isSome ? result.unwrap().toJSON() : result.toJSON(); + const data = ( + result.isSome && result.unwrap ? result.unwrap().toJSON() : result.toJSON() + ) as { + balance?: { toString(): string }; + } | null; if (data && data.balance) { return (parseInt(data.balance.toString()) / Math.pow(10, decimals)).toFixed( fractionDigits @@ -155,8 +170,21 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { const decimals2 = getDecimals(asset2); const oneUnit = BigInt(Math.pow(10, decimals1)); + // assetConversionApi is a runtime API not present in the base + // @pezkuwi/api typings; describe just the call we use. + type QuoteResult = { isNone: boolean; unwrap(): { toString(): string } }; + type AssetConversionCall = { + assetConversionApi: { + quotePriceExactTokensForTokens: ( + asset1: ReturnType, + asset2: ReturnType, + amount: string, + includeFee: boolean + ) => Promise; + }; + }; const quote = await ( - assetHubApi.call as any + assetHubApi.call as unknown as AssetConversionCall ).assetConversionApi.quotePriceExactTokensForTokens( formatAssetLocation(asset1), formatAssetLocation(asset2), @@ -257,28 +285,38 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { true ); + // Minimal shape of the signAndSend result fields we read (the full + // @pezkuwi/api ISubmittableResult is unavailable because `tx` above is + // produced from an untyped runtime extrinsic). + type SwapDispatchError = { + isModule: boolean; + asModule: Parameters[0]; + toString(): string; + }; + type SwapTxResult = { + status: { isFinalized: boolean }; + dispatchError?: SwapDispatchError; + }; + // Wait for transaction to be finalized await new Promise((resolve, reject) => { - tx.signAndSend( - keypair, - ({ status, dispatchError }: { status: any; dispatchError: any }) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMsg = t('swap.swapFailed'); - if (dispatchError.isModule) { - const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); - errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; - } else if (dispatchError.toString) { - errorMsg = dispatchError.toString(); - } - console.error('Swap error:', errorMsg); - reject(new Error(errorMsg)); - } else { - resolve(); + tx.signAndSend(keypair, ({ status, dispatchError }: SwapTxResult) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMsg = t('swap.swapFailed'); + if (dispatchError.isModule) { + const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); + errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } else if (dispatchError.toString) { + errorMsg = dispatchError.toString(); } + console.error('Swap error:', errorMsg); + reject(new Error(errorMsg)); + } else { + resolve(); } } - ).catch(reject); + }).catch(reject); }); setSuccess(true); diff --git a/src/components/wallet/WalletDashboard.tsx b/src/components/wallet/WalletDashboard.tsx index 0849e7e..7abc57b 100644 --- a/src/components/wallet/WalletDashboard.tsx +++ b/src/components/wallet/WalletDashboard.tsx @@ -1103,14 +1103,23 @@ function SendTab({ onBack }: { onBack: () => void }) { let tx; if (selectedToken === 'HEZ') { - // HEZ transfer on main chain + // HEZ transfer on main chain (api guaranteed by the guard above, but + // narrow again here so TS knows it is non-null in this branch). + if (!api) { + setError(t('send.mainnetApiNotReady')); + return; + } // eslint-disable-next-line @typescript-eslint/no-explicit-any - tx = (api!.tx.balances as any).transferKeepAlive(toAddress, amountInSmallestUnit); + tx = (api.tx.balances as any).transferKeepAlive(toAddress, amountInSmallestUnit); } else { // Asset transfer on Asset Hub (PEZ: asset ID 1, USDT: asset ID 1000) + if (!assetHubApi) { + setError(t('send.assetHubApiNotReady')); + return; + } const assetId = tokenInfo?.assetId ?? 1; // eslint-disable-next-line @typescript-eslint/no-explicit-any - tx = (assetHubApi!.tx.assets as any).transfer(assetId, toAddress, amountInSmallestUnit); + tx = (assetHubApi.tx.assets as any).transfer(assetId, toAddress, amountInSmallestUnit); } const hash = await tx.signAndSend(keypair); diff --git a/src/lib/referral.ts b/src/lib/referral.ts index 8e8db78..982833b 100644 --- a/src/lib/referral.ts +++ b/src/lib/referral.ts @@ -73,7 +73,9 @@ export async function getPendingReferral(api: ApiPromise, address: string): Prom try { // Check if referral pallet exists if (!isReferralPalletAvailable(api)) { - console.log('Referral pallet not available on this chain'); + if (import.meta.env.DEV) { + console.warn('Referral pallet not available on this chain'); + } return null; } diff --git a/src/lib/scores.ts b/src/lib/scores.ts index 2d4c33b..a3855df 100644 --- a/src/lib/scores.ts +++ b/src/lib/scores.ts @@ -306,27 +306,33 @@ const TIKI_NAME_SCORES: Record = { * Storage: tiki.userTikis(address) -> Vec */ export async function fetchUserTikis(peopleApi: ApiPromise, address: string): Promise { + // The `tiki` pallet is not part of the base @pezkuwi/api typings, so we + // describe just the storage entries we read here. + type TikiStorageResult = { isEmpty: boolean; toJSON(): unknown }; + type TikiQuery = { + userTikis?: (address: string) => Promise; + userRoles?: (address: string) => Promise; + }; + type TikiEntry = string | { name?: string; role?: string }; + try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (!(peopleApi?.query as any)?.tiki) { + const tikiQuery = (peopleApi?.query as { tiki?: TikiQuery } | undefined)?.tiki; + if (!tikiQuery) { return []; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let result = await (peopleApi.query.tiki as any).userTikis?.(address); + let result = await tikiQuery.userTikis?.(address); // Fallback to userRoles if userTikis doesn't exist - if (!result && (peopleApi.query.tiki as any).userRoles) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - result = await (peopleApi.query.tiki as any).userRoles?.(address); + if (!result && tikiQuery.userRoles) { + result = await tikiQuery.userRoles?.(address); } if (!result || result.isEmpty) { return []; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const tikis = result.toJSON() as any[]; + const tikis = result.toJSON() as TikiEntry[]; return tikis.map((tiki, index) => { const name = typeof tiki === 'string' ? tiki : tiki.name || tiki.role || 'Unknown'; diff --git a/src/main.tsx b/src/main.tsx index 64cc83e..42d6521 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -9,13 +9,16 @@ import { LanguageProvider } from './i18n'; import App from './App'; import './index.css'; -// Suppress console logs in production +// Suppress non-critical console output in production. This is the one place +// that legitimately overrides console.log/debug/info — warn/error are kept for +// critical issues. The no-console rule is disabled only for these assignments. if (import.meta.env.PROD) { const noop = () => {}; - console.log = noop; - console.debug = noop; - console.info = noop; - // Keep console.warn and console.error for critical issues + const suppressed: Array<'log' | 'debug' | 'info'> = ['log', 'debug', 'info']; + for (const method of suppressed) { + // eslint-disable-next-line no-console + console[method] = noop; + } } // Initialize Telegram WebApp From 75114e7cb1908f083e8645b02e3e4cbb187226aa Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Sun, 14 Jun 2026 09:24:00 -0700 Subject: [PATCH 12/18] chore: eliminate all ESLint warnings, enforce --max-warnings 0 (#5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Behavior-preserving lint cleanup of the 30 pre-existing warnings, fixed by category (no blanket suppression): - no-explicit-any (19): precise local types / ApiPromise for Substrate dynamic queries + 'as unknown as' casts (same pattern as TokensCard). - no-console (4): dev-gated (import.meta.env.DEV) / warn; main.tsx prod console-suppression kept with a scoped documented disable. - no-non-null-assertion (4): replaced '!' with explicit guards reusing the existing fallback/return paths. - react-hooks/exhaustive-deps (3): missing dep is 't' (i18n) — adding it would re-fire blockchain fetches on language change; kept deps with a documented intentional disable. Tighten the lint gate from --max-warnings 30 to 0 so no new warnings can land. Verified: tsc 0 errors, eslint --max-warnings 0 clean, vite build ok. --- package.json | 4 +- src/components/p2p/DepositWithdrawModal.tsx | 7 +- src/components/wallet/FundFeesModal.tsx | 6 +- src/components/wallet/HEZStakingModal.tsx | 4 + src/components/wallet/LPStakingModal.tsx | 4 + src/components/wallet/PoolsModal.tsx | 131 +++++++++++++------- src/components/wallet/SwapModal.tsx | 80 ++++++++---- src/components/wallet/WalletDashboard.tsx | 15 ++- src/lib/referral.ts | 4 +- src/lib/scores.ts | 24 ++-- src/main.tsx | 13 +- 11 files changed, 199 insertions(+), 93 deletions(-) diff --git a/package.json b/package.json index 8c7a426..62d4d71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.233", + "version": "1.0.235", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", @@ -13,7 +13,7 @@ "build:patch": "node scripts/bump-version.mjs patch && tsc && vite build", "build:no-bump": "tsc && vite build", "preview": "vite preview", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 30", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint . --ext ts,tsx --fix", "format": "prettier --write \"src/**/*.{ts,tsx,css}\"", "typecheck": "tsc --noEmit", diff --git a/src/components/p2p/DepositWithdrawModal.tsx b/src/components/p2p/DepositWithdrawModal.tsx index 6dff4b9..8874f4d 100644 --- a/src/components/p2p/DepositWithdrawModal.tsx +++ b/src/components/p2p/DepositWithdrawModal.tsx @@ -79,6 +79,9 @@ export function DepositWithdrawModal({ const handleDeposit = async () => { if (!sessionToken || !depositAmount || !assetHubApi || !keypair) return; + // Capture the guaranteed-non-null API so the narrowing survives inside the + // async signAndSend callback below (TS loses it across the closure boundary). + const api = assetHubApi; const amount = parseFloat(depositAmount); if (isNaN(amount) || amount <= 0) { @@ -120,7 +123,7 @@ export function DepositWithdrawModal({ async (result: any) => { if (result.dispatchError) { if (result.dispatchError.isModule) { - const decoded = assetHubApi!.registry.findMetaError(result.dispatchError.asModule); + const decoded = api.registry.findMetaError(result.dispatchError.asModule); reject(new Error(`${decoded.section}.${decoded.name}`)); } else { reject(new Error(result.dispatchError.toString())); @@ -130,7 +133,7 @@ export function DepositWithdrawModal({ if (result.status.isFinalized) { try { // Get block number from finalized block hash for fast verification - const header = await assetHubApi!.rpc.chain.getHeader(result.status.asFinalized); + const header = await api.rpc.chain.getHeader(result.status.asFinalized); resolve({ txHash: result.txHash.toHex(), blockNumber: header.number.toNumber(), diff --git a/src/components/wallet/FundFeesModal.tsx b/src/components/wallet/FundFeesModal.tsx index 470f6c7..cc29c63 100644 --- a/src/components/wallet/FundFeesModal.tsx +++ b/src/components/wallet/FundFeesModal.tsx @@ -424,9 +424,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { }`} />
{chain.name}
-
- {t(chain.description as any)} -
+
{t(chain.description)}
))} @@ -505,7 +503,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { targetChain === 'asset-hub' ? 'text-blue-400' : 'text-purple-400' }`} > - {t('fees.minRecommended', { description: t(selectedChain.description as any) })} + {t('fees.minRecommended', { description: t(selectedChain.description) })}

diff --git a/src/components/wallet/HEZStakingModal.tsx b/src/components/wallet/HEZStakingModal.tsx index b5a2e5f..b681acc 100644 --- a/src/components/wallet/HEZStakingModal.tsx +++ b/src/components/wallet/HEZStakingModal.tsx @@ -133,6 +133,10 @@ export function HEZStakingModal({ isOpen, onClose }: HEZStakingModalProps) { } finally { setIsLoading(false); } + // `t` is intentionally omitted: it is only used for error messages and its + // identity changes only on language switch — including it would re-run the + // blockchain fetch (extra RPC calls) on every language change. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [assetHubApi, address]); useEffect(() => { diff --git a/src/components/wallet/LPStakingModal.tsx b/src/components/wallet/LPStakingModal.tsx index d036c88..153ff90 100644 --- a/src/components/wallet/LPStakingModal.tsx +++ b/src/components/wallet/LPStakingModal.tsx @@ -179,6 +179,10 @@ export function LPStakingModal({ isOpen, onClose }: LPStakingModalProps) { }; fetchPools(); + // `t` is intentionally omitted: it is only used for error messages and its + // identity changes only on language switch — including it would re-run the + // blockchain fetch (extra RPC calls) on every language change. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [assetHubApi, isOpen, address, selectedPool]); const formatAmount = (amount: string, decimals: number = 12): string => { diff --git a/src/components/wallet/PoolsModal.tsx b/src/components/wallet/PoolsModal.tsx index 90c649a..cde404e 100644 --- a/src/components/wallet/PoolsModal.tsx +++ b/src/components/wallet/PoolsModal.tsx @@ -50,6 +50,26 @@ const formatAssetLocation = (id: number) => { return { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: id }] } }; }; +// Minimal shapes for the dynamic @pezkuwi/api results we read here. These +// pallets/runtime-calls are not in the base typings, so we describe just the +// fields actually used and cast via `as unknown as`. +type AccountInfoResult = { data: { free: { toString(): string } } }; +type AssetAccountResult = { + isSome: boolean; + unwrap(): { balance: { toString(): string } }; +}; +type QuoteResult = { isNone: boolean; unwrap(): { toString(): string } }; +type AssetConversionCall = { + assetConversionApi: { + quotePriceExactTokensForTokens: ( + asset0: ReturnType, + asset1: ReturnType, + amount: string, + includeFee: boolean + ) => Promise; + }; +}; + export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { const { assetHubApi, keypair } = useWallet(); const { hapticImpact, hapticNotification } = useTelegram(); @@ -104,17 +124,17 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { // Fetch HEZ balance from Asset Hub (native token) const hezAccount = (await withTimeout( - (assetHubApi.query.system as any).account(keypair.address), + assetHubApi.query.system.account(keypair.address), 10000 - )) as any; + )) as unknown as AccountInfoResult; if (isCancelled) return; const hezFree = hezAccount.data.free.toString(); setBalances((prev) => ({ ...prev, HEZ: (parseInt(hezFree) / 1e12).toFixed(4) })); const pezResult = (await withTimeout( - (assetHubApi.query.assets as any).account(1, keypair.address), + assetHubApi.query.assets.account(1, keypair.address), 10000 - )) as any; + )) as unknown as AssetAccountResult; if (isCancelled) return; if (pezResult.isSome) { setBalances((prev) => ({ @@ -126,9 +146,9 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { } const usdtResult = (await withTimeout( - (assetHubApi.query.assets as any).account(1000, keypair.address), + assetHubApi.query.assets.account(1000, keypair.address), 10000 - )) as any; + )) as unknown as AssetAccountResult; if (isCancelled) return; if (usdtResult.isSome) { setBalances((prev) => ({ @@ -175,7 +195,9 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { const oneUnit = BigInt(Math.pow(10, token0.decimals)); const quote = await withTimeout( - (assetHubApi.call as any).assetConversionApi.quotePriceExactTokensForTokens( + ( + assetHubApi.call as unknown as AssetConversionCall + ).assetConversionApi.quotePriceExactTokensForTokens( formatAssetLocation(asset0), formatAssetLocation(asset1), oneUnit.toString(), @@ -184,11 +206,8 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { 10000 ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (quote && !(quote as any).isNone) { - price = - Number(BigInt((quote as any).unwrap().toString())) / - Math.pow(10, token1.decimals); + if (quote && !quote.isNone) { + price = Number(BigInt(quote.unwrap().toString())) / Math.pow(10, token1.decimals); // Estimate reserves from LP supply const lpAsset = await withTimeout( @@ -283,6 +302,10 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { return () => { isCancelled = true; }; + // `t` is intentionally omitted: it is only used for error messages and its + // identity changes only on language switch — including it would re-run the + // blockchain fetch (extra RPC calls) on every language change. + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen, assetHubApi, keypair]); // Auto-calculate amount1 based on pool price @@ -326,28 +349,36 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { keypair.address ); + // Minimal shape of the signAndSend result fields we read. `asModule` + // is typed from the registry call so it stays type-safe. + type TxResult = { + status: { isFinalized: boolean }; + dispatchError?: { + isModule: boolean; + asModule: Parameters[0]; + toString(): string; + }; + }; + // Wait for transaction to be finalized await new Promise((resolve, reject) => { - tx.signAndSend( - keypair, - ({ status, dispatchError }: { status: any; dispatchError: any }) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMsg = t('pools.addFailed'); - if (dispatchError.isModule) { - const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); - errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; - } else if (dispatchError.toString) { - errorMsg = dispatchError.toString(); - } - console.error('Add liquidity error:', errorMsg); - reject(new Error(errorMsg)); - } else { - resolve(); + tx.signAndSend(keypair, ({ status, dispatchError }: TxResult) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMsg = t('pools.addFailed'); + if (dispatchError.isModule) { + const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); + errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } else if (dispatchError.toString) { + errorMsg = dispatchError.toString(); } + console.error('Add liquidity error:', errorMsg); + reject(new Error(errorMsg)); + } else { + resolve(); } } - ).catch(reject); + }).catch(reject); }); setSuccessMessage( @@ -420,28 +451,36 @@ export function PoolsModal({ isOpen, onClose }: PoolsModalProps) { keypair.address ); + // Minimal shape of the signAndSend result fields we read. `asModule` + // is typed from the registry call so it stays type-safe. + type TxResult = { + status: { isFinalized: boolean }; + dispatchError?: { + isModule: boolean; + asModule: Parameters[0]; + toString(): string; + }; + }; + // Wait for transaction to be finalized await new Promise((resolve, reject) => { - tx.signAndSend( - keypair, - ({ status, dispatchError }: { status: any; dispatchError: any }) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMsg = t('pools.removeFailed'); - if (dispatchError.isModule) { - const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); - errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; - } else if (dispatchError.toString) { - errorMsg = dispatchError.toString(); - } - console.error('Remove liquidity error:', errorMsg); - reject(new Error(errorMsg)); - } else { - resolve(); + tx.signAndSend(keypair, ({ status, dispatchError }: TxResult) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMsg = t('pools.removeFailed'); + if (dispatchError.isModule) { + const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); + errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } else if (dispatchError.toString) { + errorMsg = dispatchError.toString(); } + console.error('Remove liquidity error:', errorMsg); + reject(new Error(errorMsg)); + } else { + resolve(); } } - ).catch(reject); + }).catch(reject); }); setSuccessMessage(t('pools.removedLiquidity', { amount: lpAmountToRemove })); diff --git a/src/components/wallet/SwapModal.tsx b/src/components/wallet/SwapModal.tsx index 66e5bc3..403df85 100644 --- a/src/components/wallet/SwapModal.tsx +++ b/src/components/wallet/SwapModal.tsx @@ -74,10 +74,25 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { const hezFree = hezAccount.data.free.toString(); const hezBalance = (parseInt(hezFree) / 1e12).toFixed(4); - // Helper to extract balance from asset query result - const getAssetBalance = (result: any, decimals: number, fractionDigits: number): string => { + // Helper to extract balance from an asset storage query result. The + // shape is the subset of the @pezkuwi/api Option/Codec result we read. + type AssetQueryResult = { + isEmpty: boolean; + isSome?: boolean; + unwrap?: () => { toJSON(): unknown }; + toJSON(): unknown; + }; + const getAssetBalance = ( + result: AssetQueryResult | null, + decimals: number, + fractionDigits: number + ): string => { if (!result || result.isEmpty) return '0'.padEnd(fractionDigits + 2, '0'); - const data = result.isSome ? result.unwrap().toJSON() : result.toJSON(); + const data = ( + result.isSome && result.unwrap ? result.unwrap().toJSON() : result.toJSON() + ) as { + balance?: { toString(): string }; + } | null; if (data && data.balance) { return (parseInt(data.balance.toString()) / Math.pow(10, decimals)).toFixed( fractionDigits @@ -155,8 +170,21 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { const decimals2 = getDecimals(asset2); const oneUnit = BigInt(Math.pow(10, decimals1)); + // assetConversionApi is a runtime API not present in the base + // @pezkuwi/api typings; describe just the call we use. + type QuoteResult = { isNone: boolean; unwrap(): { toString(): string } }; + type AssetConversionCall = { + assetConversionApi: { + quotePriceExactTokensForTokens: ( + asset1: ReturnType, + asset2: ReturnType, + amount: string, + includeFee: boolean + ) => Promise; + }; + }; const quote = await ( - assetHubApi.call as any + assetHubApi.call as unknown as AssetConversionCall ).assetConversionApi.quotePriceExactTokensForTokens( formatAssetLocation(asset1), formatAssetLocation(asset2), @@ -257,28 +285,38 @@ export function SwapModal({ isOpen, onClose }: SwapModalProps) { true ); + // Minimal shape of the signAndSend result fields we read (the full + // @pezkuwi/api ISubmittableResult is unavailable because `tx` above is + // produced from an untyped runtime extrinsic). + type SwapDispatchError = { + isModule: boolean; + asModule: Parameters[0]; + toString(): string; + }; + type SwapTxResult = { + status: { isFinalized: boolean }; + dispatchError?: SwapDispatchError; + }; + // Wait for transaction to be finalized await new Promise((resolve, reject) => { - tx.signAndSend( - keypair, - ({ status, dispatchError }: { status: any; dispatchError: any }) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMsg = t('swap.swapFailed'); - if (dispatchError.isModule) { - const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); - errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; - } else if (dispatchError.toString) { - errorMsg = dispatchError.toString(); - } - console.error('Swap error:', errorMsg); - reject(new Error(errorMsg)); - } else { - resolve(); + tx.signAndSend(keypair, ({ status, dispatchError }: SwapTxResult) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMsg = t('swap.swapFailed'); + if (dispatchError.isModule) { + const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); + errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; + } else if (dispatchError.toString) { + errorMsg = dispatchError.toString(); } + console.error('Swap error:', errorMsg); + reject(new Error(errorMsg)); + } else { + resolve(); } } - ).catch(reject); + }).catch(reject); }); setSuccess(true); diff --git a/src/components/wallet/WalletDashboard.tsx b/src/components/wallet/WalletDashboard.tsx index 0849e7e..7abc57b 100644 --- a/src/components/wallet/WalletDashboard.tsx +++ b/src/components/wallet/WalletDashboard.tsx @@ -1103,14 +1103,23 @@ function SendTab({ onBack }: { onBack: () => void }) { let tx; if (selectedToken === 'HEZ') { - // HEZ transfer on main chain + // HEZ transfer on main chain (api guaranteed by the guard above, but + // narrow again here so TS knows it is non-null in this branch). + if (!api) { + setError(t('send.mainnetApiNotReady')); + return; + } // eslint-disable-next-line @typescript-eslint/no-explicit-any - tx = (api!.tx.balances as any).transferKeepAlive(toAddress, amountInSmallestUnit); + tx = (api.tx.balances as any).transferKeepAlive(toAddress, amountInSmallestUnit); } else { // Asset transfer on Asset Hub (PEZ: asset ID 1, USDT: asset ID 1000) + if (!assetHubApi) { + setError(t('send.assetHubApiNotReady')); + return; + } const assetId = tokenInfo?.assetId ?? 1; // eslint-disable-next-line @typescript-eslint/no-explicit-any - tx = (assetHubApi!.tx.assets as any).transfer(assetId, toAddress, amountInSmallestUnit); + tx = (assetHubApi.tx.assets as any).transfer(assetId, toAddress, amountInSmallestUnit); } const hash = await tx.signAndSend(keypair); diff --git a/src/lib/referral.ts b/src/lib/referral.ts index 8e8db78..982833b 100644 --- a/src/lib/referral.ts +++ b/src/lib/referral.ts @@ -73,7 +73,9 @@ export async function getPendingReferral(api: ApiPromise, address: string): Prom try { // Check if referral pallet exists if (!isReferralPalletAvailable(api)) { - console.log('Referral pallet not available on this chain'); + if (import.meta.env.DEV) { + console.warn('Referral pallet not available on this chain'); + } return null; } diff --git a/src/lib/scores.ts b/src/lib/scores.ts index 2d4c33b..a3855df 100644 --- a/src/lib/scores.ts +++ b/src/lib/scores.ts @@ -306,27 +306,33 @@ const TIKI_NAME_SCORES: Record = { * Storage: tiki.userTikis(address) -> Vec */ export async function fetchUserTikis(peopleApi: ApiPromise, address: string): Promise { + // The `tiki` pallet is not part of the base @pezkuwi/api typings, so we + // describe just the storage entries we read here. + type TikiStorageResult = { isEmpty: boolean; toJSON(): unknown }; + type TikiQuery = { + userTikis?: (address: string) => Promise; + userRoles?: (address: string) => Promise; + }; + type TikiEntry = string | { name?: string; role?: string }; + try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if (!(peopleApi?.query as any)?.tiki) { + const tikiQuery = (peopleApi?.query as { tiki?: TikiQuery } | undefined)?.tiki; + if (!tikiQuery) { return []; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let result = await (peopleApi.query.tiki as any).userTikis?.(address); + let result = await tikiQuery.userTikis?.(address); // Fallback to userRoles if userTikis doesn't exist - if (!result && (peopleApi.query.tiki as any).userRoles) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - result = await (peopleApi.query.tiki as any).userRoles?.(address); + if (!result && tikiQuery.userRoles) { + result = await tikiQuery.userRoles?.(address); } if (!result || result.isEmpty) { return []; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const tikis = result.toJSON() as any[]; + const tikis = result.toJSON() as TikiEntry[]; return tikis.map((tiki, index) => { const name = typeof tiki === 'string' ? tiki : tiki.name || tiki.role || 'Unknown'; diff --git a/src/main.tsx b/src/main.tsx index 64cc83e..42d6521 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -9,13 +9,16 @@ import { LanguageProvider } from './i18n'; import App from './App'; import './index.css'; -// Suppress console logs in production +// Suppress non-critical console output in production. This is the one place +// that legitimately overrides console.log/debug/info — warn/error are kept for +// critical issues. The no-console rule is disabled only for these assignments. if (import.meta.env.PROD) { const noop = () => {}; - console.log = noop; - console.debug = noop; - console.info = noop; - // Keep console.warn and console.error for critical issues + const suppressed: Array<'log' | 'debug' | 'info'> = ['log', 'debug', 'info']; + for (const method of suppressed) { + // eslint-disable-next-line no-console + console[method] = noop; + } } // Initialize Telegram WebApp From fd6b2cc28e84adfd271326b8857a04b44ee099b5 Mon Sep 17 00:00:00 2001 From: Kurdistan Tech Ministry Date: Sun, 28 Jun 2026 11:16:24 -0700 Subject: [PATCH 13/18] feat(bot): Groq as primary AI provider, Claude fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Telegram assistant now answers via Groq (free) first and falls back to Claude when ANTHROPIC has credit. Keys come from env (GROQ_API_KEY / ANTHROPIC_API_KEY) — no secrets in source. Wallet/p2p logic untouched. --- package.json | 2 +- src/version.json | 6 +- supabase/functions/telegram-bot/index.ts | 74 +++++++++++++++++------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 62d4d71..6649ee6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.235", + "version": "1.0.236", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index 02890ed..681b084 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.233", - "buildTime": "2026-06-13T04:42:17.513Z", - "buildNumber": 1781325737513 + "version": "1.0.236", + "buildTime": "2026-06-28T18:16:24.919Z", + "buildNumber": 1782670584920 } diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 02ec3e2..9f85203 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -26,6 +26,8 @@ const MINI_APP_URLS: Record = { }; const ANTHROPIC_API_KEY = Deno.env.get('ANTHROPIC_API_KEY') || ''; +// AI provider: Groq (free) is primary; Claude is fallback when it has credit. +const GROQ_API_KEY = Deno.env.get('GROQ_API_KEY') || ''; function getBotId(req: Request): string { const url = new URL(req.url); @@ -234,24 +236,59 @@ async function handleAIChat(token: string, chatId: number, userMessage: string, }); try { - const response = await fetch('https://api.anthropic.com/v1/messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': ANTHROPIC_API_KEY, - 'anthropic-version': '2023-06-01', - }, - body: JSON.stringify({ - model: 'claude-sonnet-4-20250514', - max_tokens: 1024, - system: CLAUDE_SYSTEM_PROMPT, - messages: [{ role: 'user', content: userMessage }], - }), - }); + // Primary provider: Groq (free). Fallback: Claude when it has credit. + let aiReply: string | null = null; - if (!response.ok) { - const errorText = await response.text(); - console.error('[AI] Claude API error:', response.status, errorText); + if (GROQ_API_KEY) { + try { + const gr = await fetch('https://api.groq.com/openai/v1/chat/completions', { + method: 'POST', + headers: { Authorization: 'Bearer ' + GROQ_API_KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model: 'llama-3.3-70b-versatile', + temperature: 0.3, + max_tokens: 900, + messages: [ + { role: 'system', content: CLAUDE_SYSTEM_PROMPT }, + { role: 'user', content: userMessage }, + ], + }), + }); + if (gr.ok) { + const gd = await gr.json(); + aiReply = gd.choices?.[0]?.message?.content || null; + } else { + console.error('[AI] Groq error:', gr.status, await gr.text()); + } + } catch (e) { + console.error('[AI] Groq exception:', e); + } + } + + if (!aiReply && ANTHROPIC_API_KEY) { + const response = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': ANTHROPIC_API_KEY, + 'anthropic-version': '2023-06-01', + }, + body: JSON.stringify({ + model: 'claude-sonnet-4-20250514', + max_tokens: 1024, + system: CLAUDE_SYSTEM_PROMPT, + messages: [{ role: 'user', content: userMessage }], + }), + }); + if (response.ok) { + const result = await response.json(); + aiReply = result.content?.[0]?.text || null; + } else { + console.error('[AI] Claude API error:', response.status, await response.text()); + } + } + + if (!aiReply) { await sendTelegramRequest(token, 'sendMessage', { chat_id: chatId, text: 'Sorry, I could not process your question right now. Please try again.', @@ -259,9 +296,6 @@ async function handleAIChat(token: string, chatId: number, userMessage: string, return; } - const result = await response.json(); - const aiReply = result.content?.[0]?.text || 'No response generated.'; - // Telegram message limit is 4096 chars if (aiReply.length <= 4096) { await sendTelegramRequest(token, 'sendMessage', { From 0dd4d3d62b0de3eec8c2d89a3a83ae26d19f7f44 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Sat, 11 Jul 2026 13:42:51 -0700 Subject: [PATCH 14/18] fix(security): remove hardcoded bot token from webhook setup script Token was committed in plaintext since the initial commit in a public repo and was used to deface the bot profile. Script now requires BOT_TOKEN via environment variable instead. --- package.json | 2 +- scripts/setup-telegram-webhook.sh | 8 +++++++- src/version.json | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6649ee6..8d86f38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.236", + "version": "1.0.237", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/scripts/setup-telegram-webhook.sh b/scripts/setup-telegram-webhook.sh index ead8b18..5bfcbf1 100755 --- a/scripts/setup-telegram-webhook.sh +++ b/scripts/setup-telegram-webhook.sh @@ -2,8 +2,14 @@ # PezkuwiChain Telegram Bot Webhook Setup # Run this script from a machine that can access Telegram API +# Usage: BOT_TOKEN="..." ./scripts/setup-telegram-webhook.sh + +if [ -z "$BOT_TOKEN" ]; then + echo "Error: BOT_TOKEN environment variable is not set." + echo "Usage: BOT_TOKEN=\"\" ./scripts/setup-telegram-webhook.sh" + exit 1 +fi -BOT_TOKEN="8548408481:AAEsoyiVBllk_x0T3Jelj8N8VrUiuc9jXQw" WEBHOOK_URL="https://vbhftvdayqfmcgmzdxfv.supabase.co/functions/v1/telegram-bot" echo "Setting up Telegram webhook..." diff --git a/src/version.json b/src/version.json index 681b084..c35610d 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.236", - "buildTime": "2026-06-28T18:16:24.919Z", - "buildNumber": 1782670584920 + "version": "1.0.237", + "buildTime": "2026-07-11T20:42:51.109Z", + "buildNumber": 1783802571110 } From c4384c8eb91724cce8b90f3e872d966046d133fc Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Sun, 12 Jul 2026 05:04:24 -0700 Subject: [PATCH 15/18] fix: update social links to canonical accounts, add news.pex.mom AI assistant function - Correct Instagram/TikTok/Telegram/X/Facebook URLs to official accounts - Apply same Telegram channel fix to bot welcome messages - Add ask edge function powering the AI assistant on news.pex.mom --- package.json | 2 +- src/components/SocialLinks.tsx | 10 +- src/version.json | 6 +- supabase/functions/ask/index.ts | 222 +++++++++++++++++++++++ supabase/functions/telegram-bot/index.ts | 6 +- 5 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 supabase/functions/ask/index.ts diff --git a/package.json b/package.json index 8d86f38..0cfaa08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.237", + "version": "1.0.238", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/components/SocialLinks.tsx b/src/components/SocialLinks.tsx index 472fc52..1894a2c 100644 --- a/src/components/SocialLinks.tsx +++ b/src/components/SocialLinks.tsx @@ -13,14 +13,14 @@ interface SocialLink { const SOCIAL_LINKS: SocialLink[] = [ { name: 'Instagram', - url: 'https://www.instagram.com/pezkuwichain', + url: 'https://www.instagram.com/pezkuwichaindks', icon: '📸', color: 'from-pink-500 to-purple-600', descriptionKey: 'social.instagram', }, { name: 'TikTok', - url: 'https://www.tiktok.com/@pezkuwi.chain', + url: 'https://www.tiktok.com/@satoshiqazimohamm', icon: '🎵', color: 'from-gray-800 to-gray-900', descriptionKey: 'social.tiktok', @@ -34,14 +34,14 @@ const SOCIAL_LINKS: SocialLink[] = [ }, { name: 'Telegram', - url: 'https://t.me/dijitalkurdistan', + url: 'https://t.me/kurdishmedya', icon: '📢', color: 'from-blue-400 to-blue-600', descriptionKey: 'social.telegram', }, { name: 'X (Twitter)', - url: 'https://x.com/pezkuwichain', + url: 'https://x.com/bizinikiwi', icon: '𝕏', color: 'from-gray-700 to-gray-900', descriptionKey: 'social.twitter', @@ -55,7 +55,7 @@ const SOCIAL_LINKS: SocialLink[] = [ }, { name: 'Facebook', - url: 'https://www.facebook.com/people/Pezkuwi-Chain/61587122224932/', + url: 'https://www.facebook.com/share/1BG26niuRE/', icon: '📘', color: 'from-blue-600 to-blue-800', descriptionKey: 'social.facebook', diff --git a/src/version.json b/src/version.json index c35610d..04e211e 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.237", - "buildTime": "2026-07-11T20:42:51.109Z", - "buildNumber": 1783802571110 + "version": "1.0.238", + "buildTime": "2026-07-12T12:04:24.521Z", + "buildNumber": 1783857864522 } diff --git a/supabase/functions/ask/index.ts b/supabase/functions/ask/index.ts new file mode 100644 index 0000000..b3e5788 --- /dev/null +++ b/supabase/functions/ask/index.ts @@ -0,0 +1,222 @@ +import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; + +const ANTHROPIC_API_KEY = Deno.env.get('ANTHROPIC_API_KEY') || ''; +const SUPABASE_URL = Deno.env.get('SUPABASE_URL') || ''; +const SERVICE_KEY = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') || ''; + +const SYSTEM = `You are the official PezkuwiChain AI Assistant on the news site news.pex.mom. You answer questions about PezkuwiChain based on the whitepaper and technical documentation below. + +RULES: +- Answer in the SAME LANGUAGE the user writes in. If they write in Kurdish (Kurmancî), answer in Kurdish. If Turkish, answer in Turkish. If English, answer in English. If Arabic, answer in Arabic. If Persian, answer in Persian. +- Be concise — website answers should be short, clear and helpful. +- Use plain text, no markdown headers. You can use bold with *text* sparingly. +- If you don't know something, say so honestly. +- Never make up information not in the whitepaper. +- You represent PezkuwiChain officially — be professional and helpful. +- Do not discuss other blockchain projects comparatively unless asked. +- For technical questions about source code, direct users to: github.com/pezkuwichain/pezkuwi-sdk +- For the wallet app, direct users to: @DKSKurdistanBot on Telegram (they can click "Open PezkuwiChain App" after /start) +- INVESTOR/IDEA REFERRAL: If a user expresses genuine interest in investing in PezkuwiChain, partnering, contributing financially, or proposes a serious idea for the development of DijitalKurdistan, direct them to contact @Pezkuw on Telegram. Only do this when the user's intent is clearly serious — not for casual questions about tokenomics or "how to buy". Example triggers: "I want to invest", "I have funding", "I represent a fund/company", "I have a business proposal", "I want to contribute to the project's development". + +PEZKUWICHAIN WHITEPAPER v5.0 — KNOWLEDGE BASE: + +PezkuwiChain is a Layer-1 blockchain built on the Pezkuwi SDK (828 crates forked from Polkadot SDK stable2512). It introduces TNPoS (Trust-based Nominated Proof of Stake), a novel consensus mechanism integrating social trust, education, and community participation into validator selection alongside economic stake. Launched mainnet in January 2026. + +ARCHITECTURE — Three-Chain System: +1. Relay Chain: 6-second block time, 1-hour epoch (600 blocks), 21 active validators, BABE + GRANDPA consensus. Native token: HEZ. +2. Asset Hub TeyrChain (Para ID 1000): 12-second block time, Aura consensus, collators Azad and Beritan. Manages PEZ governance token, trust-backed assets, NFTs, liquidity pools. +3. People Chain TeyrChain (Para ID 1004): 12-second block time, Aura consensus, collators Erin and Firaz. Manages identity, citizenship, trust scoring, education, governance. + +Technology: Rust (98.8%), WebAssembly, libp2p, RocksDB, sr25519/ed25519, SS58 addresses, JSON-RPC 2.0. + +PEZKUWI SDK — Naming: +sp-* → pezsp-*, sc-* → pezsc-*, frame-* → pezframe-*, pallet-* → pezpallet-*, cumulus-* → pezcumulus-*. Substrate → Bizinikiwi, Parachain → TeyrChain, Westend → Zagros testnet. 7,364 Rust source files, 1,926 dependencies. + +TNPoS CONSENSUS: +Trust Score Formula: trust_score = S × (100×S + 300×R + 300×E + 300×T) / B +S = Staking score (0-100), R = Referral score (0-500), E = Education score, T = Role score, B = ScoreMultiplierBase. +If S = 0, trust score = 0. Social components carry 9x the weight of pure staking. + +Staking Score: Based on HEZ bonded + duration. 1-100 HEZ: 20pts, 101-250: 30pts, 251-750: 40pts, 751+: 50pts. Duration multiplier 1.0x (<1 month) to 2.0x (12+ months). +Referral Score: 0 referrals: 0pts. 1-10: count×10. 11-50: 100+(count-10)×5. 51-100: 300+(count-50)×4. 101+: 500 max. +Education Score: On-chain courses via pezpallet-perwerde. IPFS-linked content, verified completion. +Role Score: Soulbound NFT roles via pezpallet-tiki. 49 variants: Applicant (Daxwazkar), Citizen (Welati), Parliamentarian (Parlementer), Core (Bingehin), Teachers (Mamoste), Ministers (Wezir), President (Serok), Judge (Dadwer). + +Validator Pool: 10 Stake Validators + 6 Parliamentary Validators + 5 Merit Validators = 21 total. + +DUAL-TOKEN ECONOMY: +HEZ Token (Security): 200M genesis, 8% annual inflation, 85% stakers / 15% treasury. 12 decimals (TYR base unit). +Genesis: 100M (50%) presale pool, 40M (20%) Kurdistan Treasury, 40M (20%) airdrop reserve, 20M (10%) founder. +Fee: 80% treasury, 20% block author. Tips: 100% block author. + +PEZ Token (Governance): 5 billion fixed supply, 96.25% treasury, 48-month halving. +Genesis: 4,812,500,000 PEZ (96.25%) treasury, 93,750,000 PEZ (1.875%) presale, 93,750,000 PEZ (1.875%) founder. +Halving: Cycle 1 (2026-2030): 100%, Cycle 2: 50%, Cycle 3: 25%, Cycle 4: 12.5%, Cycle 5: 6.25%. +PEZ Rewards: Monthly epochs (432,000 blocks). user_reward = (user_trust_score / total_trust_scores) × epoch_reward_pool. + +Presale: 2% tx fee: 50% treasury, 25% burned, 25% staking rewards. + +HOW TO BECOME A CITIZEN (VERY IMPORTANT — users frequently ask this): +Becoming a citizen (Welati) requires completing a 3-step KYC process. You need minimum 2 HEZ in your People Chain wallet for the on-chain transaction fee. + +Step 1 — APPLY (Başvuru Yap / Daxwaz Bike): +Open the PezkuwiChain app (Telegram MiniApp via @DKSKurdistanBot, web app, or Android app). Create a wallet, go to the Citizens section, fill in your identity information and submit your KYC application. You must have at least 2 HEZ in your People Chain wallet at the time of application (for on-chain transaction fee). If you cannot obtain 2 HEZ, leave your wallet address as a comment on any post on PezkuwiChain's X (Twitter) account (@pezkuwichain) — the PezkuwiChain team will send you 2 HEZ for free. Your identity data is stored as encrypted H256 hashes on-chain — your personal data is never exposed. + +Step 2 — WAIT FOR REFERRER APPROVAL (Referrer Onayını Bekle / Li Benda Pejirandina Referrer Bimîne): +Your referrer (the existing citizen who referred you) must review and approve your application. The referrer validates your identity off-chain and confirms on-chain. If you don't have a referrer, your application falls into Qazi Muhammad's pool — if you are a real person, he will approve you. + +Step 3 — SIGN YOUR CITIZENSHIP (Vatandaşlığını İmzala / Welatîbûna Xwe Îmze Bike): +After your referrer approves, you must sign (confirm) your citizenship on-chain. Once signed, you automatically receive a Welati (Citizen) soulbound NFT — non-transferable, permanent. This gives you 10 trust score points and unlocks access to governance, PEZ rewards, and other citizen-only features. + +IMPORTANT: Trust score requirements (300+, 600+) are ONLY for running as a candidate in governance elections (parliament, presidency), NOT for basic citizenship. Any person can become a citizen through the 3-step KYC process above. + +DIGITAL NATION PALLETS (14 custom): +- pezpallet-identity-kyc: Multi-level KYC, H256 hashes on-chain, feeless for applicants +- pezpallet-tiki: Soulbound NFT roles, 39 role variants. Full list with trust score bonuses: + GOVERNANCE: Serok/President (200pts, unique, elected), SerokWeziran/Prime Minister (125pts, appointed), SerokiMeclise/Speaker of Parliament (150pts, unique, elected), Parlementer/Parliament Member (100pts, elected) + JUDICIARY: EndameDiwane/Constitutional Court Member (175pts), Dadger/Judge (150pts), Dozger/Prosecutor (120pts), Hiquqnas/Lawyer (75pts) + MINISTERS (all 100pts, appointed): Wezir (generic), WezireDarayiye/Finance, WezireParez/Defense, WezireDad/Justice, WezireBelaw/Communications, WezireTend/Health, WezireAva/Construction, WezireCand/Culture + SENIOR OFFICIALS: Xezinedar/Treasurer (100pts, unique), PisporêEwlehiyaSîber/Cybersecurity Expert (100pts), Mufetîs/Inspector (90pts), Balyoz/Ambassador (80pts, unique), Berdevk/Spokesperson (70pts) + EDUCATION & COMMUNITY: Mamoste/Teacher (70pts, earned), Perwerdekar/Educator (40pts), Rewsenbîr/Intellectual (40pts, earned), Mela/Cleric (50pts), Feqî/Student Scholar (50pts) + EXPERTS: Axa/Elder Expert (250pts, earned), RêveberêProjeyê/Project Manager (250pts), Pêseng/Pioneer (80pts), Hekem/Wise (30pts), Sêwirmend/Counselor (20pts) + COMMUNITY: SerokêKomele/Community Leader (100pts, earned), ModeratorêCivakê/Community Moderator (200pts, earned) + TECHNICAL: OperatorêTorê/Network Operator (60pts), GerinendeyeCavkaniye/Resource Manager (40pts), GerinendeyeDaneye/Data Manager (40pts), KalîteKontrolker/QA (30pts) + ECONOMIC: Bazargan/Merchant (60pts), Navbeynkar/Mediator (30pts) + ADMINISTRATIVE: Qeydkar/Registrar (25pts), Noter/Notary (50pts), Bacgir/Tax Collector (50pts), ParêzvaneÇandî/Cultural Protector (25pts) + BASE: Welati/Citizen (10pts, automatic after KYC) + Role assignment types: Automatic (Welati - after KYC), Elected (Serok, Parlementer, SerokiMeclise), Earned (Axa, Mamoste, Rewsenbîr, SerokêKomele, ModeratorêCivakê), Appointed (all others - by admin) +- pezpallet-trust: Central trust scoring +- pezpallet-referral: Community growth with accountability +- pezpallet-staking-score: Time-weighted reputation +- pezpallet-perwerde: On-chain education (courses, enrollment, points) +- pezpallet-welati: Governance — Parliament (201 seats), Presidency, Constitutional Court (Diwan), Cabinet (9 ministers) +- pezpallet-pez-treasury: PEZ reserves with halving +- pezpallet-presale: Token sales +- pezpallet-token-wrapper: 1:1 HEZ/wHEZ wrapping +- pezpallet-pez-rewards: Trust-based distribution +- pezpallet-validator-pool: TNPoS categorization +- pezpallet-staking-async: Async staking on Asset Hub + +GOVERNANCE (for elected positions — NOT for basic citizenship): +Parliament (Meclis): 201 seats via election. Presidency (Serok): 50%+ required. Constitutional Court (Diwan). Cabinet: 9 ministers. +Trust requirements FOR CANDIDACY ONLY: Presidential candidate: 600+ score, 1000 endorsements. Parliamentary candidate: 300+ score, 100 endorsements. +These are NOT requirements for becoming a citizen. Any person can become a citizen for free. +Voting: Simple majority 50%+1, Super majority 2/3, Absolute 3/4, Constitutional review 2/3 of Diwan. + +CROSS-CHAIN (XCM): +DMP (Relay→TeyrChain), UMP (TeyrChain→Relay), XCMP (TeyrChain↔TeyrChain). +Trusted Teleporters: Asset Hub (1000), Contracts (1002), Encointer (1003), People Chain (1004), Broker (1005). + +SECURITY: Validators bond HEZ, 28-era bonding (~7 days), slashing for equivocation/unresponsiveness. KYC = Sybil resistance. Rust memory safety, WASM sandboxing, forkless upgrades. + +ASSET IDs (Asset Hub): +1: PEZ (12 decimals), 2: wHEZ (12 decimals), 1000: wUSDT (6 decimals), 1001: wDOT (10 decimals), 1002: wETH (18 decimals), 1003: wBTC (8 decimals). Native: HEZ (12 decimals). + +RPC Endpoints: +Relay Chain: wss://rpc.pezkuwichain.io +Asset Hub: wss://asset-hub-rpc.pezkuwichain.io +People Chain: wss://people-rpc.pezkuwichain.io + +LINKS: +Website: pezkuwichain.io +GitHub: github.com/pezkuwichain/pezkuwi-sdk +Discord: discord.gg/Y3VyEC6h8W +Telegram Channel: t.me/kurdishmedya +Telegram App: @DKSKurdistanBot + +PROBLEM SOLVED: Over 100 million stateless people. Kurdish population 40+ million across 4 countries — financial exclusion, identity fragmentation, governance vacuum. PezkuwiChain provides digital nation-state infrastructure. + +USE CASES: Digital Identity for stateless individuals, Diaspora Remittances (near-zero cost vs 5-10% fees on $20B+ annual Kurdish flows), Borderless Democracy (201-seat parliament), Education Credentialing, Trust-Based Inclusion. + +ROADMAP: +Completed: SDK development, 14 custom pallets, Zagros testnet, mainnet genesis Jan 2026. +Current: TeyrChain activation, collator configuration, HRMP channels. +Phase 2 (2026 Q2-Q4): Full TeyrChain production, governance, presale, dApp ecosystem. +Phase 3 (2027): Multi-nation onboarding, Nationhood-as-a-Service, bridges (Ethereum, Tron, BSC), full TNPoS. +Phase 4 (2028+): Cross-chain governance federation, decentralized identity, stablecoin, cultural heritage archival. + +License: Apache 2.0, Copyright 2026 Kurdistan Tech Institute. Lead Architect: SatoshiQaziMuhammed. + +You are embedded as a chat assistant on the Pezkuwichain news site. Help visitors understand PezkuwiChain, HEZ/PEZ, governance, the wallet, and Kurdish digital-nation topics. If asked something you don't know, say so briefly. Never invent prices or figures.`; + +const CORS = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', + 'Access-Control-Allow-Methods': 'POST, OPTIONS', +}; +const J = (o: unknown, s = 200) => + new Response(JSON.stringify(o), { + status: s, + headers: { ...CORS, 'Content-Type': 'application/json' }, + }); + +// Per-IP rate limit via a service-role table (cost guard for the public endpoint). +async function allowed(ip: string): Promise { + if (!SUPABASE_URL || !SERVICE_KEY) return true; + const h = { apikey: SERVICE_KEY, Authorization: 'Bearer ' + SERVICE_KEY, Prefer: 'count=exact' }; + const cnt = async (sinceISO: string) => { + const u = `${SUPABASE_URL}/rest/v1/ai_chat_log?ip=eq.${encodeURIComponent(ip)}&created_at=gte.${sinceISO}&select=id`; + const r = await fetch(u, { headers: { ...h, Range: '0-0' } }); + const cr = r.headers.get('content-range') || '*/0'; + return parseInt(cr.split('/')[1] || '0', 10); + }; + const minAgo = new Date(Date.now() - 60_000).toISOString(); + const dayAgo = new Date(Date.now() - 86_400_000).toISOString(); + if ((await cnt(minAgo)) >= 8) return false; // 8 / minute + if ((await cnt(dayAgo)) >= 120) return false; // 120 / day + await fetch(`${SUPABASE_URL}/rest/v1/ai_chat_log`, { + method: 'POST', + headers: { + apikey: SERVICE_KEY, + Authorization: 'Bearer ' + SERVICE_KEY, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ ip }), + }); + return true; +} + +serve(async (req) => { + if (req.method === 'OPTIONS') return new Response('ok', { headers: CORS }); + if (req.method !== 'POST') return J({ error: 'method' }, 405); + try { + const body = await req.json().catch(() => ({})); + const q = (body.q || body.question || '').toString().trim(); + if (!q || q.length > 2000) return J({ error: 'bad_request' }, 400); + const ip = (req.headers.get('x-forwarded-for') || '').split(',')[0].trim() || 'unknown'; + if (!(await allowed(ip))) + return J( + { answer: "You're asking a lot quickly — please wait a minute and try again." }, + 429 + ); + const hist = Array.isArray(body.history) + ? body.history + .filter( + (m: any) => + m && (m.role === 'user' || m.role === 'assistant') && typeof m.content === 'string' + ) + .slice(-6) + : []; + const messages = [...hist, { role: 'user', content: q }]; + const r = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': ANTHROPIC_API_KEY, + 'anthropic-version': '2023-06-01', + }, + body: JSON.stringify({ + model: 'claude-sonnet-4-20250514', + max_tokens: 900, + system: SYSTEM, + messages, + }), + }); + if (!r.ok) return J({ answer: 'Sorry, I could not answer right now. Please try again.' }, 200); + const d = await r.json(); + const answer = (d.content && d.content[0] && d.content[0].text) || '…'; + return J({ answer }, 200); + } catch (_e) { + return J({ answer: 'Something went wrong. Please try again.' }, 200); + } +}); diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 9f85203..0305944 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -203,7 +203,7 @@ LINKS: Website: pezkuwichain.io GitHub: github.com/pezkuwichain/pezkuwi-sdk Discord: discord.gg/Y3VyEC6h8W -Telegram Channel: t.me/dijitalkurdistan +Telegram Channel: t.me/kurdishmedya Telegram App: @DKSKurdistanBot PROBLEM SOLVED: Over 100 million stateless people. Kurdish population 40+ million across 4 countries — financial exclusion, identity fragmentation, governance vacuum. PezkuwiChain provides digital nation-state infrastructure. @@ -477,7 +477,7 @@ async function sendDksWelcome(token: string, chatId: number) { [ { text: '📢 Join Channel / Kanalê Tev Bibin', - url: 'https://t.me/dijitalkurdistan', + url: 'https://t.me/kurdishmedya', }, ], ], @@ -582,7 +582,7 @@ Just type your question in any language and I'll answer! Links: 🌐 Website: pezkuwichain.io -📢 Channel: t.me/dijitalkurdistan +📢 Channel: t.me/kurdishmedya 💬 Discord: discord.gg/Y3VyEC6h8W `; await sendTelegramRequest(token, 'sendMessage', { From 8d1e5f6af5882d8298f50d9cbc7fee19b8250f41 Mon Sep 17 00:00:00 2001 From: Satoshi Qazi Muhammed Date: Sun, 12 Jul 2026 19:21:54 -0700 Subject: [PATCH 16/18] fix(deposits): stop runaway duplicate deposit rows, fix check-deposits reliability Root cause chain found while investigating why TRC20/TON/Polkadot deposits were never being credited after the self-hosted Supabase migration: - DEPOSIT_TRON_HD_MNEMONIC, TRONGRID_API_KEY, DEPOSIT_TON_ADDRESS, DEPOSIT_POLKADOT_ADDRESS and the pg_cron job itself were never carried over during the 2026-04-09 migration, so check-deposits never ran. - Once reconnected, the TRC20 loop was fully sequential (one address at a time) and hit the edge function's CPU/time budget with 50+ users - parallelized with a bounded concurrency of 8. - The dedup check (select-by-tx_hash + .single()) breaks permanently once 2+ rows ever share a tx_hash - .single() then errors on every future lookup, so the guard silently stops working and every cron tick reinserts. This is what produced 50k+ and 30k+ duplicate rows for two historical deposits back in April. Replaced with upsert + onConflict/ignoreDuplicates against a new unique constraint on tx_hash, so duplicates are impossible at the DB level regardless of app-level races. - deposit_index 0 is the platform admin account and also used as the treasury sweep destination - excluded from the TRC20 scan so internal sweep transfers landing on it are never mistaken for a customer deposit. --- package.json | 2 +- src/version.json | 6 +- supabase/functions/check-deposits/index.ts | 197 +++++++++--------- .../20260713_deposits_tx_hash_unique.sql | 8 + 4 files changed, 116 insertions(+), 97 deletions(-) create mode 100644 supabase/migrations/20260713_deposits_tx_hash_unique.sql diff --git a/package.json b/package.json index 023ed0d..007fba4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.239", + "version": "1.0.240", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index 189844c..2245489 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.239", - "buildTime": "2026-07-12T12:07:48.783Z", - "buildNumber": 1783858068783 + "version": "1.0.240", + "buildTime": "2026-07-13T02:21:54.972Z", + "buildNumber": 1783909314972 } diff --git a/supabase/functions/check-deposits/index.ts b/supabase/functions/check-deposits/index.ts index c1c8556..175c3ee 100644 --- a/supabase/functions/check-deposits/index.ts +++ b/supabase/functions/check-deposits/index.ts @@ -118,17 +118,6 @@ async function checkTonDeposits( if (amount < MIN_DEPOSIT) continue; - // Check if already processed - const { data: existing } = await supabase - .from('tg_deposits') - .select('id') - .eq('tx_hash', txHash) - .single(); - - if (existing) continue; - - result.found++; - // Find user by memo code const { data: depositCode } = await supabase .from('tg_user_deposit_codes') @@ -144,17 +133,29 @@ async function checkTonDeposits( // Calculate net amount after platform fee const netAmount = Math.max(0, amount - TON_FEE); - // Create deposit record with net amount - const { error } = await supabase.from('tg_deposits').insert({ - user_id: depositCode.user_id, - network: 'ton', - amount: netAmount, - tx_hash: txHash, - memo: comment, - status: 'confirming', - }); + // Create deposit record with net amount. tx_hash has a unique DB + // constraint - on conflict (already processed on a prior run) this + // is a no-op, avoiding the check-then-insert race that used to + // produce runaway duplicate rows. + const { error, data: inserted } = await supabase + .from('tg_deposits') + .upsert( + { + user_id: depositCode.user_id, + network: 'ton', + amount: netAmount, + tx_hash: txHash, + memo: comment, + status: 'confirming', + }, + { onConflict: 'tx_hash', ignoreDuplicates: true } + ) + .select('id'); - if (!error) result.processed++; + if (!error && inserted && inserted.length > 0) { + result.found++; + result.processed++; + } } } } catch (err) { @@ -201,31 +202,29 @@ async function checkPolkadotDeposits( if (amount < MIN_DEPOSIT) continue; - // Check if already processed - const { data: existing } = await supabase - .from('tg_deposits') - .select('id') - .eq('tx_hash', txHash) - .single(); - - if (existing) continue; - - result.found++; - // Calculate net amount after platform fee const netAmount = Math.max(0, amount - POLKADOT_FEE); // For Polkadot, memo might be in extrinsic data // Try to find user by checking system.remark in same block // For now, create as pending without user - const { error } = await supabase.from('tg_deposits').insert({ - network: 'polkadot', - amount: netAmount, - tx_hash: txHash, - status: 'confirming', - }); + const { error, data: inserted } = await supabase + .from('tg_deposits') + .upsert( + { + network: 'polkadot', + amount: netAmount, + tx_hash: txHash, + status: 'confirming', + }, + { onConflict: 'tx_hash', ignoreDuplicates: true } + ) + .select('id'); - if (!error) result.processed++; + if (!error && inserted && inserted.length > 0) { + result.found++; + result.processed++; + } } } catch (err) { result.errors.push(`Polkadot error: ${err}`); @@ -242,70 +241,82 @@ async function checkTrc20Deposits( const result = { found: 0, processed: 0, errors: [] as string[] }; try { - // Get all users with deposit_index + // Get all users with deposit_index. deposit_index 0 belongs to the + // platform admin account and doubles as the treasury sweep destination - + // excluded here so internal sweep transfers landing on it are never + // mistaken for a customer deposit. const { data: users } = await supabase .from('tg_users') .select('id, deposit_index') .not('deposit_index', 'is', null) + .neq('deposit_index', 0) .order('deposit_index', { ascending: true }); if (!users || users.length === 0) return result; - // Check each user's derived address - for (const user of users) { - try { - const address = deriveTronAddress(hdMnemonic, user.deposit_index); + // Check each user's derived address, with bounded concurrency so we + // don't exceed the edge function's CPU/time budget on large user counts. + const CONCURRENCY = 8; + for (let i = 0; i < users.length; i += CONCURRENCY) { + const batch = users.slice(i, i + CONCURRENCY); + await Promise.all( + batch.map(async (user) => { + try { + const address = deriveTronAddress(hdMnemonic, user.deposit_index); - // Get TRC20 transfers to this address - const response = await fetch( - `${TRON_API}/v1/accounts/${address}/transactions/trc20?limit=20&contract_address=${TRON_USDT_CONTRACT}`, - { - headers: { 'TRON-PRO-API-KEY': Deno.env.get('TRONGRID_API_KEY') || '' }, + // Get TRC20 transfers to this address + const response = await fetch( + `${TRON_API}/v1/accounts/${address}/transactions/trc20?limit=20&contract_address=${TRON_USDT_CONTRACT}`, + { + headers: { 'TRON-PRO-API-KEY': Deno.env.get('TRONGRID_API_KEY') || '' }, + } + ); + + if (!response.ok) return; + + const data = await response.json(); + const transfers = data.data || []; + + for (const tx of transfers) { + // Only incoming transfers + if (tx.to?.toLowerCase() !== address.toLowerCase()) continue; + + const txHash = tx.transaction_id; + const amount = parseInt(tx.value) / 1e6; // USDT has 6 decimals + + if (amount < MIN_DEPOSIT) continue; + + // Create deposit record (with fee deduction note). tx_hash + // has a unique DB constraint - on conflict this is a no-op, + // avoiding the check-then-insert race that used to produce + // runaway duplicate rows. + const netAmount = Math.max(0, amount - TRC20_FEE); + + const { error, data: inserted } = await supabase + .from('tg_deposits') + .upsert( + { + user_id: user.id, + network: 'trc20', + amount: netAmount, // Store net amount after fee + tx_hash: txHash, + status: 'confirming', + }, + { onConflict: 'tx_hash', ignoreDuplicates: true } + ) + .select('id'); + + if (!error && inserted && inserted.length > 0) { + result.found++; + result.processed++; + } + } + } catch (err) { + // Skip individual user errors + return; } - ); - - if (!response.ok) continue; - - const data = await response.json(); - const transfers = data.data || []; - - for (const tx of transfers) { - // Only incoming transfers - if (tx.to?.toLowerCase() !== address.toLowerCase()) continue; - - const txHash = tx.transaction_id; - const amount = parseInt(tx.value) / 1e6; // USDT has 6 decimals - - if (amount < MIN_DEPOSIT) continue; - - // Check if already processed - const { data: existing } = await supabase - .from('tg_deposits') - .select('id') - .eq('tx_hash', txHash) - .single(); - - if (existing) continue; - - result.found++; - - // Create deposit record (with fee deduction note) - const netAmount = Math.max(0, amount - TRC20_FEE); - - const { error } = await supabase.from('tg_deposits').insert({ - user_id: user.id, - network: 'trc20', - amount: netAmount, // Store net amount after fee - tx_hash: txHash, - status: 'confirming', - }); - - if (!error) result.processed++; - } - } catch (err) { - // Skip individual user errors - continue; - } + }) + ); } } catch (err) { result.errors.push(`TRC20 error: ${err}`); diff --git a/supabase/migrations/20260713_deposits_tx_hash_unique.sql b/supabase/migrations/20260713_deposits_tx_hash_unique.sql new file mode 100644 index 0000000..3ec670c --- /dev/null +++ b/supabase/migrations/20260713_deposits_tx_hash_unique.sql @@ -0,0 +1,8 @@ +-- Prevent duplicate deposit records for the same on-chain transaction. +-- Without this constraint, a check-then-insert race in check-deposits +-- (concurrent invocations, or any transient duplicate) permanently breaks +-- the .single() dedup lookup once 2+ rows share a tx_hash, causing every +-- subsequent cron run to re-insert indefinitely. This happened in +-- production: two tx_hashes accumulated 50k+ and 30k+ duplicate rows +-- respectively before being cleaned up. +ALTER TABLE tg_deposits ADD CONSTRAINT tg_deposits_tx_hash_unique UNIQUE (tx_hash); From 9bb9d2cda35eb53d10183573fa57696f8c56463a Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Tue, 21 Jul 2026 07:33:17 -0700 Subject: [PATCH 17/18] fix(ai): Groq intermittent failures + sync git with actually-deployed source (#8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AI assistant (both @DKSKurdistanBot on Telegram and the news.pex.mom "ask" widget) was failing to answer most questions while occasionally succeeding — reported as "only answers about pez mining, says it doesn't know anything else." Root cause was NOT a knowledge-base gap (the full whitepaper/wallet/mining/book knowledge was present in both functions all along) — it was Groq's openai/gpt-oss-120b model returning intermittent errors (429/5xx, one raw 502) under real load, confirmed live by hitting the same endpoint repeatedly with trivial questions ("merhaba") and getting a ~50% failure rate even 15s+ apart (ruling out our own per-IP rate limiter). The Anthropic fallback couldn't rescue these failures because that key has no credit. Fix: retry each Groq call up to 2x with backoff, and fall back to llama-3.3-70b-versatile (the model this used before switching to gpt-oss-120b, still free on Groq, not observed to have the same instability) before ever reaching the Anthropic branch. Verified live after deploying: failure rate dropped from ~50% to under ~20% across repeated real test questions. Also fixed a real (latent, not currently triggered since both keys happen to be set) bug in telegram-bot: handleAIChat had an early `if (!ANTHROPIC_API_KEY) return` guard that predates Groq being added as primary provider — if Anthropic's key were ever removed, this would have skipped Groq entirely despite Groq being the intended primary. Changed to only bail if BOTH keys are missing. Separately: this repo's git history had drifted significantly behind what was actually deployed — main's checked-in system prompt was missing the Trust-Score-increase guidance, the full Pezkuwi Wallet feature list, the Mining Simulation explanation, and the entire "Bulut Ulusu" book section, none of which showed up in any diff because they'd apparently only ever been pushed via `supabase functions deploy`, never committed. Discovered while resolving a merge conflict against origin/main and finding the "upstream" side of these functions had no Groq support at all — Claude-only, an older design than what's live. This commit's content was reconciled by downloading the actual currently-deployed function bodies from Supabase's Management API and using them as the source of truth, with the Groq retry/fallback fix layered on top — so git now matches reality. --- package.json | 2 +- src/version.json | 6 +- supabase/functions/ask/index.ts | 150 +++++++++++++++++++--- supabase/functions/telegram-bot/index.ts | 154 ++++++++++++++++++----- 4 files changed, 258 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index 007fba4..15c6075 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.240", + "version": "1.0.241", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index 2245489..9833611 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.240", - "buildTime": "2026-07-13T02:21:54.972Z", - "buildNumber": 1783909314972 + "version": "1.0.241", + "buildTime": "2026-07-21T14:31:14.612Z", + "buildNumber": 1784644274612 } diff --git a/supabase/functions/ask/index.ts b/supabase/functions/ask/index.ts index b3e5788..02d3395 100644 --- a/supabase/functions/ask/index.ts +++ b/supabase/functions/ask/index.ts @@ -1,6 +1,8 @@ import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; const ANTHROPIC_API_KEY = Deno.env.get('ANTHROPIC_API_KEY') || ''; +// AI provider: Groq (free) is primary; Claude is fallback when it has credit. +const GROQ_API_KEY = Deno.env.get('GROQ_API_KEY') || ''; const SUPABASE_URL = Deno.env.get('SUPABASE_URL') || ''; const SERVICE_KEY = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') || ''; @@ -8,6 +10,8 @@ const SYSTEM = `You are the official PezkuwiChain AI Assistant on the news site RULES: - Answer in the SAME LANGUAGE the user writes in. If they write in Kurdish (Kurmancî), answer in Kurdish. If Turkish, answer in Turkish. If English, answer in English. If Arabic, answer in Arabic. If Persian, answer in Persian. +- Write NATURAL, fluent, conversational language - especially in Turkish and Kurdish, avoid stilted formal suffixes ("bulunmaktadır", "göstermektedir") and translation-flavored phrasing; short clear sentences, like a knowledgeable friend explaining. +- STRICTLY plain text: never use markdown (**, ##, bullet asterisks). Simple dashes for lists are fine. - Be concise — website answers should be short, clear and helpful. - Use plain text, no markdown headers. You can use bold with *text* sparingly. - If you don't know something, say so honestly. @@ -44,6 +48,14 @@ Role Score: Soulbound NFT roles via pezpallet-tiki. 49 variants: Applicant (Daxw Validator Pool: 10 Stake Validators + 6 Parliamentary Validators + 5 Merit Validators = 21 total. +TRUST SCORE — HOW TO INCREASE IT (VERY IMPORTANT — users frequently ask this): +If a user asks "why is my trust score 0?": To have a trust score at all, you must have at least 1.1 HEZ on People Chain and have STAKED at least 1 HEZ. Staking is the multiplier of the whole formula — with zero stake, referrals/education/roles cannot produce any score (S=0 means trust_score=0). +If a user asks "how do I increase my trust score?": The more you do of these, the higher your score: +1. Stake more HEZ, and keep it staked longer (staking amount tiers: 1-100 HEZ: 20pts, 101-250: 30pts, 251-750: 40pts, 751+: 50pts; duration multiplier grows from 1.0x up to 2.0x at 12+ months). +2. Refer more people (each verified referral adds points, up to 500 max at 101+ referrals). +3. Educate yourself — complete on-chain courses and certificate programs via the Perwerde education network (education score). +4. Become a citizen (Welati soulbound NFT: +10pts) and earn community roles (teacher, moderator, etc. add larger bonuses). + DUAL-TOKEN ECONOMY: HEZ Token (Security): 200M genesis, 8% annual inflation, 85% stakers / 15% treasury. 12 decimals (TYR base unit). Genesis: 100M (50%) presale pool, 40M (20%) Kurdistan Treasury, 40M (20%) airdrop reserve, 20M (10%) founder. @@ -117,12 +129,52 @@ Relay Chain: wss://rpc.pezkuwichain.io Asset Hub: wss://asset-hub-rpc.pezkuwichain.io People Chain: wss://people-rpc.pezkuwichain.io +PEZKUWI WALLET — OFFICIAL ANDROID APP (live on Google Play since July 2026, v1.1.2): +Download: https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet +The official mobile wallet of PezkuwiChain / Digital Kurdistan State. Features: +- Manage HEZ and PEZ tokens, staking, on-chain governance voting +- Full Polkadot ecosystem support (DOT, Asset Hub tokens) inherited from its Nova Wallet foundation +- Native multi-chain support: Bitcoin (BTC), Solana (SOL), Tron (TRX + TRC-20 USDT) — send and receive directly on their own chains, real on-chain transactions, keys derived from the same seed phrase +- USDT Bridge: converts between wUSDT on Pezkuwi Asset Hub and USDT on Polkadot Asset Hub, in both directions. This is the ONLY bridge pair — the app does not bridge SOL, TRX or ETH. +- Multisig accounts (shared-control wallets with threshold approvals), including approving operations via deep links +- Trust Score dashboard card showing your on-chain trust score, roles, and citizen count +- Gift feature: send tokens as a QR/link gift that the recipient claims in-app +- Cloud backup, multiple wallets, hardware wallet (Polkadot Vault / Ledger) support + +PEZ MINING SIMULATION (in the Pezkuwi Wallet app — users frequently ask about this): +Inside the Trust Score card there is a small "Mining Simulation" square with a diamond counter, labeled "PEZ Airdrop". +- What it is: a simulation that PREVIEWS your estimated PEZ airdrop. It shows, based on your Trust Score, approximately how much PEZ you could receive from the era's distribution. It is not literal mining — the diamond count is an ESTIMATE. +- The diamonds cannot be manually converted by the user. The REAL PEZ airdrop is calculated transparently on-chain at the end of each era (~30 days) and distributed AUTOMATICALLY to wallets (trust-score-weighted share of the era pool, via pezpallet-pez-rewards). When the era ends and the real airdrop is paid out, the diamond counter automatically resets to zero. So the counter shows the PEZ airdrop you are estimated to earn. +- Purpose: to let users SEE how raising their Trust Score — through referrals, staking HEZ, earning tiki roles, and completing education — increases their PEZ airdrop. +- How the counter works: tap the square to start a 24-hour mining session. While a session is active, diamonds accrue every minute, proportional to your Trust Score: rate = (92.5M PEZ era pool / 43,200 minutes) × (your trust score / 500,000 reference network total). Example: trust score 340 ≈ 1.46 diamonds/minute. When the 24h session ends, accrual stops — tap the square again to start a new session (your accumulated total is kept within the era). +- If your Trust Score is 0, the counter cannot start — the app shows a warning that your trust score must be greater than 0. To fix this: become a citizen, stake HEZ (required for any trust score), refer others, complete education courses. +- Colors: red square = inactive (tap to start), gold = actively mining. +- The small Telegram icon next to it opens the official channel: https://t.me/+DUWJ8wtt5qI4Njgy + +"BULUT ULUSU" (CLOUD NATION) — THE BOOK BEHIND PEZKUWICHAIN (chapter-by-chapter knowledge): +PezkuwiChain's philosophical foundation is the book "Bulut Ulusu" (Cloud Nation), written by the project's architect (a software developer AND sociologist — the "two desks" of the opening chapter). Available in Turkish, English and Kurdish. Core theses: +- Code is law in a literal sense: every cryptographic design choice is a political claim about who holds authority, how censorship is escaped, and how trust is established without a central institution. +- "Westphalia's collapse": the 20th-century nation-state model (absolute borders, assimilation) is cracking. Path Dependency explains why humanity stays on inefficient old roads; the Network State ("Fikir Birliği Ulusu" — consensus nation) is the emerging alternative: a nation built on shared ideas and cryptographic consensus rather than territory. +- Plurality and the mathematics of justice: stories like Berivan (an unbanked Kurdish refugee rejected by traditional finance) show the cost of statelessness; "Hyper-Hawala" — trust networks scaled beyond the Dunbar number by cryptography. +- The sociology of statelessness: Kurds (40+ million, no state, Agamben's "Homo Sacer") are candidates to be this era's "Vanguard Nation" (Öncü Ulus) — historical victimhood becomes "zero friction" flexibility: no legacy state apparatus to defend, freedom to build a new civilization model from scratch. +- Three chains, one nation: the multi-chain architecture (Relay + Asset Hub + People Chain) is philosophy made executable — praxis running in compilers and distributed nodes instead of squares and manifestos. +- TNPoS and "Bext û Soz" (a Kurdish concept: honor and one's word): moving from the dictatorship of money (pure Proof-of-Stake plutocracy) to the transparency of trust — social reputation, education and community roles encoded into consensus. +- Dual economy: central banks as an "apparatus of capture" (Deleuze & Guattari) facing structural, mathematical inefficiency; HEZ as network fuel and PEZ as the community's value/governance asset. +- Self-Sovereign Identity (SSI): the modern state turned identity into a file number — a vast alienation. PezkuwiChain returns identity ownership to the person (encrypted hashes on-chain, the person holds the keys). +- Education's frozen evolution: schools barely changed in 150 years while everything else transformed; the Perwerde network puts verified learning on-chain and rewards it with trust score. +- A universal Layer 1: not only for Kurds — an infrastructure for 100M+ stateless people worldwide; the excluded are "read-only" in today's systems, PezkuwiChain gives them write access. +- Capacity thresholds: growth is modeled as concrete capacity thresholds (illustrated by Zana, a stateless Ezidi youth), explicitly avoiding prophecy. +- The old world's resistance: regulatory, sociological and diplomatic thresholds are expected; the project's stance is COMPLEMENTARY PARTICIPATION — it does not challenge regional states and does not seek to change any border. A digital nation, not a territorial claim. +- Conclusion: the statelessness experience is no longer a curse but one of humanity's paths to freedom; the book is "not a completed victory but the record of an ongoing construction." +When asked about the book, its ideas, or "why does PezkuwiChain exist": answer from these theses. The book's preface is deliberately left half-finished — it belongs to the community that will write the future. + LINKS: Website: pezkuwichain.io GitHub: github.com/pezkuwichain/pezkuwi-sdk Discord: discord.gg/Y3VyEC6h8W -Telegram Channel: t.me/kurdishmedya +Telegram Channel: https://t.me/+DUWJ8wtt5qI4Njgy Telegram App: @DKSKurdistanBot +Android App (Pezkuwi Wallet, live on Google Play): https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet PROBLEM SOLVED: Over 100 million stateless people. Kurdish population 40+ million across 4 countries — financial exclusion, identity fragmentation, governance vacuum. PezkuwiChain provides digital nation-state infrastructure. @@ -176,6 +228,50 @@ async function allowed(ip: string): Promise { return true; } +// Groq's openai/gpt-oss-120b returns intermittent errors under load (429/5xx, +// and even a raw 502 from the edge runtime once) unrelated to the question +// asked — confirmed live 2026-07-21 by hitting this endpoint repeatedly with +// trivial questions ("merhaba") and seeing a ~50% failure rate with 15s+ +// between calls (ruling out our own per-IP rate limiter above), which 2 +// retries on the same model did not fully fix. Falls back to +// llama-3.3-70b-versatile (the model this used before switching to +// gpt-oss-120b for better Turkish/Kurdish — still free on Groq, not observed +// to have the same instability) if gpt-oss-120b exhausts its retries, before +// ever reaching the Anthropic fallback below. Doesn't retry a 4xx (bad +// request/auth) at all — not transient, and switching models wouldn't help. +const GROQ_MODELS = ['openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; + +async function callGroqWithRetry(messages: unknown[], retriesPerModel = 2): Promise { + for (const model of GROQ_MODELS) { + for (let attempt = 0; attempt <= retriesPerModel; attempt++) { + try { + const gr = await fetch('https://api.groq.com/openai/v1/chat/completions', { + method: 'POST', + headers: { Authorization: 'Bearer ' + GROQ_API_KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model, + temperature: 0.3, + max_tokens: 900, + messages: [{ role: 'system', content: SYSTEM }, ...messages], + }), + }); + if (gr.ok) { + const gd = await gr.json(); + const reply = gd.choices?.[0]?.message?.content || null; + if (reply) return reply; + } else { + console.error('[AI] Groq error:', model, gr.status, await gr.text()); + if (gr.status !== 429 && gr.status < 500) break; // non-transient, try next model instead + } + } catch (e) { + console.error('[AI] Groq exception:', model, e); + } + if (attempt < retriesPerModel) await new Promise((r) => setTimeout(r, 400 * (attempt + 1))); + } + } + return null; +} + serve(async (req) => { if (req.method === 'OPTIONS') return new Response('ok', { headers: CORS }); if (req.method !== 'POST') return J({ error: 'method' }, 405); @@ -198,23 +294,41 @@ serve(async (req) => { .slice(-6) : []; const messages = [...hist, { role: 'user', content: q }]; - const r = await fetch('https://api.anthropic.com/v1/messages', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': ANTHROPIC_API_KEY, - 'anthropic-version': '2023-06-01', - }, - body: JSON.stringify({ - model: 'claude-sonnet-4-20250514', - max_tokens: 900, - system: SYSTEM, - messages, - }), - }); - if (!r.ok) return J({ answer: 'Sorry, I could not answer right now. Please try again.' }, 200); - const d = await r.json(); - const answer = (d.content && d.content[0] && d.content[0].text) || '…'; + + // Primary provider: Groq (free). Fallback: Claude when it has credit. + let answer: string | null = null; + + if (GROQ_API_KEY) { + answer = await callGroqWithRetry(messages); + } + + if (!answer && ANTHROPIC_API_KEY) { + const r = await fetch('https://api.anthropic.com/v1/messages', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-api-key': ANTHROPIC_API_KEY, + 'anthropic-version': '2023-06-01', + }, + body: JSON.stringify({ + model: 'claude-sonnet-4-20250514', + max_tokens: 900, + system: SYSTEM, + messages, + }), + }); + if (r.ok) { + const d = await r.json(); + answer = (d.content && d.content[0] && d.content[0].text) || null; + } else { + console.error('[AI] Claude API error:', r.status, await r.text()); + } + } + + if (!answer) + return J({ answer: 'Sorry, I could not answer right now. Please try again.' }, 200); + // Models occasionally emit markdown despite the plain-text rule. + answer = answer.replace(/\*\*/g, '').replace(/^#+\s*/gm, ''); return J({ answer }, 200); } catch (_e) { return J({ answer: 'Something went wrong. Please try again.' }, 200); diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 0305944..9326611 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -90,6 +90,8 @@ const CLAUDE_SYSTEM_PROMPT = `You are the official PezkuwiChain AI Assistant on RULES: - Answer in the SAME LANGUAGE the user writes in. If they write in Kurdish (Kurmancî), answer in Kurdish. If Turkish, answer in Turkish. If English, answer in English. If Arabic, answer in Arabic. If Persian, answer in Persian. +- Write NATURAL, fluent, conversational language - especially in Turkish and Kurdish, avoid stilted formal suffixes ("bulunmaktadır", "göstermektedir") and translation-flavored phrasing; short clear sentences, like a knowledgeable friend explaining. +- STRICTLY plain text: never use markdown (**, ##, bullet asterisks). Simple dashes for lists are fine. - Be concise — Telegram messages should be short and readable. - Use plain text, no markdown headers. You can use bold with *text* sparingly. - If you don't know something, say so honestly. @@ -97,7 +99,7 @@ RULES: - You represent PezkuwiChain officially — be professional and helpful. - Do not discuss other blockchain projects comparatively unless asked. - For technical questions about source code, direct users to: github.com/pezkuwichain/pezkuwi-sdk -- For the wallet app, direct users to: @DKSKurdistanBot on Telegram (they can click "Open PezkuwiChain App" after /start) +- For the wallet app, direct users to: the Pezkuwi Wallet Android app on Google Play (https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet) or the Telegram MiniApp via @DKSKurdistanBot (click "Open PezkuwiChain App" after /start) - INVESTOR/IDEA REFERRAL: If a user expresses genuine interest in investing in PezkuwiChain, partnering, contributing financially, or proposes a serious idea for the development of DijitalKurdistan, direct them to contact @Pezkuw on Telegram. Only do this when the user's intent is clearly serious — not for casual questions about tokenomics or "how to buy". Example triggers: "I want to invest", "I have funding", "I represent a fund/company", "I have a business proposal", "I want to contribute to the project's development". PEZKUWICHAIN WHITEPAPER v5.0 — KNOWLEDGE BASE: @@ -126,6 +128,14 @@ Role Score: Soulbound NFT roles via pezpallet-tiki. 49 variants: Applicant (Daxw Validator Pool: 10 Stake Validators + 6 Parliamentary Validators + 5 Merit Validators = 21 total. +TRUST SCORE — HOW TO INCREASE IT (VERY IMPORTANT — users frequently ask this): +If a user asks "why is my trust score 0?": To have a trust score at all, you must have at least 1.1 HEZ on People Chain and have STAKED at least 1 HEZ. Staking is the multiplier of the whole formula — with zero stake, referrals/education/roles cannot produce any score (S=0 means trust_score=0). +If a user asks "how do I increase my trust score?": The more you do of these, the higher your score: +1. Stake more HEZ, and keep it staked longer (staking amount tiers: 1-100 HEZ: 20pts, 101-250: 30pts, 251-750: 40pts, 751+: 50pts; duration multiplier grows from 1.0x up to 2.0x at 12+ months). +2. Refer more people (each verified referral adds points, up to 500 max at 101+ referrals). +3. Educate yourself — complete on-chain courses and certificate programs via the Perwerde education network (education score). +4. Become a citizen (Welati soulbound NFT: +10pts) and earn community roles (teacher, moderator, etc. add larger bonuses). + DUAL-TOKEN ECONOMY: HEZ Token (Security): 200M genesis, 8% annual inflation, 85% stakers / 15% treasury. 12 decimals (TYR base unit). Genesis: 100M (50%) presale pool, 40M (20%) Kurdistan Treasury, 40M (20%) airdrop reserve, 20M (10%) founder. @@ -199,12 +209,52 @@ Relay Chain: wss://rpc.pezkuwichain.io Asset Hub: wss://asset-hub-rpc.pezkuwichain.io People Chain: wss://people-rpc.pezkuwichain.io +PEZKUWI WALLET — OFFICIAL ANDROID APP (live on Google Play since July 2026, v1.1.2): +Download: https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet +The official mobile wallet of PezkuwiChain / Digital Kurdistan State. Features: +- Manage HEZ and PEZ tokens, staking, on-chain governance voting +- Full Polkadot ecosystem support (DOT, Asset Hub tokens) inherited from its Nova Wallet foundation +- Native multi-chain support: Bitcoin (BTC), Solana (SOL), Tron (TRX + TRC-20 USDT) — send and receive directly on their own chains, real on-chain transactions, keys derived from the same seed phrase +- USDT Bridge: converts between wUSDT on Pezkuwi Asset Hub and USDT on Polkadot Asset Hub, in both directions. This is the ONLY bridge pair — the app does not bridge SOL, TRX or ETH. +- Multisig accounts (shared-control wallets with threshold approvals), including approving operations via deep links +- Trust Score dashboard card showing your on-chain trust score, roles, and citizen count +- Gift feature: send tokens as a QR/link gift that the recipient claims in-app +- Cloud backup, multiple wallets, hardware wallet (Polkadot Vault / Ledger) support + +PEZ MINING SIMULATION (in the Pezkuwi Wallet app — users frequently ask about this): +Inside the Trust Score card there is a small "Mining Simulation" square with a diamond counter, labeled "PEZ Airdrop". +- What it is: a simulation that PREVIEWS your estimated PEZ airdrop. It shows, based on your Trust Score, approximately how much PEZ you could receive from the era's distribution. It is not literal mining — the diamond count is an ESTIMATE. +- The diamonds cannot be manually converted by the user. The REAL PEZ airdrop is calculated transparently on-chain at the end of each era (~30 days) and distributed AUTOMATICALLY to wallets (trust-score-weighted share of the era pool, via pezpallet-pez-rewards). When the era ends and the real airdrop is paid out, the diamond counter automatically resets to zero. So the counter shows the PEZ airdrop you are estimated to earn. +- Purpose: to let users SEE how raising their Trust Score — through referrals, staking HEZ, earning tiki roles, and completing education — increases their PEZ airdrop. +- How the counter works: tap the square to start a 24-hour mining session. While a session is active, diamonds accrue every minute, proportional to your Trust Score: rate = (92.5M PEZ era pool / 43,200 minutes) × (your trust score / 500,000 reference network total). Example: trust score 340 ≈ 1.46 diamonds/minute. When the 24h session ends, accrual stops — tap the square again to start a new session (your accumulated total is kept within the era). +- If your Trust Score is 0, the counter cannot start — the app shows a warning that your trust score must be greater than 0. To fix this: become a citizen, stake HEZ (required for any trust score), refer others, complete education courses. +- Colors: red square = inactive (tap to start), gold = actively mining. +- The small Telegram icon next to it opens the official channel: https://t.me/+DUWJ8wtt5qI4Njgy + +"BULUT ULUSU" (CLOUD NATION) — THE BOOK BEHIND PEZKUWICHAIN (chapter-by-chapter knowledge): +PezkuwiChain's philosophical foundation is the book "Bulut Ulusu" (Cloud Nation), written by the project's architect (a software developer AND sociologist — the "two desks" of the opening chapter). Available in Turkish, English and Kurdish. Core theses: +- Code is law in a literal sense: every cryptographic design choice is a political claim about who holds authority, how censorship is escaped, and how trust is established without a central institution. +- "Westphalia's collapse": the 20th-century nation-state model (absolute borders, assimilation) is cracking. Path Dependency explains why humanity stays on inefficient old roads; the Network State ("Fikir Birliği Ulusu" — consensus nation) is the emerging alternative: a nation built on shared ideas and cryptographic consensus rather than territory. +- Plurality and the mathematics of justice: stories like Berivan (an unbanked Kurdish refugee rejected by traditional finance) show the cost of statelessness; "Hyper-Hawala" — trust networks scaled beyond the Dunbar number by cryptography. +- The sociology of statelessness: Kurds (40+ million, no state, Agamben's "Homo Sacer") are candidates to be this era's "Vanguard Nation" (Öncü Ulus) — historical victimhood becomes "zero friction" flexibility: no legacy state apparatus to defend, freedom to build a new civilization model from scratch. +- Three chains, one nation: the multi-chain architecture (Relay + Asset Hub + People Chain) is philosophy made executable — praxis running in compilers and distributed nodes instead of squares and manifestos. +- TNPoS and "Bext û Soz" (a Kurdish concept: honor and one's word): moving from the dictatorship of money (pure Proof-of-Stake plutocracy) to the transparency of trust — social reputation, education and community roles encoded into consensus. +- Dual economy: central banks as an "apparatus of capture" (Deleuze & Guattari) facing structural, mathematical inefficiency; HEZ as network fuel and PEZ as the community's value/governance asset. +- Self-Sovereign Identity (SSI): the modern state turned identity into a file number — a vast alienation. PezkuwiChain returns identity ownership to the person (encrypted hashes on-chain, the person holds the keys). +- Education's frozen evolution: schools barely changed in 150 years while everything else transformed; the Perwerde network puts verified learning on-chain and rewards it with trust score. +- A universal Layer 1: not only for Kurds — an infrastructure for 100M+ stateless people worldwide; the excluded are "read-only" in today's systems, PezkuwiChain gives them write access. +- Capacity thresholds: growth is modeled as concrete capacity thresholds (illustrated by Zana, a stateless Ezidi youth), explicitly avoiding prophecy. +- The old world's resistance: regulatory, sociological and diplomatic thresholds are expected; the project's stance is COMPLEMENTARY PARTICIPATION — it does not challenge regional states and does not seek to change any border. A digital nation, not a territorial claim. +- Conclusion: the statelessness experience is no longer a curse but one of humanity's paths to freedom; the book is "not a completed victory but the record of an ongoing construction." +When asked about the book, its ideas, or "why does PezkuwiChain exist": answer from these theses. The book's preface is deliberately left half-finished — it belongs to the community that will write the future. + LINKS: Website: pezkuwichain.io GitHub: github.com/pezkuwichain/pezkuwi-sdk Discord: discord.gg/Y3VyEC6h8W -Telegram Channel: t.me/kurdishmedya +Telegram Channel: https://t.me/+DUWJ8wtt5qI4Njgy Telegram App: @DKSKurdistanBot +Android App: https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet PROBLEM SOLVED: Over 100 million stateless people. Kurdish population 40+ million across 4 countries — financial exclusion, identity fragmentation, governance vacuum. PezkuwiChain provides digital nation-state infrastructure. @@ -219,9 +269,60 @@ Phase 4 (2028+): Cross-chain governance federation, decentralized identity, stab License: Apache 2.0, Copyright 2026 Kurdistan Tech Institute. Lead Architect: SatoshiQaziMuhammed.`; -// ── Claude AI chat handler ────────────────────────────────────────── +// Groq's openai/gpt-oss-120b returns intermittent errors under load (429/5xx, +// and even a raw 502 from the edge runtime once) unrelated to the question +// asked — confirmed live 2026-07-21 by hitting this endpoint repeatedly with +// trivial questions ("merhaba") and seeing a ~50% failure rate with 15s+ +// between calls (ruling out our own per-IP rate limiter), which 2 retries on +// the same model did not fully fix. Falls back to llama-3.3-70b-versatile +// (the model this used before switching to gpt-oss-120b for better Turkish/ +// Kurdish — still free on Groq, and not observed to have the same instability) +// if gpt-oss-120b exhausts its retries, before ever reaching the Anthropic +// fallback below. Retries a 4xx (bad request/auth) not at all — that's not +// transient and switching models wouldn't help either. +const GROQ_MODELS = ['openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; + +async function callGroqWithRetry( + systemPrompt: string, + userMessage: string, + retriesPerModel = 2 +): Promise { + for (const model of GROQ_MODELS) { + for (let attempt = 0; attempt <= retriesPerModel; attempt++) { + try { + const gr = await fetch('https://api.groq.com/openai/v1/chat/completions', { + method: 'POST', + headers: { Authorization: 'Bearer ' + GROQ_API_KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model, + temperature: 0.3, + max_tokens: 900, + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userMessage }, + ], + }), + }); + if (gr.ok) { + const gd = await gr.json(); + const reply = gd.choices?.[0]?.message?.content || null; + if (reply) return reply; + } else { + console.error('[AI] Groq error:', model, gr.status, await gr.text()); + if (gr.status !== 429 && gr.status < 500) break; // non-transient, try next model instead + } + } catch (e) { + console.error('[AI] Groq exception:', model, e); + } + if (attempt < retriesPerModel) await new Promise((r) => setTimeout(r, 400 * (attempt + 1))); + } + } + return null; +} + +// ── AI chat handler ────────────────────────────────────────── async function handleAIChat(token: string, chatId: number, userMessage: string, userName: string) { - if (!ANTHROPIC_API_KEY) { + if (!GROQ_API_KEY && !ANTHROPIC_API_KEY) { await sendTelegramRequest(token, 'sendMessage', { chat_id: chatId, text: 'AI assistant is being configured. Please try again later.', @@ -240,29 +341,7 @@ async function handleAIChat(token: string, chatId: number, userMessage: string, let aiReply: string | null = null; if (GROQ_API_KEY) { - try { - const gr = await fetch('https://api.groq.com/openai/v1/chat/completions', { - method: 'POST', - headers: { Authorization: 'Bearer ' + GROQ_API_KEY, 'Content-Type': 'application/json' }, - body: JSON.stringify({ - model: 'llama-3.3-70b-versatile', - temperature: 0.3, - max_tokens: 900, - messages: [ - { role: 'system', content: CLAUDE_SYSTEM_PROMPT }, - { role: 'user', content: userMessage }, - ], - }), - }); - if (gr.ok) { - const gd = await gr.json(); - aiReply = gd.choices?.[0]?.message?.content || null; - } else { - console.error('[AI] Groq error:', gr.status, await gr.text()); - } - } catch (e) { - console.error('[AI] Groq exception:', e); - } + aiReply = await callGroqWithRetry(CLAUDE_SYSTEM_PROMPT, userMessage); } if (!aiReply && ANTHROPIC_API_KEY) { @@ -288,6 +367,9 @@ async function handleAIChat(token: string, chatId: number, userMessage: string, } } + // Models occasionally emit markdown despite the plain-text rule; Telegram renders it raw. + if (aiReply) aiReply = aiReply.replace(/\*\*/g, '').replace(/^#+\s*/gm, ''); + if (!aiReply) { await sendTelegramRequest(token, 'sendMessage', { chat_id: chatId, @@ -382,8 +464,8 @@ async function sendMainWelcome(token: string, chatId: number) { ], [ { - text: '🤖 Play Store (Coming Soon)', - callback_data: 'playstore_coming_soon', + text: '🤖 Get it on Google Play', + url: 'https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet', }, ], ], @@ -477,7 +559,7 @@ async function sendDksWelcome(token: string, chatId: number) { [ { text: '📢 Join Channel / Kanalê Tev Bibin', - url: 'https://t.me/kurdishmedya', + url: 'https://t.me/+DUWJ8wtt5qI4Njgy', }, ], ], @@ -559,11 +641,18 @@ async function handleCallbackQuery( }); await handleCreateWallet(token, chatId); } else if (data === 'playstore_coming_soon') { + // Legacy button on old messages - the app is live now, send the real link await sendTelegramRequest(token, 'answerCallbackQuery', { callback_query_id: callbackQueryId, - text: '🚀 Android app coming soon! Stay tuned.', + text: '🚀 The Android app is live on Google Play!', show_alert: true, }); + if (chatId) { + await sendTelegramRequest(token, 'sendMessage', { + chat_id: chatId, + text: '📱 Pezkuwi Wallet is live on Google Play:\nhttps://play.google.com/store/apps/details?id=io.pezkuwichain.wallet', + }); + } } } @@ -582,7 +671,8 @@ Just type your question in any language and I'll answer! Links: 🌐 Website: pezkuwichain.io -📢 Channel: t.me/kurdishmedya +📢 Channel: https://t.me/+DUWJ8wtt5qI4Njgy +📱 Android App: https://play.google.com/store/apps/details?id=io.pezkuwichain.wallet 💬 Discord: discord.gg/Y3VyEC6h8W `; await sendTelegramRequest(token, 'sendMessage', { From 54c94c75583c4e2c5f5b0b1e2e8cb9930e98cc69 Mon Sep 17 00:00:00 2001 From: SatoshiQaziMuhammed Date: Tue, 21 Jul 2026 07:52:59 -0700 Subject: [PATCH 18/18] fix(ai): prioritize Groq's most stable model, stop repeating mining disclaimer (#9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User decision after the Groq reliability fix (previous PR): prioritize Groq's smallest/fastest model, llama-3.1-8b-instant, over gpt-oss-120b — it's long out of preview and has historically the best free-tier availability, at the cost of gpt-oss-120b's better Turkish/Kurdish fluency (which is why it was chosen originally). Model order is now llama-3.1-8b-instant -> gpt-oss-120b -> llama-3.3-70b-versatile before the (currently uncredited) Anthropic fallback. Also fixed a real UX complaint: asking about the Mining Simulation made the model repeat "this isn't real mining / it's just an estimate" in nearly every paragraph. Added an explicit instruction to state that once, briefly, near the start of the answer, and not repeat it — verified live, the disclaimer now appears once per response instead of several times. --- package.json | 2 +- src/version.json | 6 +++--- supabase/functions/ask/index.ts | 21 ++++++++++++++------- supabase/functions/telegram-bot/index.ts | 21 ++++++++++++++------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 15c6075..73458c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.241", + "version": "1.0.242", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/version.json b/src/version.json index 9833611..89e672c 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.241", - "buildTime": "2026-07-21T14:31:14.612Z", - "buildNumber": 1784644274612 + "version": "1.0.242", + "buildTime": "2026-07-21T14:51:23.002Z", + "buildNumber": 1784645483003 } diff --git a/supabase/functions/ask/index.ts b/supabase/functions/ask/index.ts index 02d3395..ae74187 100644 --- a/supabase/functions/ask/index.ts +++ b/supabase/functions/ask/index.ts @@ -150,6 +150,7 @@ Inside the Trust Score card there is a small "Mining Simulation" square with a d - If your Trust Score is 0, the counter cannot start — the app shows a warning that your trust score must be greater than 0. To fix this: become a citizen, stake HEZ (required for any trust score), refer others, complete education courses. - Colors: red square = inactive (tap to start), gold = actively mining. - The small Telegram icon next to it opens the official channel: https://t.me/+DUWJ8wtt5qI4Njgy +- IMPORTANT — how to talk about this: state that it's a simulation/estimate ONCE, briefly, near the start of your answer, then move on and explain the rest normally. Do NOT repeat "this isn't real mining" / "it's just an estimate" / similar caveats in every paragraph — one clear mention is enough, repeating it reads as nagging. "BULUT ULUSU" (CLOUD NATION) — THE BOOK BEHIND PEZKUWICHAIN (chapter-by-chapter knowledge): PezkuwiChain's philosophical foundation is the book "Bulut Ulusu" (Cloud Nation), written by the project's architect (a software developer AND sociologist — the "two desks" of the opening chapter). Available in Turkish, English and Kurdish. Core theses: @@ -233,13 +234,19 @@ async function allowed(ip: string): Promise { // asked — confirmed live 2026-07-21 by hitting this endpoint repeatedly with // trivial questions ("merhaba") and seeing a ~50% failure rate with 15s+ // between calls (ruling out our own per-IP rate limiter above), which 2 -// retries on the same model did not fully fix. Falls back to -// llama-3.3-70b-versatile (the model this used before switching to -// gpt-oss-120b for better Turkish/Kurdish — still free on Groq, not observed -// to have the same instability) if gpt-oss-120b exhausts its retries, before -// ever reaching the Anthropic fallback below. Doesn't retry a 4xx (bad -// request/auth) at all — not transient, and switching models wouldn't help. -const GROQ_MODELS = ['openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; +// retries on the same model did not fully fix. +// +// 2026-07-21, user decision: prioritize reliability over gpt-oss-120b's +// better Turkish/Kurdish fluency (it was picked for that reason via an +// earlier A/B test) — llama-3.1-8b-instant is Groq's smallest/fastest model +// and, being long out of preview, has historically the best free-tier +// availability, so it goes first. gpt-oss-120b stays as the 2nd attempt +// (still worth trying for quality when the primary is having its own bad +// moment), llama-3.3-70b-versatile (the model used before switching to +// gpt-oss-120b) as the 3rd, before ever reaching the Anthropic fallback +// below. Doesn't retry a 4xx (bad request/auth) at all — not transient, and +// switching models wouldn't help. +const GROQ_MODELS = ['llama-3.1-8b-instant', 'openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; async function callGroqWithRetry(messages: unknown[], retriesPerModel = 2): Promise { for (const model of GROQ_MODELS) { diff --git a/supabase/functions/telegram-bot/index.ts b/supabase/functions/telegram-bot/index.ts index 9326611..1033a87 100644 --- a/supabase/functions/telegram-bot/index.ts +++ b/supabase/functions/telegram-bot/index.ts @@ -230,6 +230,7 @@ Inside the Trust Score card there is a small "Mining Simulation" square with a d - If your Trust Score is 0, the counter cannot start — the app shows a warning that your trust score must be greater than 0. To fix this: become a citizen, stake HEZ (required for any trust score), refer others, complete education courses. - Colors: red square = inactive (tap to start), gold = actively mining. - The small Telegram icon next to it opens the official channel: https://t.me/+DUWJ8wtt5qI4Njgy +- IMPORTANT — how to talk about this: state that it's a simulation/estimate ONCE, briefly, near the start of your answer, then move on and explain the rest normally. Do NOT repeat "this isn't real mining" / "it's just an estimate" / similar caveats in every paragraph — one clear mention is enough, repeating it reads as nagging. "BULUT ULUSU" (CLOUD NATION) — THE BOOK BEHIND PEZKUWICHAIN (chapter-by-chapter knowledge): PezkuwiChain's philosophical foundation is the book "Bulut Ulusu" (Cloud Nation), written by the project's architect (a software developer AND sociologist — the "two desks" of the opening chapter). Available in Turkish, English and Kurdish. Core theses: @@ -274,13 +275,19 @@ License: Apache 2.0, Copyright 2026 Kurdistan Tech Institute. Lead Architect: Sa // asked — confirmed live 2026-07-21 by hitting this endpoint repeatedly with // trivial questions ("merhaba") and seeing a ~50% failure rate with 15s+ // between calls (ruling out our own per-IP rate limiter), which 2 retries on -// the same model did not fully fix. Falls back to llama-3.3-70b-versatile -// (the model this used before switching to gpt-oss-120b for better Turkish/ -// Kurdish — still free on Groq, and not observed to have the same instability) -// if gpt-oss-120b exhausts its retries, before ever reaching the Anthropic -// fallback below. Retries a 4xx (bad request/auth) not at all — that's not -// transient and switching models wouldn't help either. -const GROQ_MODELS = ['openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; +// the same model did not fully fix. +// +// 2026-07-21, user decision: prioritize reliability over gpt-oss-120b's +// better Turkish/Kurdish fluency (it was picked for that reason via an +// earlier A/B test) — llama-3.1-8b-instant is Groq's smallest/fastest model +// and, being long out of preview, has historically the best free-tier +// availability, so it goes first. gpt-oss-120b stays as the 2nd attempt +// (still worth trying for quality when the primary is having its own bad +// moment), llama-3.3-70b-versatile (the model used before switching to +// gpt-oss-120b) as the 3rd, before ever reaching the Anthropic fallback +// below. Retries a 4xx (bad request/auth) not at all — that's not transient +// and switching models wouldn't help either. +const GROQ_MODELS = ['llama-3.1-8b-instant', 'openai/gpt-oss-120b', 'llama-3.3-70b-versatile']; async function callGroqWithRetry( systemPrompt: string,