From 8ca6b2a53044b4d7ba30825efff555011584ddda Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Wed, 25 Feb 2026 19:47:40 -0600 Subject: [PATCH 01/38] refactor: remove CredentialCard component and enhance SavedCredentialsCard functionality - Deleted the CredentialCard component to streamline the codebase. - Updated SavedCredentialsCard to include expandable functionality with motion effects for improved user interaction. - Enhanced layout and styling for better visual consistency and responsiveness. - Integrated new props for handling click events and layout animations. --- .../modules/credentials/ui/CredentialCard.tsx | 85 ------------------- .../credentials/ui/SavedCredentialsCard.tsx | 26 ++---- .../modules/vault/ui/VaultDashboard.tsx | 2 +- 3 files changed, 8 insertions(+), 105 deletions(-) delete mode 100644 src/components/modules/credentials/ui/CredentialCard.tsx diff --git a/src/components/modules/credentials/ui/CredentialCard.tsx b/src/components/modules/credentials/ui/CredentialCard.tsx deleted file mode 100644 index e1f9c9d..0000000 --- a/src/components/modules/credentials/ui/CredentialCard.tsx +++ /dev/null @@ -1,85 +0,0 @@ -'use client'; - -import { BorderBeam } from '@/components/ui/border-beam'; -import { MagicCard } from '@/components/ui/magic-card'; -import Image from 'next/image'; - -export function CredentialCard() { - return ( -
- - } - > -
-
-

Credential

- ACTA -
- -
-
-
- Owner - - GAGSFSAC..MUMDRXYZ - -
- -
- Issuer - Example University -
- -
- Issued on - 1/11/2025 -
- -
- Holder ID - - MUMDRXYZ..GAGSFSAC - -
- -
- Credential Type - University Degree -
- -
- Degree Name - Bachelor of Engineering -
-
- -
-
- ACTA • Verifiable Credential -
- ACTA Logo -
-
-
-
-
- ); -} diff --git a/src/components/modules/credentials/ui/SavedCredentialsCard.tsx b/src/components/modules/credentials/ui/SavedCredentialsCard.tsx index f037706..b3d6c99 100644 --- a/src/components/modules/credentials/ui/SavedCredentialsCard.tsx +++ b/src/components/modules/credentials/ui/SavedCredentialsCard.tsx @@ -2,7 +2,7 @@ import { Card } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { Copy, Share2, Trash2, Eye } from 'lucide-react'; +import { Share2, Trash2, Eye } from 'lucide-react'; import Image from 'next/image'; import { BorderBeam } from '@/components/ui/border-beam'; import type { CredentialCardProps } from '@/@types/credentials'; @@ -19,8 +19,8 @@ export function CredentialCard({ onView, }: CredentialCardProps) { return ( - -
+ +
{(() => { @@ -32,7 +32,7 @@ export function CredentialCard({ : '/acta.png'; const translateClass = logoSrc === '/acta.png' ? '-translate-x-2' : '-translate-x-1'; return ( -
+
Logo

Wallet Address

-
-

- {wallet} -

- {onCopy && ( - - )} -
+

+ {wallet} +

diff --git a/src/components/modules/vault/ui/VaultDashboard.tsx b/src/components/modules/vault/ui/VaultDashboard.tsx index e085dab..85f3da8 100644 --- a/src/components/modules/vault/ui/VaultDashboard.tsx +++ b/src/components/modules/vault/ui/VaultDashboard.tsx @@ -211,7 +211,7 @@ export default function VaultPage() {

) : ( -
+
{filteredCredentials.map((credential) => ( Date: Wed, 25 Feb 2026 21:23:10 -0600 Subject: [PATCH 02/38] feat: enhance VaultDashboard and SavedCredentialsCard with motion effects and new hooks - Updated VaultDashboard to utilize motion effects for credential cards, improving user interaction and visual appeal. - Introduced useOutsideClick hook for handling outside click events, enhancing modal behavior. - Enhanced SavedCredentialsCard to support expandable functionality with layout animations and improved styling. - Refactored state management in VaultDashboard for better handling of active credentials and loading states. --- .../credentials/ui/SavedCredentialsCard.tsx | 229 ++++++----- .../modules/vault/ui/VaultDashboard.tsx | 372 +++++++++++++++--- src/hooks/use-outside-click.ts | 20 + 3 files changed, 460 insertions(+), 161 deletions(-) create mode 100644 src/hooks/use-outside-click.ts diff --git a/src/components/modules/credentials/ui/SavedCredentialsCard.tsx b/src/components/modules/credentials/ui/SavedCredentialsCard.tsx index b3d6c99..de799b6 100644 --- a/src/components/modules/credentials/ui/SavedCredentialsCard.tsx +++ b/src/components/modules/credentials/ui/SavedCredentialsCard.tsx @@ -2,10 +2,16 @@ import { Card } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { Share2, Trash2, Eye } from 'lucide-react'; +import { Share2, Trash2 } from 'lucide-react'; import Image from 'next/image'; import { BorderBeam } from '@/components/ui/border-beam'; import type { CredentialCardProps } from '@/@types/credentials'; +import { motion } from 'motion/react'; + +interface ExpandableCredentialCardProps extends CredentialCardProps { + layoutId?: string; + onClick?: () => void; +} export function CredentialCard({ name, @@ -17,115 +23,132 @@ export function CredentialCard({ status, onRevoke, onView, -}: CredentialCardProps) { + layoutId, + onClick, +}: ExpandableCredentialCardProps) { + const logoInfo = (() => { + const c = String(category || '').toLowerCase(); + const logoSrc = c.includes('escrow') + ? '/tw-x-acta.png' + : c.includes('contributions') + ? '/gf-x-acta.png' + : '/acta.png'; + const translateClass = logoSrc === '/acta.png' ? '-translate-x-2' : '-translate-x-1'; + return { logoSrc, translateClass }; + })(); + return ( - -
-
-
- {(() => { - const c = String(category || '').toLowerCase(); - const logoSrc = c.includes('escrow') - ? '/tw-x-acta.png' - : c.includes('contributions') - ? '/gf-x-acta.png' - : '/acta.png'; - const translateClass = logoSrc === '/acta.png' ? '-translate-x-2' : '-translate-x-1'; - return ( -
- Logo -
- ); - })()} -
-
-
- {category} - + + +
+
+
+ + Logo + +
+
+ + {category} + + + {status === 'revoked' && ( + + Revoked + + )}
- {status === 'revoked' && ( - - Revoked - - )}
-
-
-

Wallet Address

-

- {wallet} -

-
- -
-
-

Credential Name

-

{name}

- {url && ( - - {new URL(url).hostname} - - )} +
+

Wallet Address

+ + {wallet} +
-
- {onView && ( - - )} - {onRevoke && ( - - )} - {onShare && ( - - )} + {name} + + {url && ( + e.stopPropagation()} + > + {new URL(url).hostname} + + )} +
+
+ {onRevoke && ( + + )} + {onShare && ( + + )} +
-
- + + ); } diff --git a/src/components/modules/vault/ui/VaultDashboard.tsx b/src/components/modules/vault/ui/VaultDashboard.tsx index 85f3da8..4150c3f 100644 --- a/src/components/modules/vault/ui/VaultDashboard.tsx +++ b/src/components/modules/vault/ui/VaultDashboard.tsx @@ -3,16 +3,31 @@ import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; -import { Shield, Search, Key, Lock } from 'lucide-react'; +import { Shield, Search, Key, Lock, X, Share2, Trash2, Eye } from 'lucide-react'; import { useVaultDashboard } from '@/components/modules/vault/hooks/useVaultDashboard'; import { useVaultCards } from '@/components/modules/vault/hooks/useVaultCards'; import ShareCredentialModal from '@/components/modules/credentials/ui/ShareCredentialModal'; import { Skeleton } from '@/components/ui/skeleton'; import { CredentialCard } from '@/components/modules/credentials/ui/SavedCredentialsCard'; -import { useMemo, useState } from 'react'; +import { useCallback, useEffect, useId, useRef, useState } from 'react'; import type { Credential } from '@/@types/credentials'; import { useVault } from '@/components/modules/vault/hooks/use-vault'; import { useWalletContext } from '@/providers/wallet.provider'; +import { AnimatePresence, motion } from 'motion/react'; +import { useOutsideClick } from '@/hooks/use-outside-click'; +import Image from 'next/image'; + +interface ActiveCredentialView { + credential: Credential; + gridCredential: { + id: string; + name: string; + category: string; + status?: string; + wallet: string; + url?: string; + }; +} export default function VaultPage() { const { walletAddress } = useWalletContext(); @@ -29,24 +44,41 @@ export default function VaultPage() { onRevoke, } = useVaultDashboard(); const { actaById, getWalletFromDid, filteredCredentials, copyToClipboard } = useVaultCards(); - const [contentOpen, setContentOpen] = useState(false); - const [contentCred, setContentCred] = useState(null); const [isCreating, setIsCreating] = useState(false); + const [active, setActive] = useState(null); + const [showRawJson, setShowRawJson] = useState(false); + const [hasMounted, setHasMounted] = useState(false); + const expandedRef = useRef(null); + const motionId = useId(); + + useEffect(() => { + setHasMounted(true); + }, []); const { loading: creatingVault } = useVault(); const showCreatingLoader = isCreating || creatingVault; - const rawJson = useMemo(() => { - if (!contentCred) return ''; - const raw = (contentCred as unknown as { raw?: unknown }).raw; - const vaultRecord = (contentCred as unknown as { vaultRecord?: unknown }).vaultRecord; - const payload = raw ?? vaultRecord ?? contentCred; - try { - return JSON.stringify(payload, null, 2); - } catch { - return String(payload); + const closeExpanded = useCallback(() => { + setActive(null); + setShowRawJson(false); + }, []); + + useEffect(() => { + function onKeyDown(event: KeyboardEvent) { + if (event.key === 'Escape') closeExpanded(); + } + + if (active) { + document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = 'auto'; } - }, [contentCred]); + + window.addEventListener('keydown', onKeyDown); + return () => window.removeEventListener('keydown', onKeyDown); + }, [active, closeExpanded]); + + useOutsideClick(expandedRef, closeExpanded); const handleCreateVault = async () => { setIsCreating(true); @@ -57,6 +89,19 @@ export default function VaultPage() { } }; + // Evitar hydration mismatch: walletAddress puede ser null en servidor y tener valor en cliente (localStorage) + if (!hasMounted) { + return ( +
+
+
+

Checking vault...

+

Detecting if your wallet has a vault

+
+
+ ); + } + if (!walletAddress) { return (
@@ -67,9 +112,7 @@ export default function VaultPage() { ); } - // Still loading vault status (wallet connected but we don't know yet if vault exists) const isCheckingVault = vaultExists === null && dashboardStatus === 'pending'; - // Show create vault only when we know for sure the vault does NOT exist const shouldShowCreateVault = vaultExists === false; if (isCheckingVault) { @@ -215,17 +258,43 @@ export default function VaultPage() { {filteredCredentials.map((credential) => ( copyToClipboard(text, label)} + onClick={() => { + const ac = actaById.get(credential.id); + if (ac) { + setActive({ + credential: ac, + gridCredential: { + id: credential.id, + name: credential.name, + category: credential.category, + status: credential.status, + wallet: getWalletFromDid(credential.username), + url: credential.url || undefined, + }, + }); + } + }} onView={() => { const ac = actaById.get(credential.id); if (ac) { - setContentCred(ac); - setContentOpen(true); + setActive({ + credential: ac, + gridCredential: { + id: credential.id, + name: credential.name, + category: credential.category, + status: credential.status, + wallet: getWalletFromDid(credential.username), + url: credential.url || undefined, + }, + }); } }} onShare={() => { @@ -239,53 +308,240 @@ export default function VaultPage() { )}
+ {shareOpen && ( )} - {contentOpen && ( -
-
{ - setContentOpen(false); - setContentCred(null); - }} + + + {active && ( + -
-
-
-

- Credential content -

-

- {contentCred?.id || ''} -

+ )} + + + + {active && ( +
+ +
+
+
+ + {(() => { + const c = String(active.gridCredential.category || '').toLowerCase(); + const logoSrc = c.includes('escrow') + ? '/tw-x-acta.png' + : c.includes('contributions') + ? '/gf-x-acta.png' + : '/acta.png'; + const translateClass = + logoSrc === '/acta.png' ? '-translate-x-2' : '-translate-x-1'; + return ( + Logo + ); + })()} + +
+
+ + {active.gridCredential.category} + + + + +
+
+ +
+

Credential Name

+ + {active.gridCredential.name} + +
+ +
+

Wallet Address

+ + {active.gridCredential.wallet} + +
+ +
+ + + +
- -
-
-
-                {rawJson || 'No content available'}
-              
-
+

+ Credential Fields +

+
+ {[ + { key: 'issuer', label: 'Issuer' }, + { key: 'subject', label: 'Holder DID' }, + { key: 'type', label: 'Credential Type' }, + { key: 'issuedAt', label: 'Issued At' }, + { key: 'expirationDate', label: 'Expiration Date' }, + { key: 'status', label: 'Status' }, + { key: 'birthDate', label: 'Birth Date' }, + ] + .filter((f) => { + const val = (active.credential as unknown as Record)[f.key]; + return val !== undefined && val !== null && String(val).trim() !== ''; + }) + .map((f) => { + const val = (active.credential as unknown as Record)[f.key]; + let display = String(val); + if ( + f.key === 'issuedAt' || + f.key === 'expirationDate' || + f.key === 'birthDate' + ) { + try { + display = new Date(display).toLocaleDateString(); + } catch { + /* keep raw */ + } + } + return ( +
+ {f.label} + + {display} + +
+ ); + })} +
+ + +
-
- )} + )} + + + + {showRawJson && active && ( + <> + setShowRawJson(false)} + /> +
+ +
+
+

Raw JSON

+

+ {active.credential.id} +

+
+ +
+
+
+                    {(() => {
+                      const raw = (active.credential as unknown as { raw?: unknown }).raw;
+                      const vaultRecord = (active.credential as unknown as { vaultRecord?: unknown }).vaultRecord;
+                      const payload = raw ?? vaultRecord ?? active.credential;
+                      try { return JSON.stringify(payload, null, 2); } catch { return String(payload); }
+                    })()}
+                  
+
+
+
+ + )} +
); } diff --git a/src/hooks/use-outside-click.ts b/src/hooks/use-outside-click.ts new file mode 100644 index 0000000..357ed55 --- /dev/null +++ b/src/hooks/use-outside-click.ts @@ -0,0 +1,20 @@ +import { useEffect, type RefObject } from 'react'; + +export function useOutsideClick( + ref: RefObject, + callback: (event: MouseEvent | TouchEvent) => void +) { + useEffect(() => { + const listener = (event: MouseEvent | TouchEvent) => { + if (!ref.current || ref.current.contains(event.target as Node)) return; + callback(event); + }; + + document.addEventListener('mousedown', listener); + document.addEventListener('touchstart', listener); + return () => { + document.removeEventListener('mousedown', listener); + document.removeEventListener('touchstart', listener); + }; + }, [ref, callback]); +} From 34fcff2921e6832427b1f03e897bd0f691500401 Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Wed, 25 Feb 2026 21:42:46 -0600 Subject: [PATCH 03/38] refactor: clean up VaultDashboard code for improved readability - Removed unnecessary line breaks in the JSX structure to enhance clarity. - Reformatted the JSON stringification logic for better readability and maintainability. --- src/components/modules/vault/ui/VaultDashboard.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/modules/vault/ui/VaultDashboard.tsx b/src/components/modules/vault/ui/VaultDashboard.tsx index 4150c3f..9a3f9cf 100644 --- a/src/components/modules/vault/ui/VaultDashboard.tsx +++ b/src/components/modules/vault/ui/VaultDashboard.tsx @@ -89,7 +89,6 @@ export default function VaultPage() { } }; - // Evitar hydration mismatch: walletAddress puede ser null en servidor y tener valor en cliente (localStorage) if (!hasMounted) { return (
@@ -488,7 +487,6 @@ export default function VaultPage() { ); })}
-
@@ -531,9 +529,15 @@ export default function VaultPage() {
                     {(() => {
                       const raw = (active.credential as unknown as { raw?: unknown }).raw;
-                      const vaultRecord = (active.credential as unknown as { vaultRecord?: unknown }).vaultRecord;
+                      const vaultRecord = (
+                        active.credential as unknown as { vaultRecord?: unknown }
+                      ).vaultRecord;
                       const payload = raw ?? vaultRecord ?? active.credential;
-                      try { return JSON.stringify(payload, null, 2); } catch { return String(payload); }
+                      try {
+                        return JSON.stringify(payload, null, 2);
+                      } catch {
+                        return String(payload);
+                      }
                     })()}
                   
From 1d7a7306dbfff13d0bb11f379aba59a9e8212244 Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Sat, 28 Feb 2026 00:21:27 -0600 Subject: [PATCH 04/38] chore: update configuration and dependencies - Updated next.config.ts to set outputFileTracingRoot to process.cwd(). - Added baseline-browser-mapping dependency to package.json and package-lock.json. - Adjusted peer dependencies in package-lock.json for various packages. - Cleaned up SavedCredentialsCard component by removing unused props. --- next.config.ts | 2 +- package-lock.json | 256 +++++---- package.json | 1 + .../credentials/ui/SavedCredentialsCard.tsx | 2 - yarn.lock | 504 ++++++++++++++++-- 5 files changed, 616 insertions(+), 149 deletions(-) diff --git a/next.config.ts b/next.config.ts index f40f72d..957fd51 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from 'next'; const nextConfig: NextConfig = { - transpilePackages: ['acta-builder'], + outputFileTracingRoot: process.cwd(), webpack: (config, { webpack }) => { config.resolve = config.resolve || {}; config.resolve.fallback = { diff --git a/package-lock.json b/package-lock.json index d552806..ec18356 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "@types/qrcode": "^1.5.6", "@types/react": "^19", "@types/react-dom": "^19", + "baseline-browser-mapping": "^2.10.0", "eslint": "^9.39.3", "eslint-config-next": "16.1.6", "husky": "^9.1.7", @@ -111,7 +112,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -652,13 +652,15 @@ "version": "13.2.1", "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-13.2.1.tgz", "integrity": "sha512-7RfX1gI16Vj2DgCp/ZoXqyLAakWo6+X95ku/rYGbVzuS/1etrlSiJmdbmdm+eYmszMlGQjrtOJQeVLXoj4L/Ag==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emurgo/cardano-serialization-lib-nodejs": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-13.2.0.tgz", "integrity": "sha512-Bz1zLGEqBQ0BVkqt1OgMxdBOE3BdUWUd7Ly9Ecr/aUwkA8AV1w1XzBMe4xblmJHnB1XXNlPH4SraXCvO+q0Mig==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", @@ -857,6 +859,7 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-10.1.1.tgz", "integrity": "sha512-NefPzPlrJ9w+NWVe06P+sHZQU98E1AEU9vhiHJEVT2wEcNBC1YX6hON9+smrfbn86C4U1pb2zbvjhkF+n/LKBw==", "license": "MIT", + "peer": true, "dependencies": { "@ethereumjs/util": "^10.1.1", "eventemitter3": "^5.0.1" @@ -867,6 +870,7 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-10.1.1.tgz", "integrity": "sha512-jbnWTEwcpoY+gE0r+wxfDG9zgiu54DcTcwnc9sX3DsqKR4l5K7x2V8mQL3Et6hURa4DuT9g7z6ukwpBLFchszg==", "license": "MPL-2.0", + "peer": true, "bin": { "rlp": "bin/rlp.cjs" }, @@ -879,6 +883,7 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-10.1.1.tgz", "integrity": "sha512-Kz8GWIKQjEQB60ko9hsYDX3rZMHZZOTcmm6OFl855Lu3padVnf5ZactUKM6nmWPsumHED5bWDjO32novZd1zyw==", "license": "MPL-2.0", + "peer": true, "dependencies": { "@ethereumjs/common": "^10.1.1", "@ethereumjs/rlp": "^10.1.1", @@ -895,6 +900,7 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", "license": "MIT", + "peer": true, "dependencies": { "@noble/hashes": "2.0.1" }, @@ -910,6 +916,7 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -922,6 +929,7 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-10.1.1.tgz", "integrity": "sha512-r2EhaeEmLZXVs1dT2HJFQysAkr63ZWATu/9tgYSp1IlvjvwyC++DLg5kCDwMM49HBq3sOAhrPnXkoqf9DV2gbw==", "license": "MPL-2.0", + "peer": true, "dependencies": { "@ethereumjs/rlp": "^10.1.1", "@noble/curves": "^2.0.1", @@ -936,6 +944,7 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", "license": "MIT", + "peer": true, "dependencies": { "@noble/hashes": "2.0.1" }, @@ -951,6 +960,7 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -963,6 +973,7 @@ "resolved": "https://registry.npmjs.org/@fivebinaries/coin-selection/-/coin-selection-3.0.0.tgz", "integrity": "sha512-h25Pn1ZA7oqQBQDodGAgIsQt66T2wDge9onBKNqE66WNWL0KJiKJbpij8YOLo5AAlEIg5IS7EB1QjBgDOIg6DQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@emurgo/cardano-serialization-lib-browser": "^13.2.0", "@emurgo/cardano-serialization-lib-nodejs": "13.2.0" @@ -1992,7 +2003,6 @@ "resolved": "https://registry.npmjs.org/@ngneat/elf/-/elf-2.5.1.tgz", "integrity": "sha512-13BItNZFgHglTiXuP9XhisNczwQ5QSzH+imAv9nAPsdbCq/3ortqkIYRnlxB8DGPVcuIjLujQ4OcZa+9QWgZtw==", "license": "MIT", - "peer": true, "peerDependencies": { "rxjs": ">=7.0.0" } @@ -2843,6 +2853,7 @@ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "license": "MIT", + "peer": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -2852,6 +2863,7 @@ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", "license": "MIT", + "peer": true, "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", @@ -2866,6 +2878,7 @@ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", "license": "MIT", + "peer": true, "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" @@ -2885,6 +2898,7 @@ "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz", "integrity": "sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2894,6 +2908,7 @@ "resolved": "https://registry.npmjs.org/@solana-program/stake/-/stake-0.2.1.tgz", "integrity": "sha512-ssNPsJv9XHaA+L7ihzmWGYcm/+XYURQ8UA3wQMKf6ccEHyHOUgoglkkDU/BoA0+wul6HxZUN0tHFymC0qFw6sg==", "license": "MIT", + "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2903,6 +2918,7 @@ "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.7.0.tgz", "integrity": "sha512-FKTBsKHpvHHNc1ATRm7SlC5nF/VdJtOSjldhcyfMN9R7xo712Mo2jHIzvBgn8zQO5Kg0DcWuKB7268Kv1ocicw==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2912,6 +2928,7 @@ "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.5.1.tgz", "integrity": "sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2921,6 +2938,7 @@ "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.4.2.tgz", "integrity": "sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0", "@solana/sysvars": "^2.1.0" @@ -2931,6 +2949,7 @@ "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-2.3.0.tgz", "integrity": "sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -2951,6 +2970,7 @@ "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-2.3.0.tgz", "integrity": "sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==", "license": "MIT", + "peer": true, "dependencies": { "@solana/assertions": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -2970,6 +2990,7 @@ "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-2.3.0.tgz", "integrity": "sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -2985,6 +3006,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.3.0.tgz", "integrity": "sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-data-structures": "2.3.0", @@ -3004,6 +3026,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -3019,6 +3042,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz", "integrity": "sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-numbers": "2.3.0", @@ -3036,6 +3060,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" @@ -3052,6 +3077,7 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz", "integrity": "sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-numbers": "2.3.0", @@ -3070,6 +3096,7 @@ "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", "license": "MIT", + "peer": true, "dependencies": { "chalk": "^5.4.1", "commander": "^14.0.0" @@ -3089,6 +3116,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", + "peer": true, "engines": { "node": ">=20" } @@ -3098,6 +3126,7 @@ "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz", "integrity": "sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3110,6 +3139,7 @@ "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-2.3.0.tgz", "integrity": "sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3122,6 +3152,7 @@ "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-2.3.0.tgz", "integrity": "sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" @@ -3138,6 +3169,7 @@ "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-2.3.0.tgz", "integrity": "sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==", "license": "MIT", + "peer": true, "dependencies": { "@solana/assertions": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3190,6 +3222,7 @@ "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-2.3.0.tgz", "integrity": "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3202,6 +3235,7 @@ "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.3.0.tgz", "integrity": "sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-data-structures": "2.3.0", @@ -3221,6 +3255,7 @@ "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-2.3.0.tgz", "integrity": "sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/errors": "2.3.0" @@ -3237,6 +3272,7 @@ "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-2.3.0.tgz", "integrity": "sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3249,6 +3285,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-2.3.0.tgz", "integrity": "sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/fast-stable-stringify": "2.3.0", @@ -3272,6 +3309,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-2.3.0.tgz", "integrity": "sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3297,6 +3335,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz", "integrity": "sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3309,6 +3348,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz", "integrity": "sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/rpc-spec-types": "2.3.0" @@ -3325,6 +3365,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz", "integrity": "sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3337,6 +3378,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz", "integrity": "sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/fast-stable-stringify": "2.3.0", @@ -3362,6 +3404,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz", "integrity": "sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/keys": "2.3.0", @@ -3383,6 +3426,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz", "integrity": "sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/functional": "2.3.0", @@ -3402,6 +3446,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz", "integrity": "sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/promises": "2.3.0", @@ -3420,6 +3465,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz", "integrity": "sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/functional": "2.3.0", @@ -3439,6 +3485,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz", "integrity": "sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/rpc-spec": "2.3.0", @@ -3457,6 +3504,7 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-2.3.0.tgz", "integrity": "sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3477,6 +3525,7 @@ "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-2.3.0.tgz", "integrity": "sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3499,6 +3548,7 @@ "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-2.3.0.tgz", "integrity": "sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==", "license": "MIT", + "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -3533,6 +3583,7 @@ "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz", "integrity": "sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-strings": "2.3.0", @@ -3557,6 +3608,7 @@ "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz", "integrity": "sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3580,6 +3632,7 @@ "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-2.3.0.tgz", "integrity": "sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==", "license": "MIT", + "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3607,7 +3660,6 @@ "integrity": "sha512-x+ZRB2/r5tVK/xw8QRbAfgPcX51G9f2ifEyAQ/J5npOO+6+MPeeCjtr5UxHNDAYs9Ypo0PN+YJATCO4vhzQJGg==", "deprecated": "@solana/web3.js version 2.0 is now @solana/kit! Remove @solana/web3.js@2 from your dependencies and replace it with @solana/kit. As needed, upgrade all of your @solana-program/* dependencies to the latest versions that use Kit.", "license": "MIT", - "peer": true, "dependencies": { "@solana/accounts": "2.0.0", "@solana/addresses": "2.0.0", @@ -5050,6 +5102,7 @@ "resolved": "https://registry.npmjs.org/@trezor/analytics/-/analytics-1.5.0.tgz", "integrity": "sha512-evILW5XJEmfPlf0TY1duOLtGJ47pdGeSKVE3P75ODEUsRNxtPVqlkOUBPmYpCxPnzS8XDmkatT8lf9/DF0G6nA==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@trezor/env-utils": "1.5.0", "@trezor/utils": "9.5.0" @@ -5063,6 +5116,7 @@ "resolved": "https://registry.npmjs.org/@trezor/blockchain-link/-/blockchain-link-2.6.1.tgz", "integrity": "sha512-SPwxkihOMI0o79BOy0RkfgVL2meuJhIe1yWHCeR8uoqf5KGblUyeXxvNCy6w8ckJ9LRpM1+bZhsUODuNs3083Q==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { "@solana-program/compute-budget": "^0.8.0", "@solana-program/stake": "^0.2.1", @@ -5092,6 +5146,7 @@ "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-types/-/blockchain-link-types-1.5.0.tgz", "integrity": "sha512-wD6FKKxNr89MTWYL+NikRkBcWXhiWNFR0AuDHW6GHmlCEHhKu/hAvQtcER8X5jt/Wd0hSKNZqtHBXJ1ZkpJ6rg==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@trezor/utils": "9.5.0", "@trezor/utxo-lib": "2.5.0" @@ -5105,6 +5160,7 @@ "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-utils/-/blockchain-link-utils-1.5.1.tgz", "integrity": "sha512-2tDGLEj5jzydjsJQONGTWVmCDDy6FTZ4ytr1/2gE6anyYEJU8MbaR+liTt3UvcP5jwZTNutwYLvZixRfrb8JpA==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@mobily/ts-belt": "^3.13.1", "@stellar/stellar-sdk": "14.2.0", @@ -5122,6 +5178,7 @@ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.0.4.tgz", "integrity": "sha512-UbNW6zbdOBXJwLAV2mMak0bIC9nw3IZVlQXkv2w2dk1jgCbJjy3oRVC943zeGE5JAm0Z9PHxrIjmkpGhayY7kw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@noble/curves": "^1.9.6", "@stellar/js-xdr": "^3.1.2", @@ -5140,6 +5197,7 @@ "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@stellar/stellar-base": "^14.0.1", "axios": "^1.12.2", @@ -5159,6 +5217,7 @@ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.0.4.tgz", "integrity": "sha512-UbNW6zbdOBXJwLAV2mMak0bIC9nw3IZVlQXkv2w2dk1jgCbJjy3oRVC943zeGE5JAm0Z9PHxrIjmkpGhayY7kw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@noble/curves": "^1.9.6", "@stellar/js-xdr": "^3.1.2", @@ -5177,6 +5236,7 @@ "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@stellar/stellar-base": "^14.0.1", "axios": "^1.12.2", @@ -5241,6 +5301,7 @@ "resolved": "https://registry.npmjs.org/@trezor/connect-analytics/-/connect-analytics-1.4.0.tgz", "integrity": "sha512-hy2J2oeIhRC/e1bOWXo5dsVMVnDwO2UKnxhR6FD8PINR3jgM6PWAXc6k33WJsBcyiTzwMP7/xPysLcgNJH5o4w==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@trezor/analytics": "1.5.0" }, @@ -5253,6 +5314,7 @@ "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-0.5.0.tgz", "integrity": "sha512-WE71iaFcWmfQxDCiTUNynj2DccRgUiLBJ+g3nrqCBJqEYzu+cD6eZ5k/OLtZ3hfh5gyB5EQwXdGvRT07iNdxAA==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { "@trezor/env-utils": "1.5.0", "@trezor/type-utils": "1.2.0", @@ -5669,6 +5731,7 @@ "resolved": "https://registry.npmjs.org/@trezor/crypto-utils/-/crypto-utils-1.2.0.tgz", "integrity": "sha512-9i1NrfW1IE6JO910ut7xrx4u5LxE++GETbpJhWLj4P5xpuGDDSDLEn/MXaYisls2DpE897aOrGPaa1qyt8V6tw==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "peerDependencies": { "tslib": "^2.6.2" } @@ -5678,6 +5741,7 @@ "resolved": "https://registry.npmjs.org/@trezor/device-authenticity/-/device-authenticity-1.1.1.tgz", "integrity": "sha512-WlYbQgc5l0pWUVP9GkMp+Oj3rVAqMKsWF0HyxujoymNjEB7rLTl2hXs+GFjlz7VnldaSslECc6EBex/eQiNOnA==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@noble/curves": "^2.0.1", "@trezor/crypto-utils": "1.2.0", @@ -5691,6 +5755,7 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", "license": "MIT", + "peer": true, "dependencies": { "@noble/hashes": "2.0.1" }, @@ -5706,6 +5771,7 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -5717,13 +5783,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-1.2.0.tgz", "integrity": "sha512-Aqp7pIooFTx21zRUtTI6i1AS4d9Lrx7cclvksh2nJQF9WJvbzuCXshEGkLoOsHwhQrCl3IXfbGuMdA12yDenPA==", - "license": "See LICENSE.md in repo root" + "license": "See LICENSE.md in repo root", + "peer": true }, "node_modules/@trezor/env-utils": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@trezor/env-utils/-/env-utils-1.5.0.tgz", "integrity": "sha512-u1TN7dMQ5Qhpbae08Z4JJmI9fQrbbJ4yj8eIAsuzMQn6vb+Sg9vbntl+IDsZ1G9WeI73uHTLu1wWMmAgiujH8w==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "ua-parser-js": "^2.0.4" }, @@ -5750,6 +5818,7 @@ "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.1.tgz", "integrity": "sha512-nAkaCCAqLpErBd+IuKeG5MpbyLR/2RMgCw18TWc80m1Ws/XgQirhHY9Jbk6gLImTXb9GTrxP0+MDSahzd94rSA==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@trezor/schema-utils": "1.4.0", "long": "5.2.5", @@ -5764,6 +5833,7 @@ "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-1.3.0.tgz", "integrity": "sha512-rmrxbDrdgxTouBPbZcSeqU7ba/e5WVT1dxvxxEntHqRdTiDl7d3VK+BErCrlyol8EH5YCqEF3/rXt0crSOfoFw==", "license": "See LICENSE.md in repo root", + "peer": true, "peerDependencies": { "tslib": "^2.6.2" } @@ -5773,6 +5843,7 @@ "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-1.4.0.tgz", "integrity": "sha512-K7upSeh7VDrORaIC4KAxYVW93XNlohmUnH5if/5GKYmTdQSRp1nBkO6Jm+Z4hzIthdnz/1aLgnbeN3bDxWLRxA==", "license": "See LICENSE.md in repo root", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.33.7", "ts-mixer": "^6.0.3" @@ -5786,6 +5857,7 @@ "resolved": "https://registry.npmjs.org/@trezor/transport/-/transport-1.6.1.tgz", "integrity": "sha512-RQNQingZ1TOVKSJu3Av9bmQovsu9n1NkcAYJ64+ZfapORfl/AzmZizRflhxU3FlIujQJK1gbIaW79+L54g7a8w==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { "@trezor/protobuf": "1.5.1", "@trezor/protocol": "1.3.0", @@ -5802,13 +5874,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-1.2.0.tgz", "integrity": "sha512-+E2QntxkyQuYfQQyl8RvT01tq2i5Dp/LFUOXuizF+KVOqsZBjBY43j5hewcCO3+MokD7deDiPyekbUEN5/iVlw==", - "license": "See LICENSE.md in repo root" + "license": "See LICENSE.md in repo root", + "peer": true }, "node_modules/@trezor/utils": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-9.5.0.tgz", "integrity": "sha512-kdyMyDbxzvOZmwBNvTjAK+C/kzyOz8T4oUbFvq+KaXn5mBFf1uf8rq5X2HkxgdYRPArtHS3PxLKsfkNCdhCYtQ==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { "bignumber.js": "^9.3.1" }, @@ -5821,6 +5895,7 @@ "resolved": "https://registry.npmjs.org/@trezor/utxo-lib/-/utxo-lib-2.5.0.tgz", "integrity": "sha512-Fa2cZh0037oX6AHNLfpFIj65UR/OoX0ZJTocFuQASe77/1PjZHysf6BvvGfmzuFToKfrAQ+DM/1Sx+P/vnyNmA==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { "@trezor/utils": "9.5.0", "bech32": "^2.0.0", @@ -5849,6 +5924,7 @@ "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-1.3.0.tgz", "integrity": "sha512-9KQSaVc3NtmM6rFFj1e+9bM0C5mVKVidbnxlfzuBJu7G2YMRdIdLPcAXhvmRZjs40uzDuBeApK+p547kODz2ug==", "license": "SEE LICENSE IN LICENSE.md", + "peer": true, "dependencies": { "@trezor/utils": "9.5.0", "ws": "^8.18.0" @@ -5926,7 +6002,6 @@ "integrity": "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5937,7 +6012,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5958,7 +6032,8 @@ "version": "0.0.197", "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.197.tgz", "integrity": "sha512-V4sOroWDADFx9dLodWpKm298NOJ1VJ6zoDVgaP+WBb/utWxqQ6gnMzd9lvVDAr/F3ibiKaxH9i45eS0gQPSTaQ==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/@types/ws": { "version": "7.4.7", @@ -6014,7 +6089,6 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -7004,6 +7078,7 @@ "resolved": "https://registry.npmjs.org/@xrplf/isomorphic/-/isomorphic-1.0.1.tgz", "integrity": "sha512-0bIpgx8PDjYdrLFeC3csF305QQ1L7sxaWnL5y71mCvhenZzJgku9QsA+9QCXBC1eNYtxWO/xR91zrXJy2T/ixg==", "license": "ISC", + "peer": true, "dependencies": { "@noble/hashes": "^1.0.0", "eventemitter3": "5.0.1", @@ -7017,13 +7092,15 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@xrplf/secret-numbers": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@xrplf/secret-numbers/-/secret-numbers-2.0.0.tgz", "integrity": "sha512-z3AOibRTE9E8MbjgzxqMpG1RNaBhQ1jnfhNCa1cGf2reZUJzPMYs4TggQTc7j8+0WyV3cr7y/U8Oz99SXIkN5Q==", "license": "ISC", + "peer": true, "dependencies": { "@xrplf/isomorphic": "^1.0.1", "ripple-keypairs": "^2.0.0" @@ -7035,7 +7112,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7310,6 +7386,7 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "license": "MIT", + "peer": true, "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -7320,7 +7397,8 @@ "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" + "license": "MIT", + "peer": true }, "node_modules/assert": { "version": "2.1.0", @@ -7420,50 +7498,6 @@ "dev": true, "license": "MIT" }, - "node_modules/bare-addon-resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz", - "integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-module-resolve": "^1.10.0", - "bare-semver": "^1.0.0" - }, - "peerDependencies": { - "bare-url": "*" - }, - "peerDependenciesMeta": { - "bare-url": { - "optional": true - } - } - }, - "node_modules/bare-module-resolve": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz", - "integrity": "sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-semver": "^1.0.0" - }, - "peerDependencies": { - "bare-url": "*" - }, - "peerDependenciesMeta": { - "bare-url": { - "optional": true - } - } - }, - "node_modules/bare-semver": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.2.tgz", - "integrity": "sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA==", - "license": "Apache-2.0", - "optional": true - }, "node_modules/base-x": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", @@ -7680,6 +7714,7 @@ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "license": "MIT", + "peer": true, "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -7694,6 +7729,7 @@ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "license": "MIT", + "peer": true, "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -7705,6 +7741,7 @@ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "license": "MIT", + "peer": true, "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -7717,6 +7754,7 @@ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "license": "MIT", + "peer": true, "dependencies": { "bn.js": "^5.2.1", "randombytes": "^2.1.0", @@ -7731,6 +7769,7 @@ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "license": "ISC", + "peer": true, "dependencies": { "bn.js": "^5.2.2", "browserify-rsa": "^4.1.1", @@ -7750,13 +7789,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/browserify-sign/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7771,13 +7812,15 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/browserify-sign/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -7786,7 +7829,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/browserslist": { "version": "4.28.1", @@ -7807,7 +7851,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7869,13 +7912,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/call-bind": { "version": "1.0.8", @@ -7977,6 +8022,7 @@ "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.11.tgz", "integrity": "sha512-vIwORDd/WyB8Nc23o2zNN5RrtFGlR6Fca61TtjkUXueI3Jf2DOZDl1zsshvBntZ3wZHBM9ztjnkXSmzQDaq3WA==", "license": "MIT", + "peer": true, "dependencies": { "nofilter": "^3.0.2" }, @@ -8138,6 +8184,7 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "license": "MIT", + "peer": true, "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" @@ -8147,7 +8194,8 @@ "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" + "license": "MIT", + "peer": true }, "node_modules/create-hash": { "version": "1.2.0", @@ -8214,6 +8262,7 @@ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "license": "MIT", + "peer": true, "dependencies": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -8401,6 +8450,7 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "license": "MIT", + "peer": true, "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -8436,7 +8486,8 @@ "url": "https://paypal.me/faisalman" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/detect-libc": { "version": "2.1.2", @@ -8459,6 +8510,7 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "license": "MIT", + "peer": true, "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -8469,7 +8521,8 @@ "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" + "license": "MIT", + "peer": true }, "node_modules/dijkstrajs": { "version": "1.0.3", @@ -8521,6 +8574,7 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -8789,7 +8843,6 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8923,7 +8976,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -9392,7 +9444,8 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/events": { "version": "3.3.0", @@ -9417,6 +9470,7 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "license": "MIT", + "peer": true, "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -10600,7 +10654,8 @@ "url": "https://paypal.me/faisalman" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/is-string": { "version": "1.1.1", @@ -10844,6 +10899,7 @@ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", + "peer": true, "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -10855,6 +10911,7 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", + "peer": true, "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" @@ -11334,6 +11391,7 @@ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "license": "MIT", + "peer": true, "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -11346,7 +11404,8 @@ "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" + "license": "MIT", + "peer": true }, "node_modules/mime-db": { "version": "1.52.0", @@ -11723,6 +11782,7 @@ "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", "license": "MIT", + "peer": true, "engines": { "node": ">=12.19" } @@ -12003,6 +12063,7 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "license": "ISC", + "peer": true, "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", @@ -12045,6 +12106,7 @@ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "license": "MIT", + "peer": true, "dependencies": { "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -12260,6 +12322,7 @@ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "license": "MIT", + "peer": true, "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -12273,7 +12336,8 @@ "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" + "license": "MIT", + "peer": true }, "node_modules/punycode": { "version": "2.3.1", @@ -12376,6 +12440,7 @@ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "license": "MIT", + "peer": true, "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" @@ -12386,7 +12451,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -12396,7 +12460,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -12560,19 +12623,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/require-addon": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz", - "integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "bare-addon-resolve": "^1.3.0" - }, - "engines": { - "bare": ">=1.10.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12658,6 +12708,7 @@ "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-5.0.0.tgz", "integrity": "sha512-de7osLRH/pt5HX2xw2TRJtbdLLWHu0RXirpQaEeCnWKY5DYHykh3ETSkofvm0aX0LJiV7kwkegJxQkmbO94gWw==", "license": "ISC", + "peer": true, "dependencies": { "@scure/base": "^1.1.3", "@xrplf/isomorphic": "^1.0.0" @@ -12671,6 +12722,7 @@ "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-2.7.0.tgz", "integrity": "sha512-gEBqan5muVp+q7jgZ6aUniSyN+e4FKRzn9uFAeFSIW7IgvkezP1cUolNtpahQ+jvaSK/33hxZA7wNmn1mc330g==", "license": "ISC", + "peer": true, "dependencies": { "@xrplf/isomorphic": "^1.0.1", "bignumber.js": "^9.0.0", @@ -12685,6 +12737,7 @@ "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-2.0.0.tgz", "integrity": "sha512-b5rfL2EZiffmklqZk1W+dvSy97v3V/C7936WxCCgDynaGPp7GE6R2XO7EU9O2LlM/z95rj870IylYnOQs+1Rag==", "license": "ISC", + "peer": true, "dependencies": { "@noble/curves": "^1.0.0", "@xrplf/isomorphic": "^1.0.0", @@ -12842,7 +12895,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -13195,6 +13247,7 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "license": "MIT", + "peer": true, "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", @@ -13204,16 +13257,6 @@ "node": ">= 14" } }, - "node_modules/sodium-native": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.3.tgz", - "integrity": "sha512-OnxSlN3uyY8D0EsLHpmm2HOFmKddQVvEMmsakCrXUzSd8kjjbzL413t4ZNF3n0UxSwNgwTyUvkmZHTfuCeiYSw==", - "license": "MIT", - "optional": true, - "dependencies": { - "require-addon": "^1.1.0" - } - }, "node_modules/sonic-boom": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", @@ -13636,7 +13679,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13719,8 +13761,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tw-animate-css": { "version": "1.4.0", @@ -13845,7 +13886,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -13896,7 +13936,8 @@ "url": "https://paypal.me/faisalman" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/ua-parser-js": { "version": "2.0.9", @@ -13917,6 +13958,7 @@ } ], "license": "AGPL-3.0-or-later", + "peer": true, "dependencies": { "detect-europe-js": "^0.1.2", "is-standalone-pwa": "^0.1.1", @@ -13982,7 +14024,8 @@ "version": "7.22.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.22.0.tgz", "integrity": "sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/unfetch": { "version": "4.2.0", @@ -14475,7 +14518,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -14497,6 +14539,7 @@ "resolved": "https://registry.npmjs.org/xrpl/-/xrpl-4.4.3.tgz", "integrity": "sha512-vi2OjuNkiaP8nv1j+nqHp8GZwwEjO6Y8+j/OuVMg6M4LwXEwyHdIj33dlg7cyY1Lw5+jb9HqFOQvABhaywVbTQ==", "license": "ISC", + "peer": true, "dependencies": { "@scure/bip32": "^1.3.1", "@scure/bip39": "^1.2.1", @@ -14631,7 +14674,6 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index deeefc1..b1b384e 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@types/qrcode": "^1.5.6", "@types/react": "^19", "@types/react-dom": "^19", + "baseline-browser-mapping": "^2.10.0", "eslint": "^9.39.3", "eslint-config-next": "16.1.6", "husky": "^9.1.7", diff --git a/src/components/modules/credentials/ui/SavedCredentialsCard.tsx b/src/components/modules/credentials/ui/SavedCredentialsCard.tsx index de799b6..66efc50 100644 --- a/src/components/modules/credentials/ui/SavedCredentialsCard.tsx +++ b/src/components/modules/credentials/ui/SavedCredentialsCard.tsx @@ -18,11 +18,9 @@ export function CredentialCard({ category, wallet, url, - onCopy, onShare, status, onRevoke, - onView, layoutId, onClick, }: ExpandableCredentialCardProps) { diff --git a/yarn.lock b/yarn.lock index 638628a..3b1df38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -299,7 +299,7 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@emnapi/core@^1.4.3": +"@emnapi/core@^1.4.3", "@emnapi/core@^1.6.0": version "1.7.1" resolved "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz" integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg== @@ -307,14 +307,14 @@ "@emnapi/wasi-threads" "1.1.0" tslib "^2.4.0" -"@emnapi/runtime@^1.4.3": +"@emnapi/runtime@^1.4.3", "@emnapi/runtime@^1.6.0", "@emnapi/runtime@^1.7.0": version "1.7.1" resolved "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz" integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA== dependencies: tslib "^2.4.0" -"@emnapi/wasi-threads@1.1.0": +"@emnapi/wasi-threads@^1.1.0", "@emnapi/wasi-threads@1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz" integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== @@ -543,6 +543,143 @@ resolved "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz" integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== +"@img/sharp-darwin-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-darwin-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz" + integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== + +"@img/sharp-libvips-darwin-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz" + integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== + +"@img/sharp-libvips-linux-arm@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz" + integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== + +"@img/sharp-libvips-linux-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz" + integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== + +"@img/sharp-libvips-linux-ppc64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz" + integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== + +"@img/sharp-libvips-linux-riscv64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz" + integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== + +"@img/sharp-libvips-linux-s390x@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz" + integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== + +"@img/sharp-libvips-linux-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz" + integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz" + integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz" + integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== + +"@img/sharp-linux-arm@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz" + integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.4" + +"@img/sharp-linux-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz" + integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.4" + +"@img/sharp-linux-ppc64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz" + integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.4" + +"@img/sharp-linux-riscv64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz" + integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== + optionalDependencies: + "@img/sharp-libvips-linux-riscv64" "1.2.4" + +"@img/sharp-linux-s390x@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz" + integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.4" + +"@img/sharp-linux-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz" + integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.4" + +"@img/sharp-linuxmusl-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz" + integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + +"@img/sharp-linuxmusl-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz" + integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + +"@img/sharp-wasm32@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz" + integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== + dependencies: + "@emnapi/runtime" "^1.7.0" + +"@img/sharp-win32-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz" + integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== + +"@img/sharp-win32-ia32@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz" + integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== + "@img/sharp-win32-x64@0.34.5": version "0.34.5" resolved "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz" @@ -729,11 +866,45 @@ "@motionone/dom" "^10.16.4" tslib "^2.3.1" +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz" + integrity sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz" + integrity sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz" + integrity sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz" + integrity sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz" + integrity sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg== + "@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3": version "3.0.3" resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz" integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== +"@napi-rs/wasm-runtime@^0.2.11", "@napi-rs/wasm-runtime@^1.0.7": + version "0.2.12" + resolved "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + "@next/env@16.1.6": version "16.1.6" resolved "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz" @@ -746,6 +917,41 @@ dependencies: fast-glob "3.3.1" +"@next/swc-darwin-arm64@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz" + integrity sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw== + +"@next/swc-darwin-x64@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz" + integrity sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ== + +"@next/swc-linux-arm64-gnu@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz" + integrity sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw== + +"@next/swc-linux-arm64-musl@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz" + integrity sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ== + +"@next/swc-linux-x64-gnu@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz" + integrity sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ== + +"@next/swc-linux-x64-musl@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz" + integrity sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg== + +"@next/swc-win32-arm64-msvc@16.1.6": + version "16.1.6" + resolved "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz" + integrity sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw== + "@next/swc-win32-x64-msvc@16.1.6": version "16.1.6" resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz" @@ -2208,6 +2414,68 @@ source-map-js "^1.2.1" tailwindcss "4.1.17" +"@tailwindcss/oxide-android-arm64@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz" + integrity sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ== + +"@tailwindcss/oxide-darwin-arm64@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz" + integrity sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg== + +"@tailwindcss/oxide-darwin-x64@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz" + integrity sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog== + +"@tailwindcss/oxide-freebsd-x64@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz" + integrity sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz" + integrity sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz" + integrity sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz" + integrity sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz" + integrity sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ== + +"@tailwindcss/oxide-linux-x64-musl@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz" + integrity sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ== + +"@tailwindcss/oxide-wasm32-wasi@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz" + integrity sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg== + dependencies: + "@emnapi/core" "^1.6.0" + "@emnapi/runtime" "^1.6.0" + "@emnapi/wasi-threads" "^1.1.0" + "@napi-rs/wasm-runtime" "^1.0.7" + "@tybys/wasm-util" "^0.10.1" + tslib "^2.4.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz" + integrity sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A== + "@tailwindcss/oxide-win32-x64-msvc@4.1.17": version "4.1.17" resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz" @@ -2655,7 +2923,7 @@ "@trezor/utils" "9.5.0" ws "^8.18.0" -"@tybys/wasm-util@^0.10.0": +"@tybys/wasm-util@^0.10.0", "@tybys/wasm-util@^0.10.1": version "0.10.1" resolved "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz" integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== @@ -2831,6 +3099,98 @@ "@typescript-eslint/types" "8.56.1" eslint-visitor-keys "^5.0.0" +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + "@unrs/resolver-binding-win32-x64-msvc@1.11.1": version "1.11.1" resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz" @@ -3308,26 +3668,6 @@ balanced-match@^4.0.2: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz" integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== -bare-addon-resolve@^1.3.0: - version "1.10.0" - resolved "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz" - integrity sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA== - dependencies: - bare-module-resolve "^1.10.0" - bare-semver "^1.0.0" - -bare-module-resolve@^1.10.0: - version "1.12.1" - resolved "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz" - integrity sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg== - dependencies: - bare-semver "^1.0.0" - -bare-semver@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.2.tgz" - integrity sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA== - base-x@^3.0.2: version "3.0.11" resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz" @@ -3357,7 +3697,7 @@ base64-js@^1.3.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -baseline-browser-mapping@^2.8.3, baseline-browser-mapping@^2.9.0: +baseline-browser-mapping@^2.10.0, baseline-browser-mapping@^2.8.3, baseline-browser-mapping@^2.9.0: version "2.10.0" resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz" integrity sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA== @@ -5266,6 +5606,106 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lightningcss-android-arm64@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz" + integrity sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A== + +lightningcss-android-arm64@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz" + integrity sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg== + +lightningcss-darwin-arm64@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz" + integrity sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA== + +lightningcss-darwin-arm64@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz" + integrity sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg== + +lightningcss-darwin-x64@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz" + integrity sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ== + +lightningcss-darwin-x64@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz" + integrity sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA== + +lightningcss-freebsd-x64@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz" + integrity sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA== + +lightningcss-freebsd-x64@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz" + integrity sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A== + +lightningcss-linux-arm-gnueabihf@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz" + integrity sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA== + +lightningcss-linux-arm-gnueabihf@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz" + integrity sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g== + +lightningcss-linux-arm64-gnu@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz" + integrity sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A== + +lightningcss-linux-arm64-gnu@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz" + integrity sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg== + +lightningcss-linux-arm64-musl@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz" + integrity sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA== + +lightningcss-linux-arm64-musl@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz" + integrity sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg== + +lightningcss-linux-x64-gnu@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz" + integrity sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w== + +lightningcss-linux-x64-gnu@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz" + integrity sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA== + +lightningcss-linux-x64-musl@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz" + integrity sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA== + +lightningcss-linux-x64-musl@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz" + integrity sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA== + +lightningcss-win32-arm64-msvc@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz" + integrity sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ== + +lightningcss-win32-arm64-msvc@1.31.1: + version "1.31.1" + resolved "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz" + integrity sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w== + lightningcss-win32-x64-msvc@1.30.2: version "1.30.2" resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz" @@ -6244,13 +6684,6 @@ regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: gopd "^1.2.0" set-function-name "^2.0.2" -require-addon@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz" - integrity sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA== - dependencies: - bare-addon-resolve "^1.3.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" @@ -6633,13 +7066,6 @@ socks@^2.8.3: ip-address "^10.0.1" smart-buffer "^4.2.0" -sodium-native@^4.1.1: - version "4.3.3" - resolved "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.3.tgz" - integrity sha512-OnxSlN3uyY8D0EsLHpmm2HOFmKddQVvEMmsakCrXUzSd8kjjbzL413t4ZNF3n0UxSwNgwTyUvkmZHTfuCeiYSw== - dependencies: - require-addon "^1.1.0" - sonic-boom@^2.2.1: version "2.8.0" resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz" From f09987d081c01481350917f666937627de282d7d Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Sat, 28 Feb 2026 12:16:00 -0600 Subject: [PATCH 05/38] feat: add Impacta Certificate template and enhance credential handling - Introduced a new credential template for the Impacta Certificate, including fields for holder name and description. - Updated the credential issuance logic to conditionally include the issuer name for the Impacta Certificate. - Enhanced the DynamicIssueForm to support expiration date validation based on template fields. --- .../modules/issue/hooks/useCredentialTemplates.ts | 7 +++++++ src/components/modules/issue/hooks/useIssueCredential.ts | 5 +++-- src/components/modules/issue/ui/DynamicIssueForm.tsx | 5 ++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/components/modules/issue/hooks/useCredentialTemplates.ts b/src/components/modules/issue/hooks/useCredentialTemplates.ts index 30c91c5..03a809e 100644 --- a/src/components/modules/issue/hooks/useCredentialTemplates.ts +++ b/src/components/modules/issue/hooks/useCredentialTemplates.ts @@ -6,6 +6,13 @@ export function useCredentialTemplates() { const { customTemplates, saveTemplate, deleteTemplate } = useCustomTemplates(); const builtIn: CredentialTemplate[] = [ + { + id: 'impacta-certificate', + title: 'Impacta Certificate', + description: 'Certificate template for BAF Impacta Bootcamp.', + vcType: 'ImpactaCertificateCredential', + fields: [{ key: 'holderName', label: 'Holder Name', type: 'text', required: true, placeholder: 'Full name' }], + }, { id: 'escrow', title: 'Escrow', diff --git a/src/components/modules/issue/hooks/useIssueCredential.ts b/src/components/modules/issue/hooks/useIssueCredential.ts index 41314e8..f4d10f8 100644 --- a/src/components/modules/issue/hooks/useIssueCredential.ts +++ b/src/components/modules/issue/hooks/useIssueCredential.ts @@ -86,7 +86,8 @@ export function useIssueCredential() { const nowIso = new Date().toISOString(); const expiration = state.values['expirationDate'] || undefined; - const rawSubject = state.values['subject'] || ''; + const hasSubjectField = tpl.fields.some((f) => f.key === 'subject'); + const rawSubject = hasSubjectField ? state.values['subject'] || '' : state.owner.trim(); const toSubjectDid = (input: string) => { if (!input) return ''; @@ -116,7 +117,7 @@ export function useIssueCredential() { setState((s) => ({ ...s, preview: vc })); return vc; - }, [state.template, state.values, ownerDid, network, state.vcId]); + }, [state.template, state.values, state.owner, ownerDid, network, state.vcId]); const validateRequired = useCallback( (fields: TemplateField[]) => { diff --git a/src/components/modules/issue/ui/DynamicIssueForm.tsx b/src/components/modules/issue/ui/DynamicIssueForm.tsx index 34a3a8a..4c22d8a 100644 --- a/src/components/modules/issue/ui/DynamicIssueForm.tsx +++ b/src/components/modules/issue/ui/DynamicIssueForm.tsx @@ -43,6 +43,7 @@ export default function DynamicIssueForm({ const [validatingKey, setValidatingKey] = useState(false); const [keyValidationError, setKeyValidationError] = useState(null); const [keyValidated, setKeyValidated] = useState(false); + const supportsExpiration = !!template?.fields.some((f) => f.key === 'expirationDate'); useEffect(() => { onBuildPreview(); @@ -71,8 +72,6 @@ export default function DynamicIssueForm({ } }; - void template; - return (
@@ -102,7 +101,7 @@ export default function DynamicIssueForm({ /> )}
- {template && ( + {template && supportsExpiration && (
Date: Mon, 2 Mar 2026 19:20:00 -0600 Subject: [PATCH 06/38] feat: add impacta bootcamp assets --- public/assets/impacta-bootcamp/asteriscs.svg | 53 +++++ public/assets/impacta-bootcamp/circles.svg | 21 ++ .../assets/impacta-bootcamp/corner-dots.svg | 21 ++ .../assets/impacta-bootcamp/corner-seal.svg | 35 ++++ .../assets/impacta-bootcamp/impacta-logo.svg | 92 +++++++++ .../assets/impacta-bootcamp/latam-outline.svg | 187 ++++++++++++++++++ .../stellar-baf-trustless.svg | 54 +++++ 7 files changed, 463 insertions(+) create mode 100644 public/assets/impacta-bootcamp/asteriscs.svg create mode 100644 public/assets/impacta-bootcamp/circles.svg create mode 100644 public/assets/impacta-bootcamp/corner-dots.svg create mode 100644 public/assets/impacta-bootcamp/corner-seal.svg create mode 100644 public/assets/impacta-bootcamp/impacta-logo.svg create mode 100644 public/assets/impacta-bootcamp/latam-outline.svg create mode 100644 public/assets/impacta-bootcamp/stellar-baf-trustless.svg diff --git a/public/assets/impacta-bootcamp/asteriscs.svg b/public/assets/impacta-bootcamp/asteriscs.svg new file mode 100644 index 0000000..bfa857e --- /dev/null +++ b/public/assets/impacta-bootcamp/asteriscs.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/assets/impacta-bootcamp/circles.svg b/public/assets/impacta-bootcamp/circles.svg new file mode 100644 index 0000000..858a552 --- /dev/null +++ b/public/assets/impacta-bootcamp/circles.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/assets/impacta-bootcamp/corner-dots.svg b/public/assets/impacta-bootcamp/corner-dots.svg new file mode 100644 index 0000000..b3c005b --- /dev/null +++ b/public/assets/impacta-bootcamp/corner-dots.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/assets/impacta-bootcamp/corner-seal.svg b/public/assets/impacta-bootcamp/corner-seal.svg new file mode 100644 index 0000000..6522312 --- /dev/null +++ b/public/assets/impacta-bootcamp/corner-seal.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/assets/impacta-bootcamp/impacta-logo.svg b/public/assets/impacta-bootcamp/impacta-logo.svg new file mode 100644 index 0000000..d7df0e4 --- /dev/null +++ b/public/assets/impacta-bootcamp/impacta-logo.svg @@ -0,0 +1,92 @@ + + + + + + + + + + IMPACTA + BOOTCAMP + + \ No newline at end of file diff --git a/public/assets/impacta-bootcamp/latam-outline.svg b/public/assets/impacta-bootcamp/latam-outline.svg new file mode 100644 index 0000000..d814144 --- /dev/null +++ b/public/assets/impacta-bootcamp/latam-outline.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/assets/impacta-bootcamp/stellar-baf-trustless.svg b/public/assets/impacta-bootcamp/stellar-baf-trustless.svg new file mode 100644 index 0000000..d23ee47 --- /dev/null +++ b/public/assets/impacta-bootcamp/stellar-baf-trustless.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 51f053a2b1b116cdd1648bd1cfea66a982c1540c Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 19:39:52 -0600 Subject: [PATCH 07/38] refactor: update SVG asset for impacta bootcamp --- .../stellar-baf-trustless.svg | 55 +------------------ 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/public/assets/impacta-bootcamp/stellar-baf-trustless.svg b/public/assets/impacta-bootcamp/stellar-baf-trustless.svg index d23ee47..df39cbd 100644 --- a/public/assets/impacta-bootcamp/stellar-baf-trustless.svg +++ b/public/assets/impacta-bootcamp/stellar-baf-trustless.svg @@ -1,54 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file From 3614b54bd3d4f1221acccc90319a957f782e571b Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 19:40:19 -0600 Subject: [PATCH 08/38] feat: add Certificate component for Impacta Bootcamp with decorative elements and layout --- .../ui/impacta-bootcamp/Certificate.tsx | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx new file mode 100644 index 0000000..4968653 --- /dev/null +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -0,0 +1,171 @@ +import Image from 'next/image'; + +export default function Certificate() { + return ( +
+
+
+ {/* Decorative thin white border line (partial frame) */} + + {/* Top line from logo area to right edge */} + + {/* Right vertical line going down */} + + {/* Left vertical line from top */} + + {/* Top horizontal short line at very top */} + + {/* Right short line at top to connect to seal */} + + + + {/* Top-left: Impacta Logo */} +
+ Impacta Bootcamp logo +
+ + {/* Top: Row of Asteriscs */} +
+ Asteriscs decorativos +
+ + {/* Top-right: Corner Seal (globe + asterisk) in white box */} +
+ Sello de esquina +
+ + {/* Left side: Circles / Coil */} +
+ Circulos decorativos +
+ + {/* Right side: Latam Map Outline with dots */} +
+ Mapa de Latinoamerica +
+ + {/* Main Title: CERTIFICADO DE PARTICIPACION */} +
+
+

+ {'Certificado de Participaci\u00F3n'} +

+
+
+ + {/* Subtitle text */} +
+

+ Se otorga el presente reconocimiento a: +

+
+ + {/* Name line */} +
+
+
+ + {/* Description text */} +
+

+ Por haber completado satisfactoriamente los + requisitos {'acad\u00E9micos'} y {'pr\u00E1cticos'} del programa intensivo{' '} + IMPACTA BOOTCAMP. +

+
+ + {/* Year 2026 */} +
+ + 2026 + +
+ + {/* Bottom-right: Corner Dots */} +
+ Puntos decorativos +
+ + {/* Bottom-left: Sponsor Logos (Stellar x BAF x Trustless) in white box */} +
+
+ Stellar, BAF y Trustless logos +
+
+
+
+
+ ); +} From 6c562eddf531040ef81a0c63389e04a4b7768e3f Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Mon, 2 Mar 2026 19:52:46 -0600 Subject: [PATCH 09/38] feat: enhance credential handling with additional fields and dynamic subject fields - Added optional fields `issuerName` and `issuerDid` to the Credential type for improved credential metadata. - Updated the `adaptVcToCredential` function to incorporate new fields and dynamically include additional subject fields. - Enhanced the `useShareCredential` hook to conditionally display the new issuer fields. - Modified the `useVerifyCard` hook to recognize `issuerDid` as a valid identifier. --- src/@types/credentials.ts | 3 ++ .../credentials/hooks/useCredentialsList.ts | 33 ++++++++++++++-- .../credentials/hooks/useShareCredential.ts | 39 ++++++++++++++++--- .../credentials/hooks/useVerifyCard.ts | 3 +- .../issue/hooks/useCredentialTemplates.ts | 10 ++++- .../modules/issue/hooks/useIssueCredential.ts | 5 ++- 6 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/@types/credentials.ts b/src/@types/credentials.ts index 62f2316..197260c 100644 --- a/src/@types/credentials.ts +++ b/src/@types/credentials.ts @@ -11,6 +11,8 @@ export type Credential = { id: string; title: string; issuer: string; + issuerName?: string; + issuerDid?: string; subject: string; type: string; issuedAt: string; @@ -26,6 +28,7 @@ export type Credential = { * Raw vault record returned by the API (`/contracts/vault/get-vc` + status merge). */ vaultRecord?: unknown; + [key: string]: unknown; }; export type CredentialVerifyProps = { diff --git a/src/components/modules/credentials/hooks/useCredentialsList.ts b/src/components/modules/credentials/hooks/useCredentialsList.ts index d439d32..4e73262 100644 --- a/src/components/modules/credentials/hooks/useCredentialsList.ts +++ b/src/components/modules/credentials/hooks/useCredentialsList.ts @@ -18,8 +18,9 @@ function adaptVcToCredential(vc: unknown): Credential { const p = (parsed ?? {}) as Record; const cs = (p.credentialSubject ?? {}) as Record; const title = (p.title as string) || (p.name as string) || (cs.name as string) || 'Credential'; - const issuer = - (obj.issuer_did as string) || (p.issuer as string) || (p.issuerName as string) || '-'; + const issuerName = (p.issuerName as string) || undefined; + const issuerDid = (obj.issuer_did as string) || (p.issuer as string) || undefined; + const issuer = issuerName || issuerDid || '-'; const subject = (p.subject as string) || (p.subjectDID as string) || (cs.id as string) || '-'; const rawType = (p.type as unknown) ?? (p.credentialType as unknown) ?? 'VC'; let type: string; @@ -48,7 +49,7 @@ function adaptVcToCredential(vc: unknown): Credential { const status: 'valid' | 'expired' | 'revoked' = statusNorm === 'revoked' ? 'revoked' : statusNorm === 'expired' ? 'expired' : 'valid'; - return { + const base: Credential = { id: String(obj.id ?? 'unknown'), title: String(title), issuer: String(issuer), @@ -58,9 +59,35 @@ function adaptVcToCredential(vc: unknown): Credential { expirationDate: expirationDate ? String(expirationDate) : null, status, birthDate: birthDate ? String(birthDate) : undefined, + issuerName, + issuerDid, raw: parsed, vaultRecord: obj, }; + + const reserved = new Set([ + 'id', + 'title', + 'issuer', + 'issuerName', + 'issuerDid', + 'subject', + 'type', + 'issuedAt', + 'expirationDate', + 'status', + 'birthDate', + 'raw', + 'vaultRecord', + ]); + const dynamicSubjectFields: Record = {}; + for (const [key, value] of Object.entries(cs)) { + if (key === 'id' || reserved.has(key)) continue; + if (value == null) continue; + dynamicSubjectFields[key] = value; + } + + return { ...base, ...dynamicSubjectFields }; } export function useCredentialsList() { diff --git a/src/components/modules/credentials/hooks/useShareCredential.ts b/src/components/modules/credentials/hooks/useShareCredential.ts index 1970070..371d152 100644 --- a/src/components/modules/credentials/hooks/useShareCredential.ts +++ b/src/components/modules/credentials/hooks/useShareCredential.ts @@ -4,17 +4,46 @@ import { useEffect, useMemo, useState } from 'react'; import type { Credential, ZkStatement } from '@/@types/credentials'; export function useShareCredential(credential: Credential | null) { - const fields = useMemo( - () => [ + const fields = useMemo(() => { + const isPresent = (value: unknown) => + value !== undefined && value !== null && String(value) !== ''; + const toLabel = (key: string) => + key + .replace(/([a-z])([A-Z])/g, '$1 $2') + .replace(/_/g, ' ') + .replace(/\s+/g, ' ') + .trim() + .replace(/^\w/, (m) => m.toUpperCase()); + const c = (credential ?? {}) as Record; + const base = [ + { key: 'issuerName', label: 'Issuer Name' }, + { key: 'issuerDid', label: 'Issuer DID' }, { key: 'issuer', label: 'Issuer' }, { key: 'subject', label: 'Holder DID' }, { key: 'type', label: 'Credential Type' }, { key: 'issuedAt', label: 'Issued At' }, { key: 'expirationDate', label: 'Expiration Date' }, { key: 'status', label: 'Status' }, - ], - [] - ); + ]; + const reserved = new Set([ + 'id', + 'title', + 'raw', + 'vaultRecord', + 'birthDate', + ...base.map((f) => f.key), + ]); + const next: Array<{ key: string; label: string }> = []; + for (const field of base) { + if (isPresent(c[field.key])) next.push(field); + } + for (const [key, value] of Object.entries(c)) { + if (reserved.has(key)) continue; + if (!isPresent(value)) continue; + next.push({ key, label: toLabel(key) }); + } + return next; + }, [credential]); const [selected, setSelected] = useState>({}); const [copied, setCopied] = useState(false); diff --git a/src/components/modules/credentials/hooks/useVerifyCard.ts b/src/components/modules/credentials/hooks/useVerifyCard.ts index e1ed4fd..e07d257 100644 --- a/src/components/modules/credentials/hooks/useVerifyCard.ts +++ b/src/components/modules/credentials/hooks/useVerifyCard.ts @@ -25,7 +25,8 @@ export function useVerifyCard(status?: string | null) { const lower = key.toLowerCase(); let text = raw; let isWallet = false; - if (lower === 'issuer' || lower === 'subject') { + const walletLike = raw.startsWith('did:') || /^G[0-9A-Za-z]{55}$/.test(raw); + if ((lower === 'issuer' || lower === 'subject' || lower === 'issuerdid') && walletLike) { const wallet = raw.startsWith('did:') ? (raw.split(':').pop() as string) : raw; text = shorten(wallet); isWallet = true; diff --git a/src/components/modules/issue/hooks/useCredentialTemplates.ts b/src/components/modules/issue/hooks/useCredentialTemplates.ts index 03a809e..ce7aa38 100644 --- a/src/components/modules/issue/hooks/useCredentialTemplates.ts +++ b/src/components/modules/issue/hooks/useCredentialTemplates.ts @@ -11,7 +11,15 @@ export function useCredentialTemplates() { title: 'Impacta Certificate', description: 'Certificate template for BAF Impacta Bootcamp.', vcType: 'ImpactaCertificateCredential', - fields: [{ key: 'holderName', label: 'Holder Name', type: 'text', required: true, placeholder: 'Full name' }], + fields: [ + { + key: 'holderName', + label: 'Holder Name', + type: 'text', + required: true, + placeholder: 'Full name', + }, + ], }, { id: 'escrow', diff --git a/src/components/modules/issue/hooks/useIssueCredential.ts b/src/components/modules/issue/hooks/useIssueCredential.ts index f4d10f8..dcd8f72 100644 --- a/src/components/modules/issue/hooks/useIssueCredential.ts +++ b/src/components/modules/issue/hooks/useIssueCredential.ts @@ -105,7 +105,7 @@ export function useIssueCredential() { credentialSubject[k] = v; } - const vc = { + const vc: Record = { id: state.vcId, '@context': ['https://www.w3.org/2018/credentials/v1'], type: ['VerifiableCredential', tpl.vcType], @@ -114,6 +114,9 @@ export function useIssueCredential() { expirationDate: expiration, credentialSubject, }; + if (tpl.id === 'impacta-certificate') { + vc.issuerName = 'BAF'; + } setState((s) => ({ ...s, preview: vc })); return vc; From 027cfc879c09e3945056844e5d80682572d54c1e Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Mon, 2 Mar 2026 19:56:19 -0600 Subject: [PATCH 10/38] fix: restore issuerName field in useShareCredential hook for credential sharing - Reintroduced the `issuerName` field in the `useShareCredential` hook to ensure proper handling of credential metadata. - Adjusted the base array to include `issuerName` for consistent credential sharing functionality. --- src/components/modules/credentials/hooks/useShareCredential.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/modules/credentials/hooks/useShareCredential.ts b/src/components/modules/credentials/hooks/useShareCredential.ts index 371d152..97fd027 100644 --- a/src/components/modules/credentials/hooks/useShareCredential.ts +++ b/src/components/modules/credentials/hooks/useShareCredential.ts @@ -16,7 +16,6 @@ export function useShareCredential(credential: Credential | null) { .replace(/^\w/, (m) => m.toUpperCase()); const c = (credential ?? {}) as Record; const base = [ - { key: 'issuerName', label: 'Issuer Name' }, { key: 'issuerDid', label: 'Issuer DID' }, { key: 'issuer', label: 'Issuer' }, { key: 'subject', label: 'Holder DID' }, @@ -31,6 +30,7 @@ export function useShareCredential(credential: Credential | null) { 'raw', 'vaultRecord', 'birthDate', + 'issuerName', ...base.map((f) => f.key), ]); const next: Array<{ key: string; label: string }> = []; From c2359c31ea7e6268515f02edeefb175f403d5d42 Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 21:18:31 -0600 Subject: [PATCH 11/38] feat: implement Impacta Bootcamp Certificate page and enhance credential handling - Added a new page for the Impacta Bootcamp Certificate, integrating the Certificate component for display. - Enhanced the `useCredentialVerify` and `useShareCredential` hooks to support the new Impacta Certificate type, including additional fields for credential sharing. - Updated the `CredentialVerify` and `ShareCredentialModal` components to conditionally render based on the Impacta Certificate type. - Refactored the `Certificate` component to accept props for dynamic rendering of certificate details. --- src/app/baf/page.tsx | 9 + .../credentials/hooks/useCredentialVerify.ts | 4 + .../credentials/hooks/useShareCredential.ts | 15 + .../credentials/ui/CredentialVerify.tsx | 43 +++ .../credentials/ui/ShareCredentialModal.tsx | 24 ++ .../ui/impacta-bootcamp/Certificate.tsx | 362 +++++++++++------- .../modules/issue/hooks/useIssueCredential.ts | 1 + 7 files changed, 313 insertions(+), 145 deletions(-) create mode 100644 src/app/baf/page.tsx diff --git a/src/app/baf/page.tsx b/src/app/baf/page.tsx new file mode 100644 index 0000000..a766844 --- /dev/null +++ b/src/app/baf/page.tsx @@ -0,0 +1,9 @@ +import Certificate from '@/components/modules/credentials/ui/impacta-bootcamp/Certificate'; + +export const metadata = { + title: 'Impacta Bootcamp Certificate', +}; + +export default function BafPage() { + return ; +} diff --git a/src/components/modules/credentials/hooks/useCredentialVerify.ts b/src/components/modules/credentials/hooks/useCredentialVerify.ts index 7abe250..8663e38 100644 --- a/src/components/modules/credentials/hooks/useCredentialVerify.ts +++ b/src/components/modules/credentials/hooks/useCredentialVerify.ts @@ -26,6 +26,7 @@ export function useCredentialVerify(vcId: string) { const [reverifyLoading, setReverifyLoading] = useState(false); const [shareParam, setShareParam] = useState(null); const [hasZkProofInShare, setHasZkProofInShare] = useState(false); + const [shareType, setShareType] = useState(null); useEffect(() => { const read = async () => { if (typeof window === 'undefined') return; @@ -86,8 +87,10 @@ export function useCredentialVerify(vcId: string) { statement?: unknown; proof?: string; ok?: boolean; + type?: string; }; setRevealed(sp.revealedFields || null); + setShareType(typeof sp.type === 'string' ? sp.type : null); const st = sp.statement; const hasSt = typeof st === 'object' && @@ -168,5 +171,6 @@ export function useCredentialVerify(vcId: string) { reverifyLoading, hasVerified, hasZkProofInShare, + shareType, }; } diff --git a/src/components/modules/credentials/hooks/useShareCredential.ts b/src/components/modules/credentials/hooks/useShareCredential.ts index 97fd027..83f7b44 100644 --- a/src/components/modules/credentials/hooks/useShareCredential.ts +++ b/src/components/modules/credentials/hooks/useShareCredential.ts @@ -15,6 +15,20 @@ export function useShareCredential(credential: Credential | null) { .trim() .replace(/^\w/, (m) => m.toUpperCase()); const c = (credential ?? {}) as Record; + + const isImpacta = + typeof c.type === 'string' && c.type.includes('ImpactaCertificateCredential'); + + if (isImpacta) { + const next: Array<{ key: string; label: string }> = []; + if (isPresent(c.issuer)) next.push({ key: 'issuer', label: 'Issuer' }); + if (isPresent(c.subject)) next.push({ key: 'subject', label: 'Holder DID' }); + if (isPresent(c.type)) next.push({ key: 'type', label: 'Credential Type' }); + if (isPresent(c.issuedAt)) next.push({ key: 'issuedAt', label: 'Issued At' }); + if (isPresent(c.status)) next.push({ key: 'status', label: 'Status' }); + if (isPresent(c.holderName)) next.push({ key: 'holderName', label: 'Holder Name' }); + return next; + } const base = [ { key: 'issuerDid', label: 'Issuer DID' }, { key: 'issuer', label: 'Issuer' }, @@ -100,6 +114,7 @@ export function useShareCredential(credential: Credential | null) { try { const payload: Record = { revealedFields }; if (credential?.id) payload.vc_id = credential.id; + if (credential?.type) payload.type = credential.type; if ( proof && proof.statement !== ('none' as ZkStatement) && diff --git a/src/components/modules/credentials/ui/CredentialVerify.tsx b/src/components/modules/credentials/ui/CredentialVerify.tsx index dc4f544..09880a4 100644 --- a/src/components/modules/credentials/ui/CredentialVerify.tsx +++ b/src/components/modules/credentials/ui/CredentialVerify.tsx @@ -2,6 +2,7 @@ import { CredentialVerifyCard } from './CredentialVerifyCard'; import { useCredentialVerify } from '@/components/modules/credentials/hooks/useCredentialVerify'; +import ImpactaCertificate from '@/components/modules/credentials/ui/impacta-bootcamp/Certificate'; export function CredentialVerify({ vcId }: { vcId: string }) { const { @@ -13,8 +14,50 @@ export function CredentialVerify({ vcId }: { vcId: string }) { reverifyLoading, hasVerified, hasZkProofInShare, + shareType, } = useCredentialVerify(vcId); + const isImpacta = + typeof shareType === 'string' && shareType.includes('ImpactaCertificateCredential'); + const impactaRevealed = (revealed || {}) as Record; + + if (isImpacta) { + return ( + + ); + } + return (
(''); + const isImpactaCertificate = !!credential?.type.includes('ImpactaCertificateCredential'); + + const impactaHolderName = + (credential as unknown as { holderName?: string | null })?.holderName ?? + ((credential?.raw as unknown as { credentialSubject?: { holderName?: string } } | null) + ?.credentialSubject?.holderName ?? + undefined); + + const impactaYear = + credential?.issuedAt && !Number.isNaN(Date.parse(credential.issuedAt)) + ? new Date(credential.issuedAt).getFullYear().toString() + : undefined; + useEffect(() => { (async () => { try { @@ -166,6 +180,16 @@ export default function ShareCredentialModal({
+ {isImpactaCertificate && ( +
+
+
+ +
+
+
+ )} +

Select Fields

diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 4968653..075ad5c 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -1,171 +1,243 @@ +'use client'; + import Image from 'next/image'; -export default function Certificate() { +type CertificateProps = { + holderName?: string; + year?: string | number; + issuer?: string; + subjectDid?: string; + credentialType?: string; + issuedAt?: string; + status?: string; +}; + +type CertificateCanvasProps = { + holderName?: string; + year?: string | number; +}; + +export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvasProps) { return ( -
-
-
- {/* Decorative thin white border line (partial frame) */} - - {/* Top line from logo area to right edge */} - - {/* Right vertical line going down */} - - {/* Left vertical line from top */} - - {/* Top horizontal short line at very top */} - - {/* Right short line at top to connect to seal */} - - +
+
+ {/* Decorative thin white border line (partial frame) */} + + {/* Top line from logo area to right edge */} + + {/* Right vertical line going down */} + + {/* Left vertical line from top */} + + {/* Top horizontal short line at very top */} + + {/* Right short line at top to connect to seal */} + + - {/* Top-left: Impacta Logo */} -
- Impacta Bootcamp logo -
+ {/* Top-left: Impacta Logo */} +
+ Impacta Bootcamp logo +
- {/* Top: Row of Asteriscs */} -
- Asteriscs decorativos -
+ {/* Top: Row of Asteriscs */} +
+ Asteriscs decorativos +
- {/* Top-right: Corner Seal (globe + asterisk) in white box */} -
- Sello de esquina -
+ {/* Top-right: Corner Seal (globe + asterisk) in white box */} +
+ Sello de esquina +
- {/* Left side: Circles / Coil */} -
- Circulos decorativos -
+ {/* Left side: Circles / Coil */} +
+ Circulos decorativos +
- {/* Right side: Latam Map Outline with dots */} -
- Mapa de Latinoamerica -
+ {/* Right side: Latam Map Outline with dots */} +
+ Mapa de Latinoamerica +
- {/* Main Title: CERTIFICADO DE PARTICIPACION */} -
-
-

- {'Certificado de Participaci\u00F3n'} -

-
+ {/* Main Title: CERTIFICADO DE PARTICIPACION */} +
+
+

+ {'Certificado de Participaci\u00F3n'} +

+
- {/* Subtitle text */} -
-

- Se otorga el presente reconocimiento a: -

-
+ {/* Subtitle text */} +
+

+ Se otorga el presente reconocimiento a: +

+
- {/* Name line */} -
-
+ {/* Name line */} +
+
+ {holderName && ( + + {holderName} + + )}
+
- {/* Description text */} -
-

- Por haber completado satisfactoriamente los - requisitos {'acad\u00E9micos'} y {'pr\u00E1cticos'} del programa intensivo{' '} - IMPACTA BOOTCAMP. -

-
+ {/* Description text */} +
+

+ Por haber completado satisfactoriamente los + requisitos {'acad\u00E9micos'} y {'pr\u00E1cticos'} del programa intensivo{' '} + IMPACTA BOOTCAMP. +

+
- {/* Year 2026 */} -
- - 2026 - -
+ {/* Year */} +
+ + {String(year)} + +
- {/* Bottom-right: Corner Dots */} -
+ {/* Bottom-right: Corner Dots */} +
+ Puntos decorativos +
+ + {/* Bottom-left: Sponsor Logos (Stellar x BAF x Trustless) in white box */} +
+
Puntos decorativos
+
+
+
+ ); +} + +export default function Certificate(props: CertificateProps) { + const { issuedAt, year, issuer, subjectDid, credentialType, status } = props; - {/* Bottom-left: Sponsor Logos (Stellar x BAF x Trustless) in white box */} -
-
- Stellar, BAF y Trustless logos + const derivedYear = + typeof year !== 'undefined' + ? year + : issuedAt && !Number.isNaN(Date.parse(issuedAt)) + ? new Date(issuedAt).getFullYear() + : 2026; + + const details = [ + issuer && { label: 'Issuer', value: issuer }, + subjectDid && { label: 'Holder DID', value: subjectDid }, + credentialType && { label: 'Credential Type', value: credentialType }, + issuedAt && { label: 'Issued At', value: issuedAt }, + status && { label: 'Status', value: status }, + ].filter(Boolean) as { label: string; value: string }[]; + + return ( +
+
+
+ +
+ + {details.length > 0 && ( +
+
+ Credential Details +
+
+ {details.map((item) => ( +
+
+ {item.label} +
+
{item.value}
+
+ ))}
-
+ )}
); } + diff --git a/src/components/modules/issue/hooks/useIssueCredential.ts b/src/components/modules/issue/hooks/useIssueCredential.ts index dcd8f72..1751a1a 100644 --- a/src/components/modules/issue/hooks/useIssueCredential.ts +++ b/src/components/modules/issue/hooks/useIssueCredential.ts @@ -116,6 +116,7 @@ export function useIssueCredential() { }; if (tpl.id === 'impacta-certificate') { vc.issuerName = 'BAF'; + vc.title = 'Impacta Bootcamp Certificate'; } setState((s) => ({ ...s, preview: vc })); From b3203427eb449c5495d001ab9c8a207820ce935e Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 21:18:52 -0600 Subject: [PATCH 12/38] refactor: clean up code formatting in credential components - Standardized code formatting in `useShareCredential`, `CredentialVerify`, `ShareCredentialModal`, and `Certificate` components for improved readability. - Removed unnecessary line breaks and adjusted indentation for consistency. --- .../credentials/hooks/useShareCredential.ts | 3 +-- .../credentials/ui/CredentialVerify.tsx | 4 +--- .../credentials/ui/ShareCredentialModal.tsx | 4 ++-- .../ui/impacta-bootcamp/Certificate.tsx | 21 ++----------------- 4 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/components/modules/credentials/hooks/useShareCredential.ts b/src/components/modules/credentials/hooks/useShareCredential.ts index 83f7b44..bb4ef76 100644 --- a/src/components/modules/credentials/hooks/useShareCredential.ts +++ b/src/components/modules/credentials/hooks/useShareCredential.ts @@ -16,8 +16,7 @@ export function useShareCredential(credential: Credential | null) { .replace(/^\w/, (m) => m.toUpperCase()); const c = (credential ?? {}) as Record; - const isImpacta = - typeof c.type === 'string' && c.type.includes('ImpactaCertificateCredential'); + const isImpacta = typeof c.type === 'string' && c.type.includes('ImpactaCertificateCredential'); if (isImpacta) { const next: Array<{ key: string; label: string }> = []; diff --git a/src/components/modules/credentials/ui/CredentialVerify.tsx b/src/components/modules/credentials/ui/CredentialVerify.tsx index 09880a4..ea01d45 100644 --- a/src/components/modules/credentials/ui/CredentialVerify.tsx +++ b/src/components/modules/credentials/ui/CredentialVerify.tsx @@ -40,9 +40,7 @@ export function CredentialVerify({ vcId }: { vcId: string }) { : undefined } credentialType={ - typeof impactaRevealed.type === 'string' - ? (impactaRevealed.type as string) - : undefined + typeof impactaRevealed.type === 'string' ? (impactaRevealed.type as string) : undefined } issuedAt={ typeof impactaRevealed.issuedAt === 'string' diff --git a/src/components/modules/credentials/ui/ShareCredentialModal.tsx b/src/components/modules/credentials/ui/ShareCredentialModal.tsx index 6cbf68f..dfe8dc6 100644 --- a/src/components/modules/credentials/ui/ShareCredentialModal.tsx +++ b/src/components/modules/credentials/ui/ShareCredentialModal.tsx @@ -40,9 +40,9 @@ export default function ShareCredentialModal({ const impactaHolderName = (credential as unknown as { holderName?: string | null })?.holderName ?? - ((credential?.raw as unknown as { credentialSubject?: { holderName?: string } } | null) + (credential?.raw as unknown as { credentialSubject?: { holderName?: string } } | null) ?.credentialSubject?.holderName ?? - undefined); + undefined; const impactaYear = credential?.issuedAt && !Number.isNaN(Date.parse(credential.issuedAt)) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 075ad5c..09e928c 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -30,15 +30,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas preserveAspectRatio="none" > {/* Top line from logo area to right edge */} - + {/* Right vertical line going down */} {/* Right short line at top to connect to seal */} - + {/* Top-left: Impacta Logo */} @@ -240,4 +224,3 @@ export default function Certificate(props: CertificateProps) { ); } - From f23f1e4cee737c713a630ca8e5b0bdebb14648df Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 21:20:03 -0600 Subject: [PATCH 13/38] refactor: streamline credential sharing logic in useShareCredential hook - Removed the fetch request for sharing credentials, simplifying the logic within the `useShareCredential` hook. - Adjusted payload handling to focus on encoding the credential data without making an API call. --- .../modules/credentials/hooks/useShareCredential.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/components/modules/credentials/hooks/useShareCredential.ts b/src/components/modules/credentials/hooks/useShareCredential.ts index bb4ef76..048d631 100644 --- a/src/components/modules/credentials/hooks/useShareCredential.ts +++ b/src/components/modules/credentials/hooks/useShareCredential.ts @@ -125,18 +125,6 @@ export function useShareCredential(credential: Credential | null) { payload.proof = proof.proof as unknown; if (typeof proof.ok === 'boolean') payload.ok = proof.ok as unknown; } - const resp = await fetch('/api/share', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - }); - if (resp.ok) { - const j = (await resp.json()) as { id?: string }; - if (j?.id) { - setShareParam(encodeURIComponent(j.id)); - return; - } - } const json = JSON.stringify(payload); const bytes = new TextEncoder().encode(json); let binary = ''; From eb839a50f8745316c25afbd6237e356411f0db18 Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 22:53:17 -0600 Subject: [PATCH 14/38] feat: enhance Impacta Bootcamp Certificate with floating animations and sharing functionality - Introduced floating animations for decorative elements in the CertificateCanvas component using CSS keyframes. - Added state management for sharing the certificate URL via social media, utilizing the useEffect hook to capture the current window URL. - Updated layout and styling for improved responsiveness and visual appeal. --- .../ui/impacta-bootcamp/Certificate.tsx | 106 +++++++++++++----- 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 09e928c..dd807ec 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -1,6 +1,8 @@ 'use client'; +import { useEffect, useState } from 'react'; import Image from 'next/image'; +import { Twitter, Linkedin } from 'lucide-react'; type CertificateProps = { holderName?: string; @@ -50,7 +52,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas {/* Top-left: Impacta Logo */} -
+
Impacta Bootcamp logo {/* Top: Row of Asteriscs */} -
+
Asteriscs decorativos {/* Top-right: Corner Seal (globe + asterisk) in white box */} -
+
Sello de esquina {/* Left side: Circles / Coil */} -
+
Circulos decorativos {/* Right side: Latam Map Outline with dots */} -
+
Mapa de Latinoamerica
{holderName && ( - + {holderName} )} @@ -148,7 +150,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas
{/* Bottom-right: Corner Dots */} -
+
Puntos decorativos
+ +
); } export default function Certificate(props: CertificateProps) { const { issuedAt, year, issuer, subjectDid, credentialType, status } = props; + const [shareUrl, setShareUrl] = useState(''); + + useEffect(() => { + if (typeof window !== 'undefined') setShareUrl(window.location.href); + }, []); const derivedYear = typeof year !== 'undefined' @@ -195,28 +225,54 @@ export default function Certificate(props: CertificateProps) { return (
-
-
- +
+ {/* Certificado a la izquierda */} +
+
+ +
{details.length > 0 && ( -
-
- Credential Details -
-
- {details.map((item) => ( -
-
- {item.label} +
+
+
+ Credential Details +
+
+ {details.map((item) => ( +
+
+ {item.label} +
+
{item.value}
-
{item.value}
-
- ))} + ))} +
+
+ +
)} From 207a3599a510fff2fb81a93eab4411b43c1a9fd9 Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 22:53:31 -0600 Subject: [PATCH 15/38] refactor: improve readability of share links in Certificate component - Reformatted the share link logic in the Certificate component for better clarity and maintainability. - Ensured consistent indentation and line breaks for improved code structure. --- .../credentials/ui/impacta-bootcamp/Certificate.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index dd807ec..5b3f6e5 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -256,7 +256,11 @@ export default function Certificate(props: CertificateProps) {
Share X Date: Mon, 2 Mar 2026 23:01:20 -0600 Subject: [PATCH 16/38] feat: enhance credential sharing functionality in useShareCredential hook and update Certificate component - Implemented a fallback mechanism in the `useShareCredential` hook to handle sharing via an API, with inline encoding as a backup. - Updated the share link format in the Certificate component to include a more descriptive message for social media sharing, improving user engagement. --- .../credentials/hooks/useShareCredential.ts | 26 +++++++++++++++++-- .../ui/impacta-bootcamp/Certificate.tsx | 6 +++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/components/modules/credentials/hooks/useShareCredential.ts b/src/components/modules/credentials/hooks/useShareCredential.ts index 048d631..cdfe8b1 100644 --- a/src/components/modules/credentials/hooks/useShareCredential.ts +++ b/src/components/modules/credentials/hooks/useShareCredential.ts @@ -125,12 +125,34 @@ export function useShareCredential(credential: Credential | null) { payload.proof = proof.proof as unknown; if (typeof proof.ok === 'boolean') payload.ok = proof.ok as unknown; } + const json = JSON.stringify(payload); + + // Prefer short share keys via /api/share so links stay compact (e.g. for X). + try { + const resp = await fetch('/api/share', { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: json, + }); + if (resp.ok) { + const data = (await resp.json()) as { id?: string } | null; + const id = data && typeof data.id === 'string' ? data.id : null; + if (id) { + setShareParam(encodeURIComponent(id)); + return; + } + } + } catch { + // fall through to inline encoding if share API is unavailable + } + + // Fallback: inline, URL-safe base64 payload. const bytes = new TextEncoder().encode(json); let binary = ''; for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]); - const encoded = encodeURIComponent(btoa(binary)); - setShareParam(encoded); + const b64 = btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); + setShareParam(encodeURIComponent(b64)); } catch { setShareParam(''); } diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 5b3f6e5..dabd8c4 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -234,7 +234,7 @@ export default function Certificate(props: CertificateProps) {
{details.length > 0 && ( -
+
Credential Details @@ -258,7 +258,9 @@ export default function Certificate(props: CertificateProps) { Date: Mon, 2 Mar 2026 23:01:31 -0600 Subject: [PATCH 17/38] fix: correct formatting in social media share link for Impacta Bootcamp Certificate - Updated the share link message in the Certificate component to ensure proper encoding and formatting for social media sharing. - Maintained consistency with previous enhancements to the sharing functionality. --- .../modules/credentials/ui/impacta-bootcamp/Certificate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index dabd8c4..77ce755 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -259,7 +259,7 @@ export default function Certificate(props: CertificateProps) { href={ shareUrl ? `https://twitter.com/intent/tweet?text=${encodeURIComponent( - `Mi certificado Impacta Bootcamp\n\n${shareUrl}\n\nEmitido por @ActaXyz \nGracias a @TheBAFNetwork @TrustlessWork @StellarOrg por el apoyo`, + `Mi certificado Impacta Bootcamp\n\n${shareUrl}\n\nEmitido por @ActaXyz \nGracias a @TheBAFNetwork @TrustlessWork @StellarOrg por el apoyo` )}` : '#' } From ce35c71098c36d5901194fcd72f438cebea0bd9b Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 23:02:49 -0600 Subject: [PATCH 18/38] refactor: simplify share URL state management in Certificate component - Replaced useEffect with a more concise useState initialization for the share URL, improving code clarity and performance. - Ensured the share URL is set correctly based on the window location, maintaining functionality for social media sharing. --- .../credentials/ui/impacta-bootcamp/Certificate.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 77ce755..8ef6d1b 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -202,11 +202,9 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas export default function Certificate(props: CertificateProps) { const { issuedAt, year, issuer, subjectDid, credentialType, status } = props; - const [shareUrl, setShareUrl] = useState(''); - - useEffect(() => { - if (typeof window !== 'undefined') setShareUrl(window.location.href); - }, []); + const [shareUrl] = useState(() => + typeof window !== 'undefined' ? window.location.href : '' + ); const derivedYear = typeof year !== 'undefined' From 5e65e2dbeabf5951b5fe8c944a89eccb30f98671 Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 23:02:57 -0600 Subject: [PATCH 19/38] refactor: streamline share URL initialization in Certificate component - Simplified the initialization of the share URL state in the Certificate component for improved readability. - Ensured the share URL is correctly set based on the window location, maintaining existing functionality. --- .../modules/credentials/ui/impacta-bootcamp/Certificate.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 8ef6d1b..0a7365d 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -202,9 +202,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas export default function Certificate(props: CertificateProps) { const { issuedAt, year, issuer, subjectDid, credentialType, status } = props; - const [shareUrl] = useState(() => - typeof window !== 'undefined' ? window.location.href : '' - ); + const [shareUrl] = useState(() => (typeof window !== 'undefined' ? window.location.href : '')); const derivedYear = typeof year !== 'undefined' From a359ef061ebb5eac56b9d6f1a218b5e41991541f Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 23:03:32 -0600 Subject: [PATCH 20/38] refactor: replace useState with useSyncExternalStore for share URL in Certificate component - Updated the share URL management in the Certificate component to utilize useSyncExternalStore, enhancing performance and clarity. - Maintained the functionality of dynamically setting the share URL based on the window location. --- .../credentials/ui/impacta-bootcamp/Certificate.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 0a7365d..4e81e64 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { useSyncExternalStore } from 'react'; import Image from 'next/image'; import { Twitter, Linkedin } from 'lucide-react'; @@ -202,7 +202,11 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas export default function Certificate(props: CertificateProps) { const { issuedAt, year, issuer, subjectDid, credentialType, status } = props; - const [shareUrl] = useState(() => (typeof window !== 'undefined' ? window.location.href : '')); + const shareUrl = useSyncExternalStore( + () => () => {}, + () => (typeof window !== 'undefined' ? window.location.href : ''), + () => '' + ); const derivedYear = typeof year !== 'undefined' From 6ee5057af2500b41741f839793c499ac602358c9 Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 23:37:42 -0600 Subject: [PATCH 21/38] feat: add image download functionality and short ID generation for certificate sharing - Implemented a new method to generate compact, URL-safe identifiers for share links in the Certificate component. - Added functionality to download the certificate as an image, including QR code generation for easy sharing. - Updated the CertificateCanvas component to support ref forwarding for better integration with the download feature. - Removed the unused BafPage component to streamline the codebase. --- package-lock.json | 312 +++++----- package.json | 2 + src/@types/impacta-certificate.ts | 15 + src/app/api/share/route.ts | 14 +- src/app/baf/page.tsx | 9 - .../ui/impacta-bootcamp/Certificate.tsx | 229 +++++--- yarn.lock | 541 +++--------------- 7 files changed, 426 insertions(+), 696 deletions(-) create mode 100644 src/@types/impacta-certificate.ts delete mode 100644 src/app/baf/page.tsx diff --git a/package-lock.json b/package-lock.json index ec18356..e2be551 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,8 @@ "buffer": "^6.0.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "html-to-image": "^1.11.13", + "html2canvas": "^1.4.1", "lucide-react": "^0.575.0", "motion": "^12.34.3", "next": "16.1.6", @@ -112,6 +114,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -652,15 +655,13 @@ "version": "13.2.1", "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-13.2.1.tgz", "integrity": "sha512-7RfX1gI16Vj2DgCp/ZoXqyLAakWo6+X95ku/rYGbVzuS/1etrlSiJmdbmdm+eYmszMlGQjrtOJQeVLXoj4L/Ag==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@emurgo/cardano-serialization-lib-nodejs": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-13.2.0.tgz", "integrity": "sha512-Bz1zLGEqBQ0BVkqt1OgMxdBOE3BdUWUd7Ly9Ecr/aUwkA8AV1w1XzBMe4xblmJHnB1XXNlPH4SraXCvO+q0Mig==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", @@ -859,7 +860,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-10.1.1.tgz", "integrity": "sha512-NefPzPlrJ9w+NWVe06P+sHZQU98E1AEU9vhiHJEVT2wEcNBC1YX6hON9+smrfbn86C4U1pb2zbvjhkF+n/LKBw==", "license": "MIT", - "peer": true, "dependencies": { "@ethereumjs/util": "^10.1.1", "eventemitter3": "^5.0.1" @@ -870,7 +870,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-10.1.1.tgz", "integrity": "sha512-jbnWTEwcpoY+gE0r+wxfDG9zgiu54DcTcwnc9sX3DsqKR4l5K7x2V8mQL3Et6hURa4DuT9g7z6ukwpBLFchszg==", "license": "MPL-2.0", - "peer": true, "bin": { "rlp": "bin/rlp.cjs" }, @@ -883,7 +882,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-10.1.1.tgz", "integrity": "sha512-Kz8GWIKQjEQB60ko9hsYDX3rZMHZZOTcmm6OFl855Lu3padVnf5ZactUKM6nmWPsumHED5bWDjO32novZd1zyw==", "license": "MPL-2.0", - "peer": true, "dependencies": { "@ethereumjs/common": "^10.1.1", "@ethereumjs/rlp": "^10.1.1", @@ -900,7 +898,6 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "2.0.1" }, @@ -916,7 +913,6 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -929,7 +925,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-10.1.1.tgz", "integrity": "sha512-r2EhaeEmLZXVs1dT2HJFQysAkr63ZWATu/9tgYSp1IlvjvwyC++DLg5kCDwMM49HBq3sOAhrPnXkoqf9DV2gbw==", "license": "MPL-2.0", - "peer": true, "dependencies": { "@ethereumjs/rlp": "^10.1.1", "@noble/curves": "^2.0.1", @@ -944,7 +939,6 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "2.0.1" }, @@ -960,7 +954,6 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -973,7 +966,6 @@ "resolved": "https://registry.npmjs.org/@fivebinaries/coin-selection/-/coin-selection-3.0.0.tgz", "integrity": "sha512-h25Pn1ZA7oqQBQDodGAgIsQt66T2wDge9onBKNqE66WNWL0KJiKJbpij8YOLo5AAlEIg5IS7EB1QjBgDOIg6DQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@emurgo/cardano-serialization-lib-browser": "^13.2.0", "@emurgo/cardano-serialization-lib-nodejs": "13.2.0" @@ -2003,6 +1995,7 @@ "resolved": "https://registry.npmjs.org/@ngneat/elf/-/elf-2.5.1.tgz", "integrity": "sha512-13BItNZFgHglTiXuP9XhisNczwQ5QSzH+imAv9nAPsdbCq/3ortqkIYRnlxB8DGPVcuIjLujQ4OcZa+9QWgZtw==", "license": "MIT", + "peer": true, "peerDependencies": { "rxjs": ">=7.0.0" } @@ -2853,7 +2846,6 @@ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", "license": "MIT", - "peer": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -2863,7 +2855,6 @@ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", "license": "MIT", - "peer": true, "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", @@ -2878,7 +2869,6 @@ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" @@ -2898,7 +2888,6 @@ "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz", "integrity": "sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2908,7 +2897,6 @@ "resolved": "https://registry.npmjs.org/@solana-program/stake/-/stake-0.2.1.tgz", "integrity": "sha512-ssNPsJv9XHaA+L7ihzmWGYcm/+XYURQ8UA3wQMKf6ccEHyHOUgoglkkDU/BoA0+wul6HxZUN0tHFymC0qFw6sg==", "license": "MIT", - "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2918,7 +2906,6 @@ "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.7.0.tgz", "integrity": "sha512-FKTBsKHpvHHNc1ATRm7SlC5nF/VdJtOSjldhcyfMN9R7xo712Mo2jHIzvBgn8zQO5Kg0DcWuKB7268Kv1ocicw==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2928,7 +2915,6 @@ "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.5.1.tgz", "integrity": "sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0" } @@ -2938,7 +2924,6 @@ "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.4.2.tgz", "integrity": "sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==", "license": "Apache-2.0", - "peer": true, "peerDependencies": { "@solana/kit": "^2.1.0", "@solana/sysvars": "^2.1.0" @@ -2949,7 +2934,6 @@ "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-2.3.0.tgz", "integrity": "sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -2970,7 +2954,6 @@ "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-2.3.0.tgz", "integrity": "sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==", "license": "MIT", - "peer": true, "dependencies": { "@solana/assertions": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -2990,7 +2973,6 @@ "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-2.3.0.tgz", "integrity": "sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -3006,7 +2988,6 @@ "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.3.0.tgz", "integrity": "sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==", "license": "MIT", - "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-data-structures": "2.3.0", @@ -3026,7 +3007,6 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -3042,7 +3022,6 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz", "integrity": "sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-numbers": "2.3.0", @@ -3060,7 +3039,6 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", "license": "MIT", - "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" @@ -3077,7 +3055,6 @@ "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz", "integrity": "sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==", "license": "MIT", - "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-numbers": "2.3.0", @@ -3096,7 +3073,6 @@ "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", "license": "MIT", - "peer": true, "dependencies": { "chalk": "^5.4.1", "commander": "^14.0.0" @@ -3116,7 +3092,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", - "peer": true, "engines": { "node": ">=20" } @@ -3126,7 +3101,6 @@ "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz", "integrity": "sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3139,7 +3113,6 @@ "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-2.3.0.tgz", "integrity": "sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3152,7 +3125,6 @@ "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-2.3.0.tgz", "integrity": "sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==", "license": "MIT", - "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" @@ -3169,7 +3141,6 @@ "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-2.3.0.tgz", "integrity": "sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==", "license": "MIT", - "peer": true, "dependencies": { "@solana/assertions": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3222,7 +3193,6 @@ "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-2.3.0.tgz", "integrity": "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3235,7 +3205,6 @@ "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.3.0.tgz", "integrity": "sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/codecs-data-structures": "2.3.0", @@ -3255,7 +3224,6 @@ "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-2.3.0.tgz", "integrity": "sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/errors": "2.3.0" @@ -3272,7 +3240,6 @@ "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-2.3.0.tgz", "integrity": "sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3285,7 +3252,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-2.3.0.tgz", "integrity": "sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/fast-stable-stringify": "2.3.0", @@ -3309,7 +3275,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-2.3.0.tgz", "integrity": "sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3335,7 +3300,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz", "integrity": "sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3348,7 +3312,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz", "integrity": "sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/rpc-spec-types": "2.3.0" @@ -3365,7 +3328,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz", "integrity": "sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=20.18.0" }, @@ -3378,7 +3340,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz", "integrity": "sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/fast-stable-stringify": "2.3.0", @@ -3404,7 +3365,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz", "integrity": "sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/keys": "2.3.0", @@ -3426,7 +3386,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz", "integrity": "sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/functional": "2.3.0", @@ -3446,7 +3405,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz", "integrity": "sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/promises": "2.3.0", @@ -3465,7 +3423,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz", "integrity": "sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/functional": "2.3.0", @@ -3485,7 +3442,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz", "integrity": "sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0", "@solana/rpc-spec": "2.3.0", @@ -3504,7 +3460,6 @@ "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-2.3.0.tgz", "integrity": "sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3525,7 +3480,6 @@ "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-2.3.0.tgz", "integrity": "sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3548,7 +3502,6 @@ "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-2.3.0.tgz", "integrity": "sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==", "license": "MIT", - "peer": true, "dependencies": { "@solana/errors": "2.3.0" }, @@ -3583,7 +3536,6 @@ "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz", "integrity": "sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-strings": "2.3.0", @@ -3608,7 +3560,6 @@ "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz", "integrity": "sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3632,7 +3583,6 @@ "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-2.3.0.tgz", "integrity": "sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==", "license": "MIT", - "peer": true, "dependencies": { "@solana/addresses": "2.3.0", "@solana/codecs-core": "2.3.0", @@ -3660,6 +3610,7 @@ "integrity": "sha512-x+ZRB2/r5tVK/xw8QRbAfgPcX51G9f2ifEyAQ/J5npOO+6+MPeeCjtr5UxHNDAYs9Ypo0PN+YJATCO4vhzQJGg==", "deprecated": "@solana/web3.js version 2.0 is now @solana/kit! Remove @solana/web3.js@2 from your dependencies and replace it with @solana/kit. As needed, upgrade all of your @solana-program/* dependencies to the latest versions that use Kit.", "license": "MIT", + "peer": true, "dependencies": { "@solana/accounts": "2.0.0", "@solana/addresses": "2.0.0", @@ -5102,7 +5053,6 @@ "resolved": "https://registry.npmjs.org/@trezor/analytics/-/analytics-1.5.0.tgz", "integrity": "sha512-evILW5XJEmfPlf0TY1duOLtGJ47pdGeSKVE3P75ODEUsRNxtPVqlkOUBPmYpCxPnzS8XDmkatT8lf9/DF0G6nA==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@trezor/env-utils": "1.5.0", "@trezor/utils": "9.5.0" @@ -5116,7 +5066,6 @@ "resolved": "https://registry.npmjs.org/@trezor/blockchain-link/-/blockchain-link-2.6.1.tgz", "integrity": "sha512-SPwxkihOMI0o79BOy0RkfgVL2meuJhIe1yWHCeR8uoqf5KGblUyeXxvNCy6w8ckJ9LRpM1+bZhsUODuNs3083Q==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "dependencies": { "@solana-program/compute-budget": "^0.8.0", "@solana-program/stake": "^0.2.1", @@ -5146,7 +5095,6 @@ "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-types/-/blockchain-link-types-1.5.0.tgz", "integrity": "sha512-wD6FKKxNr89MTWYL+NikRkBcWXhiWNFR0AuDHW6GHmlCEHhKu/hAvQtcER8X5jt/Wd0hSKNZqtHBXJ1ZkpJ6rg==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@trezor/utils": "9.5.0", "@trezor/utxo-lib": "2.5.0" @@ -5160,7 +5108,6 @@ "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-utils/-/blockchain-link-utils-1.5.1.tgz", "integrity": "sha512-2tDGLEj5jzydjsJQONGTWVmCDDy6FTZ4ytr1/2gE6anyYEJU8MbaR+liTt3UvcP5jwZTNutwYLvZixRfrb8JpA==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@mobily/ts-belt": "^3.13.1", "@stellar/stellar-sdk": "14.2.0", @@ -5178,7 +5125,6 @@ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.0.4.tgz", "integrity": "sha512-UbNW6zbdOBXJwLAV2mMak0bIC9nw3IZVlQXkv2w2dk1jgCbJjy3oRVC943zeGE5JAm0Z9PHxrIjmkpGhayY7kw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@noble/curves": "^1.9.6", "@stellar/js-xdr": "^3.1.2", @@ -5197,7 +5143,6 @@ "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@stellar/stellar-base": "^14.0.1", "axios": "^1.12.2", @@ -5217,7 +5162,6 @@ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.0.4.tgz", "integrity": "sha512-UbNW6zbdOBXJwLAV2mMak0bIC9nw3IZVlQXkv2w2dk1jgCbJjy3oRVC943zeGE5JAm0Z9PHxrIjmkpGhayY7kw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@noble/curves": "^1.9.6", "@stellar/js-xdr": "^3.1.2", @@ -5236,7 +5180,6 @@ "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@stellar/stellar-base": "^14.0.1", "axios": "^1.12.2", @@ -5301,7 +5244,6 @@ "resolved": "https://registry.npmjs.org/@trezor/connect-analytics/-/connect-analytics-1.4.0.tgz", "integrity": "sha512-hy2J2oeIhRC/e1bOWXo5dsVMVnDwO2UKnxhR6FD8PINR3jgM6PWAXc6k33WJsBcyiTzwMP7/xPysLcgNJH5o4w==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@trezor/analytics": "1.5.0" }, @@ -5314,7 +5256,6 @@ "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-0.5.0.tgz", "integrity": "sha512-WE71iaFcWmfQxDCiTUNynj2DccRgUiLBJ+g3nrqCBJqEYzu+cD6eZ5k/OLtZ3hfh5gyB5EQwXdGvRT07iNdxAA==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "dependencies": { "@trezor/env-utils": "1.5.0", "@trezor/type-utils": "1.2.0", @@ -5731,7 +5672,6 @@ "resolved": "https://registry.npmjs.org/@trezor/crypto-utils/-/crypto-utils-1.2.0.tgz", "integrity": "sha512-9i1NrfW1IE6JO910ut7xrx4u5LxE++GETbpJhWLj4P5xpuGDDSDLEn/MXaYisls2DpE897aOrGPaa1qyt8V6tw==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "peerDependencies": { "tslib": "^2.6.2" } @@ -5741,7 +5681,6 @@ "resolved": "https://registry.npmjs.org/@trezor/device-authenticity/-/device-authenticity-1.1.1.tgz", "integrity": "sha512-WlYbQgc5l0pWUVP9GkMp+Oj3rVAqMKsWF0HyxujoymNjEB7rLTl2hXs+GFjlz7VnldaSslECc6EBex/eQiNOnA==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@noble/curves": "^2.0.1", "@trezor/crypto-utils": "1.2.0", @@ -5755,7 +5694,6 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "2.0.1" }, @@ -5771,7 +5709,6 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", - "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -5783,15 +5720,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-1.2.0.tgz", "integrity": "sha512-Aqp7pIooFTx21zRUtTI6i1AS4d9Lrx7cclvksh2nJQF9WJvbzuCXshEGkLoOsHwhQrCl3IXfbGuMdA12yDenPA==", - "license": "See LICENSE.md in repo root", - "peer": true + "license": "See LICENSE.md in repo root" }, "node_modules/@trezor/env-utils": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@trezor/env-utils/-/env-utils-1.5.0.tgz", "integrity": "sha512-u1TN7dMQ5Qhpbae08Z4JJmI9fQrbbJ4yj8eIAsuzMQn6vb+Sg9vbntl+IDsZ1G9WeI73uHTLu1wWMmAgiujH8w==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "ua-parser-js": "^2.0.4" }, @@ -5818,7 +5753,6 @@ "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.1.tgz", "integrity": "sha512-nAkaCCAqLpErBd+IuKeG5MpbyLR/2RMgCw18TWc80m1Ws/XgQirhHY9Jbk6gLImTXb9GTrxP0+MDSahzd94rSA==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@trezor/schema-utils": "1.4.0", "long": "5.2.5", @@ -5833,7 +5767,6 @@ "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-1.3.0.tgz", "integrity": "sha512-rmrxbDrdgxTouBPbZcSeqU7ba/e5WVT1dxvxxEntHqRdTiDl7d3VK+BErCrlyol8EH5YCqEF3/rXt0crSOfoFw==", "license": "See LICENSE.md in repo root", - "peer": true, "peerDependencies": { "tslib": "^2.6.2" } @@ -5843,7 +5776,6 @@ "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-1.4.0.tgz", "integrity": "sha512-K7upSeh7VDrORaIC4KAxYVW93XNlohmUnH5if/5GKYmTdQSRp1nBkO6Jm+Z4hzIthdnz/1aLgnbeN3bDxWLRxA==", "license": "See LICENSE.md in repo root", - "peer": true, "dependencies": { "@sinclair/typebox": "^0.33.7", "ts-mixer": "^6.0.3" @@ -5857,7 +5789,6 @@ "resolved": "https://registry.npmjs.org/@trezor/transport/-/transport-1.6.1.tgz", "integrity": "sha512-RQNQingZ1TOVKSJu3Av9bmQovsu9n1NkcAYJ64+ZfapORfl/AzmZizRflhxU3FlIujQJK1gbIaW79+L54g7a8w==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "dependencies": { "@trezor/protobuf": "1.5.1", "@trezor/protocol": "1.3.0", @@ -5874,15 +5805,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-1.2.0.tgz", "integrity": "sha512-+E2QntxkyQuYfQQyl8RvT01tq2i5Dp/LFUOXuizF+KVOqsZBjBY43j5hewcCO3+MokD7deDiPyekbUEN5/iVlw==", - "license": "See LICENSE.md in repo root", - "peer": true + "license": "See LICENSE.md in repo root" }, "node_modules/@trezor/utils": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-9.5.0.tgz", "integrity": "sha512-kdyMyDbxzvOZmwBNvTjAK+C/kzyOz8T4oUbFvq+KaXn5mBFf1uf8rq5X2HkxgdYRPArtHS3PxLKsfkNCdhCYtQ==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "dependencies": { "bignumber.js": "^9.3.1" }, @@ -5895,7 +5824,6 @@ "resolved": "https://registry.npmjs.org/@trezor/utxo-lib/-/utxo-lib-2.5.0.tgz", "integrity": "sha512-Fa2cZh0037oX6AHNLfpFIj65UR/OoX0ZJTocFuQASe77/1PjZHysf6BvvGfmzuFToKfrAQ+DM/1Sx+P/vnyNmA==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "dependencies": { "@trezor/utils": "9.5.0", "bech32": "^2.0.0", @@ -5924,7 +5852,6 @@ "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-1.3.0.tgz", "integrity": "sha512-9KQSaVc3NtmM6rFFj1e+9bM0C5mVKVidbnxlfzuBJu7G2YMRdIdLPcAXhvmRZjs40uzDuBeApK+p547kODz2ug==", "license": "SEE LICENSE IN LICENSE.md", - "peer": true, "dependencies": { "@trezor/utils": "9.5.0", "ws": "^8.18.0" @@ -6002,6 +5929,7 @@ "integrity": "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -6012,6 +5940,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -6032,8 +5961,7 @@ "version": "0.0.197", "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.197.tgz", "integrity": "sha512-V4sOroWDADFx9dLodWpKm298NOJ1VJ6zoDVgaP+WBb/utWxqQ6gnMzd9lvVDAr/F3ibiKaxH9i45eS0gQPSTaQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/@types/ws": { "version": "7.4.7", @@ -6089,6 +6017,7 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -7078,7 +7007,6 @@ "resolved": "https://registry.npmjs.org/@xrplf/isomorphic/-/isomorphic-1.0.1.tgz", "integrity": "sha512-0bIpgx8PDjYdrLFeC3csF305QQ1L7sxaWnL5y71mCvhenZzJgku9QsA+9QCXBC1eNYtxWO/xR91zrXJy2T/ixg==", "license": "ISC", - "peer": true, "dependencies": { "@noble/hashes": "^1.0.0", "eventemitter3": "5.0.1", @@ -7092,15 +7020,13 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@xrplf/secret-numbers": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@xrplf/secret-numbers/-/secret-numbers-2.0.0.tgz", "integrity": "sha512-z3AOibRTE9E8MbjgzxqMpG1RNaBhQ1jnfhNCa1cGf2reZUJzPMYs4TggQTc7j8+0WyV3cr7y/U8Oz99SXIkN5Q==", "license": "ISC", - "peer": true, "dependencies": { "@xrplf/isomorphic": "^1.0.1", "ripple-keypairs": "^2.0.0" @@ -7112,6 +7038,7 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7386,7 +7313,6 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -7397,8 +7323,7 @@ "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", - "peer": true + "license": "MIT" }, "node_modules/assert": { "version": "2.1.0", @@ -7498,6 +7423,50 @@ "dev": true, "license": "MIT" }, + "node_modules/bare-addon-resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz", + "integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-module-resolve": "^1.10.0", + "bare-semver": "^1.0.0" + }, + "peerDependencies": { + "bare-url": "*" + }, + "peerDependenciesMeta": { + "bare-url": { + "optional": true + } + } + }, + "node_modules/bare-module-resolve": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz", + "integrity": "sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-semver": "^1.0.0" + }, + "peerDependencies": { + "bare-url": "*" + }, + "peerDependenciesMeta": { + "bare-url": { + "optional": true + } + } + }, + "node_modules/bare-semver": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.2.tgz", + "integrity": "sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA==", + "license": "Apache-2.0", + "optional": true + }, "node_modules/base-x": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", @@ -7513,6 +7482,15 @@ "node": ">=0.12.0" } }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -7714,7 +7692,6 @@ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "license": "MIT", - "peer": true, "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -7729,7 +7706,6 @@ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "license": "MIT", - "peer": true, "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -7741,7 +7717,6 @@ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "license": "MIT", - "peer": true, "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -7754,7 +7729,6 @@ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^5.2.1", "randombytes": "^2.1.0", @@ -7769,7 +7743,6 @@ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "license": "ISC", - "peer": true, "dependencies": { "bn.js": "^5.2.2", "browserify-rsa": "^4.1.1", @@ -7789,15 +7762,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-sign/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7812,15 +7783,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserify-sign/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -7829,8 +7798,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/browserslist": { "version": "4.28.1", @@ -7851,6 +7819,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7912,15 +7881,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/call-bind": { "version": "1.0.8", @@ -8022,7 +7989,6 @@ "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.11.tgz", "integrity": "sha512-vIwORDd/WyB8Nc23o2zNN5RrtFGlR6Fca61TtjkUXueI3Jf2DOZDl1zsshvBntZ3wZHBM9ztjnkXSmzQDaq3WA==", "license": "MIT", - "peer": true, "dependencies": { "nofilter": "^3.0.2" }, @@ -8184,7 +8150,6 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" @@ -8194,8 +8159,7 @@ "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", - "peer": true + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", @@ -8262,7 +8226,6 @@ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "license": "MIT", - "peer": true, "dependencies": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -8280,6 +8243,15 @@ "node": "*" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -8450,7 +8422,6 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -8486,8 +8457,7 @@ "url": "https://paypal.me/faisalman" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/detect-libc": { "version": "2.1.2", @@ -8510,7 +8480,6 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -8521,8 +8490,7 @@ "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", - "peer": true + "license": "MIT" }, "node_modules/dijkstrajs": { "version": "1.0.3", @@ -8574,7 +8542,6 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -8843,6 +8810,7 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8976,6 +8944,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -9444,8 +9413,7 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", @@ -9470,7 +9438,6 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "license": "MIT", - "peer": true, "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -10132,6 +10099,25 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/html-to-image": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", + "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", + "license": "MIT" + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -10654,8 +10640,7 @@ "url": "https://paypal.me/faisalman" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/is-string": { "version": "1.1.1", @@ -10899,7 +10884,6 @@ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", - "peer": true, "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -10911,7 +10895,6 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", - "peer": true, "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" @@ -11391,7 +11374,6 @@ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -11404,8 +11386,7 @@ "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", - "peer": true + "license": "MIT" }, "node_modules/mime-db": { "version": "1.52.0", @@ -11782,7 +11763,6 @@ "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", "license": "MIT", - "peer": true, "engines": { "node": ">=12.19" } @@ -12063,7 +12043,6 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "license": "ISC", - "peer": true, "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", @@ -12106,7 +12085,6 @@ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "license": "MIT", - "peer": true, "dependencies": { "create-hash": "^1.2.0", "create-hmac": "^1.1.7", @@ -12322,7 +12300,6 @@ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "license": "MIT", - "peer": true, "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -12336,8 +12313,7 @@ "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", - "peer": true + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", @@ -12440,7 +12416,6 @@ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "license": "MIT", - "peer": true, "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" @@ -12451,6 +12426,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -12460,6 +12436,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -12623,6 +12600,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-addon": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz", + "integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-addon-resolve": "^1.3.0" + }, + "engines": { + "bare": ">=1.10.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12708,7 +12698,6 @@ "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-5.0.0.tgz", "integrity": "sha512-de7osLRH/pt5HX2xw2TRJtbdLLWHu0RXirpQaEeCnWKY5DYHykh3ETSkofvm0aX0LJiV7kwkegJxQkmbO94gWw==", "license": "ISC", - "peer": true, "dependencies": { "@scure/base": "^1.1.3", "@xrplf/isomorphic": "^1.0.0" @@ -12722,7 +12711,6 @@ "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-2.7.0.tgz", "integrity": "sha512-gEBqan5muVp+q7jgZ6aUniSyN+e4FKRzn9uFAeFSIW7IgvkezP1cUolNtpahQ+jvaSK/33hxZA7wNmn1mc330g==", "license": "ISC", - "peer": true, "dependencies": { "@xrplf/isomorphic": "^1.0.1", "bignumber.js": "^9.0.0", @@ -12737,7 +12725,6 @@ "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-2.0.0.tgz", "integrity": "sha512-b5rfL2EZiffmklqZk1W+dvSy97v3V/C7936WxCCgDynaGPp7GE6R2XO7EU9O2LlM/z95rj870IylYnOQs+1Rag==", "license": "ISC", - "peer": true, "dependencies": { "@noble/curves": "^1.0.0", "@xrplf/isomorphic": "^1.0.0", @@ -12895,6 +12882,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -13247,7 +13235,6 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "license": "MIT", - "peer": true, "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", @@ -13257,6 +13244,16 @@ "node": ">= 14" } }, + "node_modules/sodium-native": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.3.tgz", + "integrity": "sha512-OnxSlN3uyY8D0EsLHpmm2HOFmKddQVvEMmsakCrXUzSd8kjjbzL413t4ZNF3n0UxSwNgwTyUvkmZHTfuCeiYSw==", + "license": "MIT", + "optional": true, + "dependencies": { + "require-addon": "^1.1.0" + } + }, "node_modules/sonic-boom": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", @@ -13606,6 +13603,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/thread-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", @@ -13679,6 +13685,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -13761,7 +13768,8 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/tw-animate-css": { "version": "1.4.0", @@ -13886,6 +13894,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -13936,8 +13945,7 @@ "url": "https://paypal.me/faisalman" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ua-parser-js": { "version": "2.0.9", @@ -13958,7 +13966,6 @@ } ], "license": "AGPL-3.0-or-later", - "peer": true, "dependencies": { "detect-europe-js": "^0.1.2", "is-standalone-pwa": "^0.1.1", @@ -14024,8 +14031,7 @@ "version": "7.22.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.22.0.tgz", "integrity": "sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/unfetch": { "version": "4.2.0", @@ -14305,6 +14311,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/valtio": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.11.2.tgz", @@ -14518,6 +14533,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -14539,7 +14555,6 @@ "resolved": "https://registry.npmjs.org/xrpl/-/xrpl-4.4.3.tgz", "integrity": "sha512-vi2OjuNkiaP8nv1j+nqHp8GZwwEjO6Y8+j/OuVMg6M4LwXEwyHdIj33dlg7cyY1Lw5+jb9HqFOQvABhaywVbTQ==", "license": "ISC", - "peer": true, "dependencies": { "@scure/bip32": "^1.3.1", "@scure/bip39": "^1.2.1", @@ -14674,6 +14689,7 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index b1b384e..0e8482a 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "buffer": "^6.0.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "html-to-image": "^1.11.13", + "html2canvas": "^1.4.1", "lucide-react": "^0.575.0", "motion": "^12.34.3", "next": "16.1.6", diff --git a/src/@types/impacta-certificate.ts b/src/@types/impacta-certificate.ts new file mode 100644 index 0000000..860f12c --- /dev/null +++ b/src/@types/impacta-certificate.ts @@ -0,0 +1,15 @@ +export type ImpactaCertificateProps = { + holderName?: string; + year?: string | number; + issuer?: string; + subjectDid?: string; + credentialType?: string; + issuedAt?: string; + status?: string; +}; + +export type ImpactaCertificateCanvasProps = { + holderName?: string; + year?: string | number; +}; + diff --git a/src/app/api/share/route.ts b/src/app/api/share/route.ts index f31c8cd..43c746e 100644 --- a/src/app/api/share/route.ts +++ b/src/app/api/share/route.ts @@ -2,14 +2,18 @@ import { NextResponse } from 'next/server'; const store = new Map(); +function createShortId(): string { + // Compact, URL-safe identifier (~16 chars) for shorter share links. + const part1 = Math.random().toString(36).slice(2, 10); + const part2 = Math.random().toString(36).slice(2, 6); + const raw = (part1 + part2).replace(/[^a-z0-9]/gi, ''); + return raw.slice(0, 16) || Math.random().toString(36).slice(2, 10); +} + export async function POST(req: Request) { try { const data = await req.json(); - const id = ( - globalThis.crypto && 'randomUUID' in globalThis.crypto - ? (globalThis.crypto as unknown as { randomUUID: () => string }).randomUUID() - : Math.random().toString(36).slice(2) - ) as string; + const id = createShortId(); store.set(id, data); return NextResponse.json({ id }); } catch (e) { diff --git a/src/app/baf/page.tsx b/src/app/baf/page.tsx deleted file mode 100644 index a766844..0000000 --- a/src/app/baf/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Certificate from '@/components/modules/credentials/ui/impacta-bootcamp/Certificate'; - -export const metadata = { - title: 'Impacta Bootcamp Certificate', -}; - -export default function BafPage() { - return ; -} diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index 4e81e64..bfe8ecf 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -1,27 +1,17 @@ 'use client'; -import { useSyncExternalStore } from 'react'; +import { forwardRef, useRef, useSyncExternalStore, useCallback, useState } from 'react'; import Image from 'next/image'; -import { Twitter, Linkedin } from 'lucide-react'; +import { Twitter, Linkedin, Download } from 'lucide-react'; +import type { + ImpactaCertificateProps as CertificateProps, + ImpactaCertificateCanvasProps as CertificateCanvasProps, +} from '@/@types/impacta-certificate'; -type CertificateProps = { - holderName?: string; - year?: string | number; - issuer?: string; - subjectDid?: string; - credentialType?: string; - issuedAt?: string; - status?: string; -}; - -type CertificateCanvasProps = { - holderName?: string; - year?: string | number; -}; - -export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvasProps) { - return ( -
+export const CertificateCanvas = forwardRef( + function CertificateCanvas({ holderName, year = 2026 }, ref) { + return ( +
{/* Decorative thin white border line (partial frame) */}
@@ -70,6 +61,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas width={244} height={30} className="w-full h-auto" + unoptimized />
@@ -81,6 +73,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas width={70} height={120} className="w-full h-auto" + unoptimized />
@@ -92,6 +85,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas width={232} height={76} className="w-full h-auto" + unoptimized />
@@ -103,6 +97,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas width={505} height={610} className="w-full h-auto" + unoptimized />
@@ -157,6 +152,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas width={54} height={53} className="w-full h-auto" + unoptimized />
@@ -169,6 +165,7 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas width={218} height={38} className="w-[15vw] h-auto" + unoptimized />
@@ -198,16 +195,89 @@ export function CertificateCanvas({ holderName, year = 2026 }: CertificateCanvas `}
); -} + }, +); export default function Certificate(props: CertificateProps) { const { issuedAt, year, issuer, subjectDid, credentialType, status } = props; + const certRef = useRef(null); const shareUrl = useSyncExternalStore( () => () => {}, () => (typeof window !== 'undefined' ? window.location.href : ''), () => '' ); + const [downloadError, setDownloadError] = useState(null); + const [downloading, setDownloading] = useState(false); + + const handleDownloadImage = useCallback(async () => { + const el = certRef.current; + if (!el || typeof window === 'undefined') return; + setDownloadError(null); + setDownloading(true); + let qr: HTMLImageElement | null = null; + try { + const targetUrl = shareUrl || window.location.href; + + if (targetUrl) { + qr = document.createElement('img'); + qr.src = `https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=${encodeURIComponent( + targetUrl, + )}`; + qr.alt = 'Credential QR'; + qr.style.position = 'absolute'; + qr.style.top = '24px'; + qr.style.right = '24px'; + qr.style.width = '96px'; + qr.style.height = '96px'; + qr.style.backgroundColor = '#ffffff'; + qr.style.padding = '6px'; + qr.style.borderRadius = '8px'; + qr.style.boxShadow = '0 0 0 2px rgba(0,0,0,0.25)'; + qr.style.zIndex = '40'; + el.appendChild(qr); + } + + // Wait for images inside the certificate to be loaded + const imgs = el.querySelectorAll('img'); + await Promise.all( + Array.from(imgs).map( + (img) => + new Promise((resolve) => { + if (img.complete) resolve(); + else { + img.onload = () => resolve(); + img.onerror = () => resolve(); + setTimeout(resolve, 3000); + } + }), + ), + ); + + const htmlToImage = await import('html-to-image'); + const dataUrl = await htmlToImage.toPng(el, { + cacheBust: true, + pixelRatio: 2, + quality: 1, + backgroundColor: '#0000FF', + }); + const a = document.createElement('a'); + a.href = dataUrl; + a.download = 'impacta-bootcamp-certificate.png'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + } catch (err) { + const message = err instanceof Error ? err.message : 'Download failed'; + setDownloadError(message); + } finally { + if (qr && qr.parentNode === el) { + el.removeChild(qr); + } + setDownloading(false); + } + }, [shareUrl]); + const derivedYear = typeof year !== 'undefined' ? year @@ -229,63 +299,82 @@ export default function Certificate(props: CertificateProps) { {/* Certificado a la izquierda */}
- +
- {details.length > 0 && ( -
); diff --git a/yarn.lock b/yarn.lock index 3b1df38..d6ad778 100644 --- a/yarn.lock +++ b/yarn.lock @@ -299,7 +299,7 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@emnapi/core@^1.4.3", "@emnapi/core@^1.6.0": +"@emnapi/core@^1.4.3": version "1.7.1" resolved "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz" integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg== @@ -307,14 +307,14 @@ "@emnapi/wasi-threads" "1.1.0" tslib "^2.4.0" -"@emnapi/runtime@^1.4.3", "@emnapi/runtime@^1.6.0", "@emnapi/runtime@^1.7.0": +"@emnapi/runtime@^1.4.3": version "1.7.1" resolved "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz" integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA== dependencies: tslib "^2.4.0" -"@emnapi/wasi-threads@^1.1.0", "@emnapi/wasi-threads@1.1.0": +"@emnapi/wasi-threads@1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz" integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== @@ -543,143 +543,6 @@ resolved "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz" integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== -"@img/sharp-darwin-arm64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz" - integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== - optionalDependencies: - "@img/sharp-libvips-darwin-arm64" "1.2.4" - -"@img/sharp-darwin-x64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz" - integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== - optionalDependencies: - "@img/sharp-libvips-darwin-x64" "1.2.4" - -"@img/sharp-libvips-darwin-arm64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz" - integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== - -"@img/sharp-libvips-darwin-x64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz" - integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== - -"@img/sharp-libvips-linux-arm@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz" - integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== - -"@img/sharp-libvips-linux-arm64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz" - integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== - -"@img/sharp-libvips-linux-ppc64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz" - integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== - -"@img/sharp-libvips-linux-riscv64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz" - integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== - -"@img/sharp-libvips-linux-s390x@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz" - integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== - -"@img/sharp-libvips-linux-x64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz" - integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== - -"@img/sharp-libvips-linuxmusl-arm64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz" - integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== - -"@img/sharp-libvips-linuxmusl-x64@1.2.4": - version "1.2.4" - resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz" - integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== - -"@img/sharp-linux-arm@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz" - integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== - optionalDependencies: - "@img/sharp-libvips-linux-arm" "1.2.4" - -"@img/sharp-linux-arm64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz" - integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== - optionalDependencies: - "@img/sharp-libvips-linux-arm64" "1.2.4" - -"@img/sharp-linux-ppc64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz" - integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== - optionalDependencies: - "@img/sharp-libvips-linux-ppc64" "1.2.4" - -"@img/sharp-linux-riscv64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz" - integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== - optionalDependencies: - "@img/sharp-libvips-linux-riscv64" "1.2.4" - -"@img/sharp-linux-s390x@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz" - integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== - optionalDependencies: - "@img/sharp-libvips-linux-s390x" "1.2.4" - -"@img/sharp-linux-x64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz" - integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== - optionalDependencies: - "@img/sharp-libvips-linux-x64" "1.2.4" - -"@img/sharp-linuxmusl-arm64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz" - integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== - optionalDependencies: - "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" - -"@img/sharp-linuxmusl-x64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz" - integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== - optionalDependencies: - "@img/sharp-libvips-linuxmusl-x64" "1.2.4" - -"@img/sharp-wasm32@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz" - integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== - dependencies: - "@emnapi/runtime" "^1.7.0" - -"@img/sharp-win32-arm64@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz" - integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== - -"@img/sharp-win32-ia32@0.34.5": - version "0.34.5" - resolved "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz" - integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== - "@img/sharp-win32-x64@0.34.5": version "0.34.5" resolved "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz" @@ -866,45 +729,11 @@ "@motionone/dom" "^10.16.4" tslib "^2.3.1" -"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz" - integrity sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw== - -"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz" - integrity sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw== - -"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz" - integrity sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw== - -"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz" - integrity sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg== - -"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3": - version "3.0.3" - resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz" - integrity sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg== - "@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3": version "3.0.3" resolved "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz" integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== -"@napi-rs/wasm-runtime@^0.2.11", "@napi-rs/wasm-runtime@^1.0.7": - version "0.2.12" - resolved "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz" - integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== - dependencies: - "@emnapi/core" "^1.4.3" - "@emnapi/runtime" "^1.4.3" - "@tybys/wasm-util" "^0.10.0" - "@next/env@16.1.6": version "16.1.6" resolved "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz" @@ -917,41 +746,6 @@ dependencies: fast-glob "3.3.1" -"@next/swc-darwin-arm64@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz" - integrity sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw== - -"@next/swc-darwin-x64@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz" - integrity sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ== - -"@next/swc-linux-arm64-gnu@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz" - integrity sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw== - -"@next/swc-linux-arm64-musl@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz" - integrity sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ== - -"@next/swc-linux-x64-gnu@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz" - integrity sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ== - -"@next/swc-linux-x64-musl@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz" - integrity sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg== - -"@next/swc-win32-arm64-msvc@16.1.6": - version "16.1.6" - resolved "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz" - integrity sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw== - "@next/swc-win32-x64-msvc@16.1.6": version "16.1.6" resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz" @@ -2414,68 +2208,6 @@ source-map-js "^1.2.1" tailwindcss "4.1.17" -"@tailwindcss/oxide-android-arm64@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz" - integrity sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ== - -"@tailwindcss/oxide-darwin-arm64@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz" - integrity sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg== - -"@tailwindcss/oxide-darwin-x64@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz" - integrity sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog== - -"@tailwindcss/oxide-freebsd-x64@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz" - integrity sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g== - -"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz" - integrity sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ== - -"@tailwindcss/oxide-linux-arm64-gnu@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz" - integrity sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ== - -"@tailwindcss/oxide-linux-arm64-musl@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz" - integrity sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg== - -"@tailwindcss/oxide-linux-x64-gnu@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz" - integrity sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ== - -"@tailwindcss/oxide-linux-x64-musl@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz" - integrity sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ== - -"@tailwindcss/oxide-wasm32-wasi@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz" - integrity sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg== - dependencies: - "@emnapi/core" "^1.6.0" - "@emnapi/runtime" "^1.6.0" - "@emnapi/wasi-threads" "^1.1.0" - "@napi-rs/wasm-runtime" "^1.0.7" - "@tybys/wasm-util" "^0.10.1" - tslib "^2.4.0" - -"@tailwindcss/oxide-win32-arm64-msvc@4.1.17": - version "4.1.17" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz" - integrity sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A== - "@tailwindcss/oxide-win32-x64-msvc@4.1.17": version "4.1.17" resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz" @@ -2923,7 +2655,7 @@ "@trezor/utils" "9.5.0" ws "^8.18.0" -"@tybys/wasm-util@^0.10.0", "@tybys/wasm-util@^0.10.1": +"@tybys/wasm-util@^0.10.0": version "0.10.1" resolved "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz" integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== @@ -3099,98 +2831,6 @@ "@typescript-eslint/types" "8.56.1" eslint-visitor-keys "^5.0.0" -"@unrs/resolver-binding-android-arm-eabi@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz" - integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== - -"@unrs/resolver-binding-android-arm64@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz" - integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== - -"@unrs/resolver-binding-darwin-arm64@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz" - integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== - -"@unrs/resolver-binding-darwin-x64@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz" - integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== - -"@unrs/resolver-binding-freebsd-x64@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz" - integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== - -"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz" - integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== - -"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz" - integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== - -"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz" - integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== - -"@unrs/resolver-binding-linux-arm64-musl@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz" - integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== - -"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz" - integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== - -"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz" - integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== - -"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz" - integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== - -"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz" - integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== - -"@unrs/resolver-binding-linux-x64-gnu@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz" - integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== - -"@unrs/resolver-binding-linux-x64-musl@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz" - integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== - -"@unrs/resolver-binding-wasm32-wasi@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz" - integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== - dependencies: - "@napi-rs/wasm-runtime" "^0.2.11" - -"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz" - integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== - -"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz" - integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== - "@unrs/resolver-binding-win32-x64-msvc@1.11.1": version "1.11.1" resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz" @@ -3668,6 +3308,26 @@ balanced-match@^4.0.2: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz" integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== +bare-addon-resolve@^1.3.0: + version "1.10.0" + resolved "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz" + integrity sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA== + dependencies: + bare-module-resolve "^1.10.0" + bare-semver "^1.0.0" + +bare-module-resolve@^1.10.0: + version "1.12.1" + resolved "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz" + integrity sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg== + dependencies: + bare-semver "^1.0.0" + +bare-semver@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.2.tgz" + integrity sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA== + base-x@^3.0.2: version "3.0.11" resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz" @@ -3692,6 +3352,11 @@ base32.js@^0.1.0: resolved "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz" integrity sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ== +base64-arraybuffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -4175,6 +3840,13 @@ crypto-browserify@3.12.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-line-break@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz" + integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w== + dependencies: + utrie "^1.0.2" + csstype@^3.2.2: version "3.2.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz" @@ -5162,6 +4834,19 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +html-to-image@^1.11.13: + version "1.11.13" + resolved "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz" + integrity sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg== + +html2canvas@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz" + integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA== + dependencies: + css-line-break "^2.1.0" + text-segmentation "^1.0.3" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" @@ -5606,106 +5291,6 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lightningcss-android-arm64@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz" - integrity sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A== - -lightningcss-android-arm64@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz" - integrity sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg== - -lightningcss-darwin-arm64@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz" - integrity sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA== - -lightningcss-darwin-arm64@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz" - integrity sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg== - -lightningcss-darwin-x64@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz" - integrity sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ== - -lightningcss-darwin-x64@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz" - integrity sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA== - -lightningcss-freebsd-x64@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz" - integrity sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA== - -lightningcss-freebsd-x64@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz" - integrity sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A== - -lightningcss-linux-arm-gnueabihf@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz" - integrity sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA== - -lightningcss-linux-arm-gnueabihf@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz" - integrity sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g== - -lightningcss-linux-arm64-gnu@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz" - integrity sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A== - -lightningcss-linux-arm64-gnu@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz" - integrity sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg== - -lightningcss-linux-arm64-musl@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz" - integrity sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA== - -lightningcss-linux-arm64-musl@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz" - integrity sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg== - -lightningcss-linux-x64-gnu@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz" - integrity sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w== - -lightningcss-linux-x64-gnu@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz" - integrity sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA== - -lightningcss-linux-x64-musl@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz" - integrity sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA== - -lightningcss-linux-x64-musl@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz" - integrity sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA== - -lightningcss-win32-arm64-msvc@1.30.2: - version "1.30.2" - resolved "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz" - integrity sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ== - -lightningcss-win32-arm64-msvc@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz" - integrity sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w== - lightningcss-win32-x64-msvc@1.30.2: version "1.30.2" resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz" @@ -6684,6 +6269,13 @@ regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: gopd "^1.2.0" set-function-name "^2.0.2" +require-addon@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz" + integrity sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA== + dependencies: + bare-addon-resolve "^1.3.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" @@ -7066,6 +6658,13 @@ socks@^2.8.3: ip-address "^10.0.1" smart-buffer "^4.2.0" +sodium-native@^4.1.1: + version "4.3.3" + resolved "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.3.tgz" + integrity sha512-OnxSlN3uyY8D0EsLHpmm2HOFmKddQVvEMmsakCrXUzSd8kjjbzL413t4ZNF3n0UxSwNgwTyUvkmZHTfuCeiYSw== + dependencies: + require-addon "^1.1.0" + sonic-boom@^2.2.1: version "2.8.0" resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz" @@ -7273,6 +6872,13 @@ tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz" integrity sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg== +text-segmentation@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz" + integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw== + dependencies: + utrie "^1.0.2" + thread-stream@^0.15.1: version "0.15.2" resolved "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz" @@ -7626,6 +7232,13 @@ util@^0.12.5: is-typed-array "^1.1.3" which-typed-array "^1.1.2" +utrie@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz" + integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw== + dependencies: + base64-arraybuffer "^1.0.2" + valtio@1.11.2: version "1.11.2" resolved "https://registry.npmjs.org/valtio/-/valtio-1.11.2.tgz" From 1384f3bc256e1c808e2f70f25e9a0a648be713f6 Mon Sep 17 00:00:00 2001 From: JosueBrenes Date: Mon, 2 Mar 2026 23:37:51 -0600 Subject: [PATCH 22/38] refactor: clean up unused code in Impacta Certificate types and components - Removed an unused line from the ImpactaCertificateCanvasProps type definition. - Streamlined the Certificate component by eliminating redundant comments and ensuring consistent formatting for improved readability. --- src/@types/impacta-certificate.ts | 1 - .../ui/impacta-bootcamp/Certificate.tsx | 476 +++++++++--------- 2 files changed, 243 insertions(+), 234 deletions(-) diff --git a/src/@types/impacta-certificate.ts b/src/@types/impacta-certificate.ts index 860f12c..dd521ce 100644 --- a/src/@types/impacta-certificate.ts +++ b/src/@types/impacta-certificate.ts @@ -12,4 +12,3 @@ export type ImpactaCertificateCanvasProps = { holderName?: string; year?: string | number; }; - diff --git a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx index bfe8ecf..057bfa9 100644 --- a/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx +++ b/src/components/modules/credentials/ui/impacta-bootcamp/Certificate.tsx @@ -12,190 +12,206 @@ export const CertificateCanvas = forwardRef -
- {/* Decorative thin white border line (partial frame) */} - - {/* Top line from logo area to right edge */} - - {/* Right vertical line going down */} - - {/* Left vertical line from top */} - - {/* Top horizontal short line at very top */} - - {/* Right short line at top to connect to seal */} - - - - {/* Top-left: Impacta Logo */} -
- Impacta Bootcamp logo -
+
+ {/* Decorative thin white border line (partial frame) */} + + {/* Top line from logo area to right edge */} + + {/* Right vertical line going down */} + + {/* Left vertical line from top */} + + {/* Top horizontal short line at very top */} + + {/* Right short line at top to connect to seal */} + + - {/* Top: Row of Asteriscs */} -
- Asteriscs decorativos -
+ {/* Top-left: Impacta Logo */} +
+ Impacta Bootcamp logo +
- {/* Top-right: Corner Seal (globe + asterisk) in white box */} -
- Sello de esquina -
+ {/* Top: Row of Asteriscs */} +
+ Asteriscs decorativos +
- {/* Left side: Circles / Coil */} -
- Circulos decorativos -
+ {/* Top-right: Corner Seal (globe + asterisk) in white box */} +
+ Sello de esquina +
- {/* Right side: Latam Map Outline with dots */} -
- Mapa de Latinoamerica -
+ {/* Left side: Circles / Coil */} +
+ Circulos decorativos +
- {/* Main Title: CERTIFICADO DE PARTICIPACION */} -
-
-

- {'Certificado de Participaci\u00F3n'} -

+ {/* Right side: Latam Map Outline with dots */} +
+ Mapa de Latinoamerica
-
- {/* Subtitle text */} -
-

- Se otorga el presente reconocimiento a: -

-
+ {/* Main Title: CERTIFICADO DE PARTICIPACION */} +
+
+

+ {'Certificado de Participaci\u00F3n'} +

+
+
- {/* Name line */} -
-
- {holderName && ( - - {holderName} - - )} + {/* Subtitle text */} +
+

+ Se otorga el presente reconocimiento a: +

-
- {/* Description text */} -
-

- Por haber completado satisfactoriamente los - requisitos {'acad\u00E9micos'} y {'pr\u00E1cticos'} del programa intensivo{' '} - IMPACTA BOOTCAMP. -

-
+ {/* Name line */} +
+
+ {holderName && ( + + {holderName} + + )} +
+
- {/* Year */} -
- - {String(year)} - -
+ {/* Description text */} +
+

+ Por haber completado satisfactoriamente los + requisitos {'acad\u00E9micos'} y {'pr\u00E1cticos'} del programa intensivo{' '} + IMPACTA BOOTCAMP. +

+
- {/* Bottom-right: Corner Dots */} -
- Puntos decorativos -
+ {/* Year */} +
+ + {String(year)} + +
- {/* Bottom-left: Sponsor Logos (Stellar x BAF x Trustless) in white box */} -
-
+ {/* Bottom-right: Corner Dots */} +
Stellar, BAF y Trustless logos
-
-
- -
- ); - }, + `} +
+ ); + } ); export default function Certificate(props: CertificateProps) { @@ -222,7 +238,7 @@ export default function Certificate(props: CertificateProps) { if (targetUrl) { qr = document.createElement('img'); qr.src = `https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=${encodeURIComponent( - targetUrl, + targetUrl )}`; qr.alt = 'Credential QR'; qr.style.position = 'absolute'; @@ -250,8 +266,8 @@ export default function Certificate(props: CertificateProps) { img.onerror = () => resolve(); setTimeout(resolve, 3000); } - }), - ), + }) + ) ); const htmlToImage = await import('html-to-image'); @@ -299,82 +315,76 @@ export default function Certificate(props: CertificateProps) { {/* Certificado a la izquierda */}
- +
- {details.length > 0 && ( -
-
-
- Credential Details -
-
- {details.map((item) => ( -
-
- {item.label} -
-
{item.value}
-
- ))} -
+ {details.length > 0 && ( +
+
+
+ Credential Details
- -
- - - Share X - - - - Share LinkedIn - +
+ {details.map((item) => ( +
+
+ {item.label} +
+
{item.value}
+
+ ))}
+
- {downloadError && ( -

{downloadError}

- )} - + + Share X + + + + Share LinkedIn +
- )} + + {downloadError &&

{downloadError}

} + +
+ )}
); From 811a7616746305ea80303aa278f4782e101908c3 Mon Sep 17 00:00:00 2001 From: Daniel Coto Jimenez Date: Tue, 3 Mar 2026 00:26:22 -0600 Subject: [PATCH 23/38] feat: Install vercel-react-best-practices IA skills --- .../vercel-react-best-practices/AGENTS.md | 2975 +++++++++++++++++ .../vercel-react-best-practices/README.md | 123 + .../vercel-react-best-practices/SKILL.md | 137 + .../rules/advanced-event-handler-refs.md | 55 + .../rules/advanced-init-once.md | 42 + .../rules/advanced-use-latest.md | 39 + .../rules/async-api-routes.md | 38 + .../rules/async-defer-await.md | 80 + .../rules/async-dependencies.md | 51 + .../rules/async-parallel.md | 28 + .../rules/async-suspense-boundaries.md | 99 + .../rules/bundle-barrel-imports.md | 59 + .../rules/bundle-conditional.md | 31 + .../rules/bundle-defer-third-party.md | 49 + .../rules/bundle-dynamic-imports.md | 35 + .../rules/bundle-preload.md | 50 + .../rules/client-event-listeners.md | 74 + .../rules/client-localstorage-schema.md | 71 + .../rules/client-passive-event-listeners.md | 48 + .../rules/client-swr-dedup.md | 56 + .../rules/js-batch-dom-css.md | 107 + .../rules/js-cache-function-results.md | 80 + .../rules/js-cache-property-access.md | 28 + .../rules/js-cache-storage.md | 70 + .../rules/js-combine-iterations.md | 32 + .../rules/js-early-exit.md | 50 + .../rules/js-hoist-regexp.md | 45 + .../rules/js-index-maps.md | 37 + .../rules/js-length-check-first.md | 49 + .../rules/js-min-max-loop.md | 82 + .../rules/js-set-map-lookups.md | 24 + .../rules/js-tosorted-immutable.md | 57 + .../rules/rendering-activity.md | 26 + .../rules/rendering-animate-svg-wrapper.md | 47 + .../rules/rendering-conditional-render.md | 40 + .../rules/rendering-content-visibility.md | 38 + .../rules/rendering-hoist-jsx.md | 46 + .../rules/rendering-hydration-no-flicker.md | 82 + .../rendering-hydration-suppress-warning.md | 30 + .../rules/rendering-svg-precision.md | 28 + .../rules/rendering-usetransition-loading.md | 75 + .../rules/rerender-defer-reads.md | 39 + .../rules/rerender-dependencies.md | 45 + .../rules/rerender-derived-state-no-effect.md | 40 + .../rules/rerender-derived-state.md | 29 + .../rules/rerender-functional-setstate.md | 74 + .../rules/rerender-lazy-state-init.md | 58 + .../rules/rerender-memo-with-default-value.md | 38 + .../rules/rerender-memo.md | 44 + .../rules/rerender-move-effect-to-event.md | 45 + .../rerender-simple-expression-in-memo.md | 35 + .../rules/rerender-transitions.md | 40 + .../rerender-use-ref-transient-values.md | 73 + .../rules/server-after-nonblocking.md | 73 + .../rules/server-auth-actions.md | 96 + .../rules/server-cache-lru.md | 41 + .../rules/server-cache-react.md | 76 + .../rules/server-dedup-props.md | 65 + .../rules/server-hoist-static-io.md | 142 + .../rules/server-parallel-fetching.md | 83 + .../rules/server-serialization.md | 38 + .../vercel-react-best-practices/AGENTS.md | 2975 +++++++++++++++++ .../vercel-react-best-practices/README.md | 123 + .../vercel-react-best-practices/SKILL.md | 137 + .../rules/advanced-event-handler-refs.md | 55 + .../rules/advanced-init-once.md | 42 + .../rules/advanced-use-latest.md | 39 + .../rules/async-api-routes.md | 38 + .../rules/async-defer-await.md | 80 + .../rules/async-dependencies.md | 51 + .../rules/async-parallel.md | 28 + .../rules/async-suspense-boundaries.md | 99 + .../rules/bundle-barrel-imports.md | 59 + .../rules/bundle-conditional.md | 31 + .../rules/bundle-defer-third-party.md | 49 + .../rules/bundle-dynamic-imports.md | 35 + .../rules/bundle-preload.md | 50 + .../rules/client-event-listeners.md | 74 + .../rules/client-localstorage-schema.md | 71 + .../rules/client-passive-event-listeners.md | 48 + .../rules/client-swr-dedup.md | 56 + .../rules/js-batch-dom-css.md | 107 + .../rules/js-cache-function-results.md | 80 + .../rules/js-cache-property-access.md | 28 + .../rules/js-cache-storage.md | 70 + .../rules/js-combine-iterations.md | 32 + .../rules/js-early-exit.md | 50 + .../rules/js-hoist-regexp.md | 45 + .../rules/js-index-maps.md | 37 + .../rules/js-length-check-first.md | 49 + .../rules/js-min-max-loop.md | 82 + .../rules/js-set-map-lookups.md | 24 + .../rules/js-tosorted-immutable.md | 57 + .../rules/rendering-activity.md | 26 + .../rules/rendering-animate-svg-wrapper.md | 47 + .../rules/rendering-conditional-render.md | 40 + .../rules/rendering-content-visibility.md | 38 + .../rules/rendering-hoist-jsx.md | 46 + .../rules/rendering-hydration-no-flicker.md | 82 + .../rendering-hydration-suppress-warning.md | 30 + .../rules/rendering-svg-precision.md | 28 + .../rules/rendering-usetransition-loading.md | 75 + .../rules/rerender-defer-reads.md | 39 + .../rules/rerender-dependencies.md | 45 + .../rules/rerender-derived-state-no-effect.md | 40 + .../rules/rerender-derived-state.md | 29 + .../rules/rerender-functional-setstate.md | 74 + .../rules/rerender-lazy-state-init.md | 58 + .../rules/rerender-memo-with-default-value.md | 38 + .../rules/rerender-memo.md | 44 + .../rules/rerender-move-effect-to-event.md | 45 + .../rerender-simple-expression-in-memo.md | 35 + .../rules/rerender-transitions.md | 40 + .../rerender-use-ref-transient-values.md | 73 + .../rules/server-after-nonblocking.md | 73 + .../rules/server-auth-actions.md | 96 + .../rules/server-cache-lru.md | 41 + .../rules/server-cache-react.md | 76 + .../rules/server-dedup-props.md | 65 + .../rules/server-hoist-static-io.md | 142 + .../rules/server-parallel-fetching.md | 83 + .../rules/server-serialization.md | 38 + skills-lock.json | 10 + 123 files changed, 12784 insertions(+) create mode 100644 .agents/skills/vercel-react-best-practices/AGENTS.md create mode 100644 .agents/skills/vercel-react-best-practices/README.md create mode 100644 .agents/skills/vercel-react-best-practices/SKILL.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/advanced-init-once.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/async-api-routes.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/async-defer-await.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/async-dependencies.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/async-parallel.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/bundle-conditional.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/bundle-preload.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/client-event-listeners.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-cache-storage.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-early-exit.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-index-maps.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-length-check-first.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-activity.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-memo.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-transitions.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-auth-actions.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-cache-lru.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-cache-react.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-dedup-props.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md create mode 100644 .agents/skills/vercel-react-best-practices/rules/server-serialization.md create mode 100644 .claude/skills/vercel-react-best-practices/AGENTS.md create mode 100644 .claude/skills/vercel-react-best-practices/README.md create mode 100644 .claude/skills/vercel-react-best-practices/SKILL.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/advanced-init-once.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/advanced-use-latest.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/async-api-routes.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/async-defer-await.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/async-dependencies.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/async-parallel.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/bundle-conditional.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/bundle-preload.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/client-event-listeners.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/client-localstorage-schema.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/client-swr-dedup.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-batch-dom-css.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-cache-function-results.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-cache-property-access.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-cache-storage.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-combine-iterations.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-early-exit.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-hoist-regexp.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-index-maps.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-length-check-first.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-min-max-loop.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-set-map-lookups.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-activity.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-conditional-render.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-content-visibility.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-svg-precision.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-defer-reads.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-dependencies.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-derived-state.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-memo.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-transitions.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-after-nonblocking.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-auth-actions.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-cache-lru.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-cache-react.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-dedup-props.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-hoist-static-io.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-parallel-fetching.md create mode 100644 .claude/skills/vercel-react-best-practices/rules/server-serialization.md create mode 100644 skills-lock.json diff --git a/.agents/skills/vercel-react-best-practices/AGENTS.md b/.agents/skills/vercel-react-best-practices/AGENTS.md new file mode 100644 index 0000000..94c3c84 --- /dev/null +++ b/.agents/skills/vercel-react-best-practices/AGENTS.md @@ -0,0 +1,2975 @@ +# React Best Practices + +**Version 1.0.0** +Vercel Engineering +January 2026 + +> **Note:** +> This document is mainly for agents and LLMs to follow when maintaining, +> generating, or refactoring React and Next.js codebases. Humans +> may also find it useful, but guidance here is optimized for automation +> and consistency by AI-assisted workflows. + +--- + +## Abstract + +Comprehensive performance optimization guide for React and Next.js applications, designed for AI agents and LLMs. Contains 40+ rules across 8 categories, prioritized by impact from critical (eliminating waterfalls, reducing bundle size) to incremental (advanced patterns). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation. + +--- + +## Table of Contents + +1. [Eliminating Waterfalls](#1-eliminating-waterfalls) — **CRITICAL** + - 1.1 [Defer Await Until Needed](#11-defer-await-until-needed) + - 1.2 [Dependency-Based Parallelization](#12-dependency-based-parallelization) + - 1.3 [Prevent Waterfall Chains in API Routes](#13-prevent-waterfall-chains-in-api-routes) + - 1.4 [Promise.all() for Independent Operations](#14-promiseall-for-independent-operations) + - 1.5 [Strategic Suspense Boundaries](#15-strategic-suspense-boundaries) +2. [Bundle Size Optimization](#2-bundle-size-optimization) — **CRITICAL** + - 2.1 [Avoid Barrel File Imports](#21-avoid-barrel-file-imports) + - 2.2 [Conditional Module Loading](#22-conditional-module-loading) + - 2.3 [Defer Non-Critical Third-Party Libraries](#23-defer-non-critical-third-party-libraries) + - 2.4 [Dynamic Imports for Heavy Components](#24-dynamic-imports-for-heavy-components) + - 2.5 [Preload Based on User Intent](#25-preload-based-on-user-intent) +3. [Server-Side Performance](#3-server-side-performance) — **HIGH** + - 3.1 [Authenticate Server Actions Like API Routes](#31-authenticate-server-actions-like-api-routes) + - 3.2 [Avoid Duplicate Serialization in RSC Props](#32-avoid-duplicate-serialization-in-rsc-props) + - 3.3 [Cross-Request LRU Caching](#33-cross-request-lru-caching) + - 3.4 [Hoist Static I/O to Module Level](#34-hoist-static-io-to-module-level) + - 3.5 [Minimize Serialization at RSC Boundaries](#35-minimize-serialization-at-rsc-boundaries) + - 3.6 [Parallel Data Fetching with Component Composition](#36-parallel-data-fetching-with-component-composition) + - 3.7 [Per-Request Deduplication with React.cache()](#37-per-request-deduplication-with-reactcache) + - 3.8 [Use after() for Non-Blocking Operations](#38-use-after-for-non-blocking-operations) +4. [Client-Side Data Fetching](#4-client-side-data-fetching) — **MEDIUM-HIGH** + - 4.1 [Deduplicate Global Event Listeners](#41-deduplicate-global-event-listeners) + - 4.2 [Use Passive Event Listeners for Scrolling Performance](#42-use-passive-event-listeners-for-scrolling-performance) + - 4.3 [Use SWR for Automatic Deduplication](#43-use-swr-for-automatic-deduplication) + - 4.4 [Version and Minimize localStorage Data](#44-version-and-minimize-localstorage-data) +5. [Re-render Optimization](#5-re-render-optimization) — **MEDIUM** + - 5.1 [Calculate Derived State During Rendering](#51-calculate-derived-state-during-rendering) + - 5.2 [Defer State Reads to Usage Point](#52-defer-state-reads-to-usage-point) + - 5.3 [Do not wrap a simple expression with a primitive result type in useMemo](#53-do-not-wrap-a-simple-expression-with-a-primitive-result-type-in-usememo) + - 5.4 [Extract Default Non-primitive Parameter Value from Memoized Component to Constant](#54-extract-default-non-primitive-parameter-value-from-memoized-component-to-constant) + - 5.5 [Extract to Memoized Components](#55-extract-to-memoized-components) + - 5.6 [Narrow Effect Dependencies](#56-narrow-effect-dependencies) + - 5.7 [Put Interaction Logic in Event Handlers](#57-put-interaction-logic-in-event-handlers) + - 5.8 [Subscribe to Derived State](#58-subscribe-to-derived-state) + - 5.9 [Use Functional setState Updates](#59-use-functional-setstate-updates) + - 5.10 [Use Lazy State Initialization](#510-use-lazy-state-initialization) + - 5.11 [Use Transitions for Non-Urgent Updates](#511-use-transitions-for-non-urgent-updates) + - 5.12 [Use useRef for Transient Values](#512-use-useref-for-transient-values) +6. [Rendering Performance](#6-rendering-performance) — **MEDIUM** + - 6.1 [Animate SVG Wrapper Instead of SVG Element](#61-animate-svg-wrapper-instead-of-svg-element) + - 6.2 [CSS content-visibility for Long Lists](#62-css-content-visibility-for-long-lists) + - 6.3 [Hoist Static JSX Elements](#63-hoist-static-jsx-elements) + - 6.4 [Optimize SVG Precision](#64-optimize-svg-precision) + - 6.5 [Prevent Hydration Mismatch Without Flickering](#65-prevent-hydration-mismatch-without-flickering) + - 6.6 [Suppress Expected Hydration Mismatches](#66-suppress-expected-hydration-mismatches) + - 6.7 [Use Activity Component for Show/Hide](#67-use-activity-component-for-showhide) + - 6.8 [Use Explicit Conditional Rendering](#68-use-explicit-conditional-rendering) + - 6.9 [Use useTransition Over Manual Loading States](#69-use-usetransition-over-manual-loading-states) +7. [JavaScript Performance](#7-javascript-performance) — **LOW-MEDIUM** + - 7.1 [Avoid Layout Thrashing](#71-avoid-layout-thrashing) + - 7.2 [Build Index Maps for Repeated Lookups](#72-build-index-maps-for-repeated-lookups) + - 7.3 [Cache Property Access in Loops](#73-cache-property-access-in-loops) + - 7.4 [Cache Repeated Function Calls](#74-cache-repeated-function-calls) + - 7.5 [Cache Storage API Calls](#75-cache-storage-api-calls) + - 7.6 [Combine Multiple Array Iterations](#76-combine-multiple-array-iterations) + - 7.7 [Early Length Check for Array Comparisons](#77-early-length-check-for-array-comparisons) + - 7.8 [Early Return from Functions](#78-early-return-from-functions) + - 7.9 [Hoist RegExp Creation](#79-hoist-regexp-creation) + - 7.10 [Use Loop for Min/Max Instead of Sort](#710-use-loop-for-minmax-instead-of-sort) + - 7.11 [Use Set/Map for O(1) Lookups](#711-use-setmap-for-o1-lookups) + - 7.12 [Use toSorted() Instead of sort() for Immutability](#712-use-tosorted-instead-of-sort-for-immutability) +8. [Advanced Patterns](#8-advanced-patterns) — **LOW** + - 8.1 [Initialize App Once, Not Per Mount](#81-initialize-app-once-not-per-mount) + - 8.2 [Store Event Handlers in Refs](#82-store-event-handlers-in-refs) + - 8.3 [useEffectEvent for Stable Callback Refs](#83-useeffectevent-for-stable-callback-refs) + +--- + +## 1. Eliminating Waterfalls + +**Impact: CRITICAL** + +Waterfalls are the #1 performance killer. Each sequential await adds full network latency. Eliminating them yields the largest gains. + +### 1.1 Defer Await Until Needed + +**Impact: HIGH (avoids blocking unused code paths)** + +Move `await` operations into the branches where they're actually used to avoid blocking code paths that don't need them. + +**Incorrect: blocks both branches** + +```typescript +async function handleRequest(userId: string, skipProcessing: boolean) { + const userData = await fetchUserData(userId) + + if (skipProcessing) { + // Returns immediately but still waited for userData + return { skipped: true } + } + + // Only this branch uses userData + return processUserData(userData) +} +``` + +**Correct: only blocks when needed** + +```typescript +async function handleRequest(userId: string, skipProcessing: boolean) { + if (skipProcessing) { + // Returns immediately without waiting + return { skipped: true } + } + + // Fetch only when needed + const userData = await fetchUserData(userId) + return processUserData(userData) +} +``` + +**Another example: early return optimization** + +```typescript +// Incorrect: always fetches permissions +async function updateResource(resourceId: string, userId: string) { + const permissions = await fetchPermissions(userId) + const resource = await getResource(resourceId) + + if (!resource) { + return { error: 'Not found' } + } + + if (!permissions.canEdit) { + return { error: 'Forbidden' } + } + + return await updateResourceData(resource, permissions) +} + +// Correct: fetches only when needed +async function updateResource(resourceId: string, userId: string) { + const resource = await getResource(resourceId) + + if (!resource) { + return { error: 'Not found' } + } + + const permissions = await fetchPermissions(userId) + + if (!permissions.canEdit) { + return { error: 'Forbidden' } + } + + return await updateResourceData(resource, permissions) +} +``` + +This optimization is especially valuable when the skipped branch is frequently taken, or when the deferred operation is expensive. + +### 1.2 Dependency-Based Parallelization + +**Impact: CRITICAL (2-10× improvement)** + +For operations with partial dependencies, use `better-all` to maximize parallelism. It automatically starts each task at the earliest possible moment. + +**Incorrect: profile waits for config unnecessarily** + +```typescript +const [user, config] = await Promise.all([ + fetchUser(), + fetchConfig() +]) +const profile = await fetchProfile(user.id) +``` + +**Correct: config and profile run in parallel** + +```typescript +import { all } from 'better-all' + +const { user, config, profile } = await all({ + async user() { return fetchUser() }, + async config() { return fetchConfig() }, + async profile() { + return fetchProfile((await this.$.user).id) + } +}) +``` + +**Alternative without extra dependencies:** + +```typescript +const userPromise = fetchUser() +const profilePromise = userPromise.then(user => fetchProfile(user.id)) + +const [user, config, profile] = await Promise.all([ + userPromise, + fetchConfig(), + profilePromise +]) +``` + +We can also create all the promises first, and do `Promise.all()` at the end. + +Reference: [https://github.com/shuding/better-all](https://github.com/shuding/better-all) + +### 1.3 Prevent Waterfall Chains in API Routes + +**Impact: CRITICAL (2-10× improvement)** + +In API routes and Server Actions, start independent operations immediately, even if you don't await them yet. + +**Incorrect: config waits for auth, data waits for both** + +```typescript +export async function GET(request: Request) { + const session = await auth() + const config = await fetchConfig() + const data = await fetchData(session.user.id) + return Response.json({ data, config }) +} +``` + +**Correct: auth and config start immediately** + +```typescript +export async function GET(request: Request) { + const sessionPromise = auth() + const configPromise = fetchConfig() + const session = await sessionPromise + const [config, data] = await Promise.all([ + configPromise, + fetchData(session.user.id) + ]) + return Response.json({ data, config }) +} +``` + +For operations with more complex dependency chains, use `better-all` to automatically maximize parallelism (see Dependency-Based Parallelization). + +### 1.4 Promise.all() for Independent Operations + +**Impact: CRITICAL (2-10× improvement)** + +When async operations have no interdependencies, execute them concurrently using `Promise.all()`. + +**Incorrect: sequential execution, 3 round trips** + +```typescript +const user = await fetchUser() +const posts = await fetchPosts() +const comments = await fetchComments() +``` + +**Correct: parallel execution, 1 round trip** + +```typescript +const [user, posts, comments] = await Promise.all([ + fetchUser(), + fetchPosts(), + fetchComments() +]) +``` + +### 1.5 Strategic Suspense Boundaries + +**Impact: HIGH (faster initial paint)** + +Instead of awaiting data in async components before returning JSX, use Suspense boundaries to show the wrapper UI faster while data loads. + +**Incorrect: wrapper blocked by data fetching** + +```tsx +async function Page() { + const data = await fetchData() // Blocks entire page + + return ( +
+
Sidebar
+
Header
+
+ +
+
Footer
+
+ ) +} +``` + +The entire layout waits for data even though only the middle section needs it. + +**Correct: wrapper shows immediately, data streams in** + +```tsx +function Page() { + return ( +
+
Sidebar
+
Header
+
+ }> + + +
+
Footer
+
+ ) +} + +async function DataDisplay() { + const data = await fetchData() // Only blocks this component + return
{data.content}
+} +``` + +Sidebar, Header, and Footer render immediately. Only DataDisplay waits for data. + +**Alternative: share promise across components** + +```tsx +function Page() { + // Start fetch immediately, but don't await + const dataPromise = fetchData() + + return ( +
+
Sidebar
+
Header
+ }> + + + +
Footer
+
+ ) +} + +function DataDisplay({ dataPromise }: { dataPromise: Promise }) { + const data = use(dataPromise) // Unwraps the promise + return
{data.content}
+} + +function DataSummary({ dataPromise }: { dataPromise: Promise }) { + const data = use(dataPromise) // Reuses the same promise + return
{data.summary}
+} +``` + +Both components share the same promise, so only one fetch occurs. Layout renders immediately while both components wait together. + +**When NOT to use this pattern:** + +- Critical data needed for layout decisions (affects positioning) + +- SEO-critical content above the fold + +- Small, fast queries where suspense overhead isn't worth it + +- When you want to avoid layout shift (loading → content jump) + +**Trade-off:** Faster initial paint vs potential layout shift. Choose based on your UX priorities. + +--- + +## 2. Bundle Size Optimization + +**Impact: CRITICAL** + +Reducing initial bundle size improves Time to Interactive and Largest Contentful Paint. + +### 2.1 Avoid Barrel File Imports + +**Impact: CRITICAL (200-800ms import cost, slow builds)** + +Import directly from source files instead of barrel files to avoid loading thousands of unused modules. **Barrel files** are entry points that re-export multiple modules (e.g., `index.js` that does `export * from './module'`). + +Popular icon and component libraries can have **up to 10,000 re-exports** in their entry file. For many React packages, **it takes 200-800ms just to import them**, affecting both development speed and production cold starts. + +**Why tree-shaking doesn't help:** When a library is marked as external (not bundled), the bundler can't optimize it. If you bundle it to enable tree-shaking, builds become substantially slower analyzing the entire module graph. + +**Incorrect: imports entire library** + +```tsx +import { Check, X, Menu } from 'lucide-react' +// Loads 1,583 modules, takes ~2.8s extra in dev +// Runtime cost: 200-800ms on every cold start + +import { Button, TextField } from '@mui/material' +// Loads 2,225 modules, takes ~4.2s extra in dev +``` + +**Correct: imports only what you need** + +```tsx +import Check from 'lucide-react/dist/esm/icons/check' +import X from 'lucide-react/dist/esm/icons/x' +import Menu from 'lucide-react/dist/esm/icons/menu' +// Loads only 3 modules (~2KB vs ~1MB) + +import Button from '@mui/material/Button' +import TextField from '@mui/material/TextField' +// Loads only what you use +``` + +**Alternative: Next.js 13.5+** + +```js +// next.config.js - use optimizePackageImports +module.exports = { + experimental: { + optimizePackageImports: ['lucide-react', '@mui/material'] + } +} + +// Then you can keep the ergonomic barrel imports: +import { Check, X, Menu } from 'lucide-react' +// Automatically transformed to direct imports at build time +``` + +Direct imports provide 15-70% faster dev boot, 28% faster builds, 40% faster cold starts, and significantly faster HMR. + +Libraries commonly affected: `lucide-react`, `@mui/material`, `@mui/icons-material`, `@tabler/icons-react`, `react-icons`, `@headlessui/react`, `@radix-ui/react-*`, `lodash`, `ramda`, `date-fns`, `rxjs`, `react-use`. + +Reference: [https://vercel.com/blog/how-we-optimized-package-imports-in-next-js](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js) + +### 2.2 Conditional Module Loading + +**Impact: HIGH (loads large data only when needed)** + +Load large data or modules only when a feature is activated. + +**Example: lazy-load animation frames** + +```tsx +function AnimationPlayer({ enabled, setEnabled }: { enabled: boolean; setEnabled: React.Dispatch> }) { + const [frames, setFrames] = useState(null) + + useEffect(() => { + if (enabled && !frames && typeof window !== 'undefined') { + import('./animation-frames.js') + .then(mod => setFrames(mod.frames)) + .catch(() => setEnabled(false)) + } + }, [enabled, frames, setEnabled]) + + if (!frames) return + return +} +``` + +The `typeof window !== 'undefined'` check prevents bundling this module for SSR, optimizing server bundle size and build speed. + +### 2.3 Defer Non-Critical Third-Party Libraries + +**Impact: MEDIUM (loads after hydration)** + +Analytics, logging, and error tracking don't block user interaction. Load them after hydration. + +**Incorrect: blocks initial bundle** + +```tsx +import { Analytics } from '@vercel/analytics/react' + +export default function RootLayout({ children }) { + return ( + + + {children} + + + + ) +} +``` + +**Correct: loads after hydration** + +```tsx +import dynamic from 'next/dynamic' + +const Analytics = dynamic( + () => import('@vercel/analytics/react').then(m => m.Analytics), + { ssr: false } +) + +export default function RootLayout({ children }) { + return ( + + + {children} + + + + ) +} +``` + +### 2.4 Dynamic Imports for Heavy Components + +**Impact: CRITICAL (directly affects TTI and LCP)** + +Use `next/dynamic` to lazy-load large components not needed on initial render. + +**Incorrect: Monaco bundles with main chunk ~300KB** + +```tsx +import { MonacoEditor } from './monaco-editor' + +function CodePanel({ code }: { code: string }) { + return +} +``` + +**Correct: Monaco loads on demand** + +```tsx +import dynamic from 'next/dynamic' + +const MonacoEditor = dynamic( + () => import('./monaco-editor').then(m => m.MonacoEditor), + { ssr: false } +) + +function CodePanel({ code }: { code: string }) { + return +} +``` + +### 2.5 Preload Based on User Intent + +**Impact: MEDIUM (reduces perceived latency)** + +Preload heavy bundles before they're needed to reduce perceived latency. + +**Example: preload on hover/focus** + +```tsx +function EditorButton({ onClick }: { onClick: () => void }) { + const preload = () => { + if (typeof window !== 'undefined') { + void import('./monaco-editor') + } + } + + return ( + + ) +} +``` + +**Example: preload when feature flag is enabled** + +```tsx +function FlagsProvider({ children, flags }: Props) { + useEffect(() => { + if (flags.editorEnabled && typeof window !== 'undefined') { + void import('./monaco-editor').then(mod => mod.init()) + } + }, [flags.editorEnabled]) + + return + {children} + +} +``` + +The `typeof window !== 'undefined'` check prevents bundling preloaded modules for SSR, optimizing server bundle size and build speed. + +--- + +## 3. Server-Side Performance + +**Impact: HIGH** + +Optimizing server-side rendering and data fetching eliminates server-side waterfalls and reduces response times. + +### 3.1 Authenticate Server Actions Like API Routes + +**Impact: CRITICAL (prevents unauthorized access to server mutations)** + +Server Actions (functions with `"use server"`) are exposed as public endpoints, just like API routes. Always verify authentication and authorization **inside** each Server Action—do not rely solely on middleware, layout guards, or page-level checks, as Server Actions can be invoked directly. + +Next.js documentation explicitly states: "Treat Server Actions with the same security considerations as public-facing API endpoints, and verify if the user is allowed to perform a mutation." + +**Incorrect: no authentication check** + +```typescript +'use server' + +export async function deleteUser(userId: string) { + // Anyone can call this! No auth check + await db.user.delete({ where: { id: userId } }) + return { success: true } +} +``` + +**Correct: authentication inside the action** + +```typescript +'use server' + +import { verifySession } from '@/lib/auth' +import { unauthorized } from '@/lib/errors' + +export async function deleteUser(userId: string) { + // Always check auth inside the action + const session = await verifySession() + + if (!session) { + throw unauthorized('Must be logged in') + } + + // Check authorization too + if (session.user.role !== 'admin' && session.user.id !== userId) { + throw unauthorized('Cannot delete other users') + } + + await db.user.delete({ where: { id: userId } }) + return { success: true } +} +``` + +**With input validation:** + +```typescript +'use server' + +import { verifySession } from '@/lib/auth' +import { z } from 'zod' + +const updateProfileSchema = z.object({ + userId: z.string().uuid(), + name: z.string().min(1).max(100), + email: z.string().email() +}) + +export async function updateProfile(data: unknown) { + // Validate input first + const validated = updateProfileSchema.parse(data) + + // Then authenticate + const session = await verifySession() + if (!session) { + throw new Error('Unauthorized') + } + + // Then authorize + if (session.user.id !== validated.userId) { + throw new Error('Can only update own profile') + } + + // Finally perform the mutation + await db.user.update({ + where: { id: validated.userId }, + data: { + name: validated.name, + email: validated.email + } + }) + + return { success: true } +} +``` + +Reference: [https://nextjs.org/docs/app/guides/authentication](https://nextjs.org/docs/app/guides/authentication) + +### 3.2 Avoid Duplicate Serialization in RSC Props + +**Impact: LOW (reduces network payload by avoiding duplicate serialization)** + +RSC→client serialization deduplicates by object reference, not value. Same reference = serialized once; new reference = serialized again. Do transformations (`.toSorted()`, `.filter()`, `.map()`) in client, not server. + +**Incorrect: duplicates array** + +```tsx +// RSC: sends 6 strings (2 arrays × 3 items) + +``` + +**Correct: sends 3 strings** + +```tsx +// RSC: send once + + +// Client: transform there +'use client' +const sorted = useMemo(() => [...usernames].sort(), [usernames]) +``` + +**Nested deduplication behavior:** + +```tsx +// string[] - duplicates everything +usernames={['a','b']} sorted={usernames.toSorted()} // sends 4 strings + +// object[] - duplicates array structure only +users={[{id:1},{id:2}]} sorted={users.toSorted()} // sends 2 arrays + 2 unique objects (not 4) +``` + +Deduplication works recursively. Impact varies by data type: + +- `string[]`, `number[]`, `boolean[]`: **HIGH impact** - array + all primitives fully duplicated + +- `object[]`: **LOW impact** - array duplicated, but nested objects deduplicated by reference + +**Operations breaking deduplication: create new references** + +- Arrays: `.toSorted()`, `.filter()`, `.map()`, `.slice()`, `[...arr]` + +- Objects: `{...obj}`, `Object.assign()`, `structuredClone()`, `JSON.parse(JSON.stringify())` + +**More examples:** + +```tsx +// ❌ Bad + u.active)} /> + + +// ✅ Good + + +// Do filtering/destructuring in client +``` + +**Exception:** Pass derived data when transformation is expensive or client doesn't need original. + +### 3.3 Cross-Request LRU Caching + +**Impact: HIGH (caches across requests)** + +`React.cache()` only works within one request. For data shared across sequential requests (user clicks button A then button B), use an LRU cache. + +**Implementation:** + +```typescript +import { LRUCache } from 'lru-cache' + +const cache = new LRUCache({ + max: 1000, + ttl: 5 * 60 * 1000 // 5 minutes +}) + +export async function getUser(id: string) { + const cached = cache.get(id) + if (cached) return cached + + const user = await db.user.findUnique({ where: { id } }) + cache.set(id, user) + return user +} + +// Request 1: DB query, result cached +// Request 2: cache hit, no DB query +``` + +Use when sequential user actions hit multiple endpoints needing the same data within seconds. + +**With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** LRU caching is especially effective because multiple concurrent requests can share the same function instance and cache. This means the cache persists across requests without needing external storage like Redis. + +**In traditional serverless:** Each invocation runs in isolation, so consider Redis for cross-process caching. + +Reference: [https://github.com/isaacs/node-lru-cache](https://github.com/isaacs/node-lru-cache) + +### 3.4 Hoist Static I/O to Module Level + +**Impact: HIGH (avoids repeated file/network I/O per request)** + +When loading static assets (fonts, logos, images, config files) in route handlers or server functions, hoist the I/O operation to module level. Module-level code runs once when the module is first imported, not on every request. This eliminates redundant file system reads or network fetches that would otherwise run on every invocation. + +**Incorrect: reads font file on every request** + +**Correct: loads once at module initialization** + +**Alternative: synchronous file reads with Node.js fs** + +**General Node.js example: loading config or templates** + +**When to use this pattern:** + +- Loading fonts for OG image generation + +- Loading static logos, icons, or watermarks + +- Reading configuration files that don't change at runtime + +- Loading email templates or other static templates + +- Any static asset that's the same across all requests + +**When NOT to use this pattern:** + +- Assets that vary per request or user + +- Files that may change during runtime (use caching with TTL instead) + +- Large files that would consume too much memory if kept loaded + +- Sensitive data that shouldn't persist in memory + +**With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** Module-level caching is especially effective because multiple concurrent requests share the same function instance. The static assets stay loaded in memory across requests without cold start penalties. + +**In traditional serverless:** Each cold start re-executes module-level code, but subsequent warm invocations reuse the loaded assets until the instance is recycled. + +### 3.5 Minimize Serialization at RSC Boundaries + +**Impact: HIGH (reduces data transfer size)** + +The React Server/Client boundary serializes all object properties into strings and embeds them in the HTML response and subsequent RSC requests. This serialized data directly impacts page weight and load time, so **size matters a lot**. Only pass fields that the client actually uses. + +**Incorrect: serializes all 50 fields** + +```tsx +async function Page() { + const user = await fetchUser() // 50 fields + return +} + +'use client' +function Profile({ user }: { user: User }) { + return
{user.name}
// uses 1 field +} +``` + +**Correct: serializes only 1 field** + +```tsx +async function Page() { + const user = await fetchUser() + return +} + +'use client' +function Profile({ name }: { name: string }) { + return
{name}
+} +``` + +### 3.6 Parallel Data Fetching with Component Composition + +**Impact: CRITICAL (eliminates server-side waterfalls)** + +React Server Components execute sequentially within a tree. Restructure with composition to parallelize data fetching. + +**Incorrect: Sidebar waits for Page's fetch to complete** + +```tsx +export default async function Page() { + const header = await fetchHeader() + return ( +
+
{header}
+ +
+ ) +} + +async function Sidebar() { + const items = await fetchSidebarItems() + return +} +``` + +**Correct: both fetch simultaneously** + +```tsx +async function Header() { + const data = await fetchHeader() + return
{data}
+} + +async function Sidebar() { + const items = await fetchSidebarItems() + return +} + +export default function Page() { + return ( +
+
+ +
+ ) +} +``` + +**Alternative with children prop:** + +```tsx +async function Header() { + const data = await fetchHeader() + return
{data}
+} + +async function Sidebar() { + const items = await fetchSidebarItems() + return +} + +function Layout({ children }: { children: ReactNode }) { + return ( +
+
+ {children} +
+ ) +} + +export default function Page() { + return ( + + + + ) +} +``` + +### 3.7 Per-Request Deduplication with React.cache() + +**Impact: MEDIUM (deduplicates within request)** + +Use `React.cache()` for server-side request deduplication. Authentication and database queries benefit most. + +**Usage:** + +```typescript +import { cache } from 'react' + +export const getCurrentUser = cache(async () => { + const session = await auth() + if (!session?.user?.id) return null + return await db.user.findUnique({ + where: { id: session.user.id } + }) +}) +``` + +Within a single request, multiple calls to `getCurrentUser()` execute the query only once. + +**Avoid inline objects as arguments:** + +`React.cache()` uses shallow equality (`Object.is`) to determine cache hits. Inline objects create new references each call, preventing cache hits. + +**Incorrect: always cache miss** + +```typescript +const getUser = cache(async (params: { uid: number }) => { + return await db.user.findUnique({ where: { id: params.uid } }) +}) + +// Each call creates new object, never hits cache +getUser({ uid: 1 }) +getUser({ uid: 1 }) // Cache miss, runs query again +``` + +**Correct: cache hit** + +```typescript +const params = { uid: 1 } +getUser(params) // Query runs +getUser(params) // Cache hit (same reference) +``` + +If you must pass objects, pass the same reference: + +**Next.js-Specific Note:** + +In Next.js, the `fetch` API is automatically extended with request memoization. Requests with the same URL and options are automatically deduplicated within a single request, so you don't need `React.cache()` for `fetch` calls. However, `React.cache()` is still essential for other async tasks: + +- Database queries (Prisma, Drizzle, etc.) + +- Heavy computations + +- Authentication checks + +- File system operations + +- Any non-fetch async work + +Use `React.cache()` to deduplicate these operations across your component tree. + +Reference: [https://react.dev/reference/react/cache](https://react.dev/reference/react/cache) + +### 3.8 Use after() for Non-Blocking Operations + +**Impact: MEDIUM (faster response times)** + +Use Next.js's `after()` to schedule work that should execute after a response is sent. This prevents logging, analytics, and other side effects from blocking the response. + +**Incorrect: blocks response** + +```tsx +import { logUserAction } from '@/app/utils' + +export async function POST(request: Request) { + // Perform mutation + await updateDatabase(request) + + // Logging blocks the response + const userAgent = request.headers.get('user-agent') || 'unknown' + await logUserAction({ userAgent }) + + return new Response(JSON.stringify({ status: 'success' }), { + status: 200, + headers: { 'Content-Type': 'application/json' } + }) +} +``` + +**Correct: non-blocking** + +```tsx +import { after } from 'next/server' +import { headers, cookies } from 'next/headers' +import { logUserAction } from '@/app/utils' + +export async function POST(request: Request) { + // Perform mutation + await updateDatabase(request) + + // Log after response is sent + after(async () => { + const userAgent = (await headers()).get('user-agent') || 'unknown' + const sessionCookie = (await cookies()).get('session-id')?.value || 'anonymous' + + logUserAction({ sessionCookie, userAgent }) + }) + + return new Response(JSON.stringify({ status: 'success' }), { + status: 200, + headers: { 'Content-Type': 'application/json' } + }) +} +``` + +The response is sent immediately while logging happens in the background. + +**Common use cases:** + +- Analytics tracking + +- Audit logging + +- Sending notifications + +- Cache invalidation + +- Cleanup tasks + +**Important notes:** + +- `after()` runs even if the response fails or redirects + +- Works in Server Actions, Route Handlers, and Server Components + +Reference: [https://nextjs.org/docs/app/api-reference/functions/after](https://nextjs.org/docs/app/api-reference/functions/after) + +--- + +## 4. Client-Side Data Fetching + +**Impact: MEDIUM-HIGH** + +Automatic deduplication and efficient data fetching patterns reduce redundant network requests. + +### 4.1 Deduplicate Global Event Listeners + +**Impact: LOW (single listener for N components)** + +Use `useSWRSubscription()` to share global event listeners across component instances. + +**Incorrect: N instances = N listeners** + +```tsx +function useKeyboardShortcut(key: string, callback: () => void) { + useEffect(() => { + const handler = (e: KeyboardEvent) => { + if (e.metaKey && e.key === key) { + callback() + } + } + window.addEventListener('keydown', handler) + return () => window.removeEventListener('keydown', handler) + }, [key, callback]) +} +``` + +When using the `useKeyboardShortcut` hook multiple times, each instance will register a new listener. + +**Correct: N instances = 1 listener** + +```tsx +import useSWRSubscription from 'swr/subscription' + +// Module-level Map to track callbacks per key +const keyCallbacks = new Map void>>() + +function useKeyboardShortcut(key: string, callback: () => void) { + // Register this callback in the Map + useEffect(() => { + if (!keyCallbacks.has(key)) { + keyCallbacks.set(key, new Set()) + } + keyCallbacks.get(key)!.add(callback) + + return () => { + const set = keyCallbacks.get(key) + if (set) { + set.delete(callback) + if (set.size === 0) { + keyCallbacks.delete(key) + } + } + } + }, [key, callback]) + + useSWRSubscription('global-keydown', () => { + const handler = (e: KeyboardEvent) => { + if (e.metaKey && keyCallbacks.has(e.key)) { + keyCallbacks.get(e.key)!.forEach(cb => cb()) + } + } + window.addEventListener('keydown', handler) + return () => window.removeEventListener('keydown', handler) + }) +} + +function Profile() { + // Multiple shortcuts will share the same listener + useKeyboardShortcut('p', () => { /* ... */ }) + useKeyboardShortcut('k', () => { /* ... */ }) + // ... +} +``` + +### 4.2 Use Passive Event Listeners for Scrolling Performance + +**Impact: MEDIUM (eliminates scroll delay caused by event listeners)** + +Add `{ passive: true }` to touch and wheel event listeners to enable immediate scrolling. Browsers normally wait for listeners to finish to check if `preventDefault()` is called, causing scroll delay. + +**Incorrect:** + +```typescript +useEffect(() => { + const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX) + const handleWheel = (e: WheelEvent) => console.log(e.deltaY) + + document.addEventListener('touchstart', handleTouch) + document.addEventListener('wheel', handleWheel) + + return () => { + document.removeEventListener('touchstart', handleTouch) + document.removeEventListener('wheel', handleWheel) + } +}, []) +``` + +**Correct:** + +```typescript +useEffect(() => { + const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX) + const handleWheel = (e: WheelEvent) => console.log(e.deltaY) + + document.addEventListener('touchstart', handleTouch, { passive: true }) + document.addEventListener('wheel', handleWheel, { passive: true }) + + return () => { + document.removeEventListener('touchstart', handleTouch) + document.removeEventListener('wheel', handleWheel) + } +}, []) +``` + +**Use passive when:** tracking/analytics, logging, any listener that doesn't call `preventDefault()`. + +**Don't use passive when:** implementing custom swipe gestures, custom zoom controls, or any listener that needs `preventDefault()`. + +### 4.3 Use SWR for Automatic Deduplication + +**Impact: MEDIUM-HIGH (automatic deduplication)** + +SWR enables request deduplication, caching, and revalidation across component instances. + +**Incorrect: no deduplication, each instance fetches** + +```tsx +function UserList() { + const [users, setUsers] = useState([]) + useEffect(() => { + fetch('/api/users') + .then(r => r.json()) + .then(setUsers) + }, []) +} +``` + +**Correct: multiple instances share one request** + +```tsx +import useSWR from 'swr' + +function UserList() { + const { data: users } = useSWR('/api/users', fetcher) +} +``` + +**For immutable data:** + +```tsx +import { useImmutableSWR } from '@/lib/swr' + +function StaticContent() { + const { data } = useImmutableSWR('/api/config', fetcher) +} +``` + +**For mutations:** + +```tsx +import { useSWRMutation } from 'swr/mutation' + +function UpdateButton() { + const { trigger } = useSWRMutation('/api/user', updateUser) + return +} +``` + +Reference: [https://swr.vercel.app](https://swr.vercel.app) + +### 4.4 Version and Minimize localStorage Data + +**Impact: MEDIUM (prevents schema conflicts, reduces storage size)** + +Add version prefix to keys and store only needed fields. Prevents schema conflicts and accidental storage of sensitive data. + +**Incorrect:** + +```typescript +// No version, stores everything, no error handling +localStorage.setItem('userConfig', JSON.stringify(fullUserObject)) +const data = localStorage.getItem('userConfig') +``` + +**Correct:** + +```typescript +const VERSION = 'v2' + +function saveConfig(config: { theme: string; language: string }) { + try { + localStorage.setItem(`userConfig:${VERSION}`, JSON.stringify(config)) + } catch { + // Throws in incognito/private browsing, quota exceeded, or disabled + } +} + +function loadConfig() { + try { + const data = localStorage.getItem(`userConfig:${VERSION}`) + return data ? JSON.parse(data) : null + } catch { + return null + } +} + +// Migration from v1 to v2 +function migrate() { + try { + const v1 = localStorage.getItem('userConfig:v1') + if (v1) { + const old = JSON.parse(v1) + saveConfig({ theme: old.darkMode ? 'dark' : 'light', language: old.lang }) + localStorage.removeItem('userConfig:v1') + } + } catch {} +} +``` + +**Store minimal fields from server responses:** + +```typescript +// User object has 20+ fields, only store what UI needs +function cachePrefs(user: FullUser) { + try { + localStorage.setItem('prefs:v1', JSON.stringify({ + theme: user.preferences.theme, + notifications: user.preferences.notifications + })) + } catch {} +} +``` + +**Always wrap in try-catch:** `getItem()` and `setItem()` throw in incognito/private browsing (Safari, Firefox), when quota exceeded, or when disabled. + +**Benefits:** Schema evolution via versioning, reduced storage size, prevents storing tokens/PII/internal flags. + +--- + +## 5. Re-render Optimization + +**Impact: MEDIUM** + +Reducing unnecessary re-renders minimizes wasted computation and improves UI responsiveness. + +### 5.1 Calculate Derived State During Rendering + +**Impact: MEDIUM (avoids redundant renders and state drift)** + +If a value can be computed from current props/state, do not store it in state or update it in an effect. Derive it during render to avoid extra renders and state drift. Do not set state in effects solely in response to prop changes; prefer derived values or keyed resets instead. + +**Incorrect: redundant state and effect** + +```tsx +function Form() { + const [firstName, setFirstName] = useState('First') + const [lastName, setLastName] = useState('Last') + const [fullName, setFullName] = useState('') + + useEffect(() => { + setFullName(firstName + ' ' + lastName) + }, [firstName, lastName]) + + return

{fullName}

+} +``` + +**Correct: derive during render** + +```tsx +function Form() { + const [firstName, setFirstName] = useState('First') + const [lastName, setLastName] = useState('Last') + const fullName = firstName + ' ' + lastName + + return

{fullName}

+} +``` + +Reference: [https://react.dev/learn/you-might-not-need-an-effect](https://react.dev/learn/you-might-not-need-an-effect) + +### 5.2 Defer State Reads to Usage Point + +**Impact: MEDIUM (avoids unnecessary subscriptions)** + +Don't subscribe to dynamic state (searchParams, localStorage) if you only read it inside callbacks. + +**Incorrect: subscribes to all searchParams changes** + +```tsx +function ShareButton({ chatId }: { chatId: string }) { + const searchParams = useSearchParams() + + const handleShare = () => { + const ref = searchParams.get('ref') + shareChat(chatId, { ref }) + } + + return +} +``` + +**Correct: reads on demand, no subscription** + +```tsx +function ShareButton({ chatId }: { chatId: string }) { + const handleShare = () => { + const params = new URLSearchParams(window.location.search) + const ref = params.get('ref') + shareChat(chatId, { ref }) + } + + return +} +``` + +### 5.3 Do not wrap a simple expression with a primitive result type in useMemo + +**Impact: LOW-MEDIUM (wasted computation on every render)** + +When an expression is simple (few logical or arithmetical operators) and has a primitive result type (boolean, number, string), do not wrap it in `useMemo`. + +Calling `useMemo` and comparing hook dependencies may consume more resources than the expression itself. + +**Incorrect:** + +```tsx +function Header({ user, notifications }: Props) { + const isLoading = useMemo(() => { + return user.isLoading || notifications.isLoading + }, [user.isLoading, notifications.isLoading]) + + if (isLoading) return + // return some markup +} +``` + +**Correct:** + +```tsx +function Header({ user, notifications }: Props) { + const isLoading = user.isLoading || notifications.isLoading + + if (isLoading) return + // return some markup +} +``` + +### 5.4 Extract Default Non-primitive Parameter Value from Memoized Component to Constant + +**Impact: MEDIUM (restores memoization by using a constant for default value)** + +When memoized component has a default value for some non-primitive optional parameter, such as an array, function, or object, calling the component without that parameter results in broken memoization. This is because new value instances are created on every rerender, and they do not pass strict equality comparison in `memo()`. + +To address this issue, extract the default value into a constant. + +**Incorrect: `onClick` has different values on every rerender** + +```tsx +const UserAvatar = memo(function UserAvatar({ onClick = () => {} }: { onClick?: () => void }) { + // ... +}) + +// Used without optional onClick + +``` + +**Correct: stable default value** + +```tsx +const NOOP = () => {}; + +const UserAvatar = memo(function UserAvatar({ onClick = NOOP }: { onClick?: () => void }) { + // ... +}) + +// Used without optional onClick + +``` + +### 5.5 Extract to Memoized Components + +**Impact: MEDIUM (enables early returns)** + +Extract expensive work into memoized components to enable early returns before computation. + +**Incorrect: computes avatar even when loading** + +```tsx +function Profile({ user, loading }: Props) { + const avatar = useMemo(() => { + const id = computeAvatarId(user) + return + }, [user]) + + if (loading) return + return
{avatar}
+} +``` + +**Correct: skips computation when loading** + +```tsx +const UserAvatar = memo(function UserAvatar({ user }: { user: User }) { + const id = useMemo(() => computeAvatarId(user), [user]) + return +}) + +function Profile({ user, loading }: Props) { + if (loading) return + return ( +
+ +
+ ) +} +``` + +**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders. + +### 5.6 Narrow Effect Dependencies + +**Impact: LOW (minimizes effect re-runs)** + +Specify primitive dependencies instead of objects to minimize effect re-runs. + +**Incorrect: re-runs on any user field change** + +```tsx +useEffect(() => { + console.log(user.id) +}, [user]) +``` + +**Correct: re-runs only when id changes** + +```tsx +useEffect(() => { + console.log(user.id) +}, [user.id]) +``` + +**For derived state, compute outside effect:** + +```tsx +// Incorrect: runs on width=767, 766, 765... +useEffect(() => { + if (width < 768) { + enableMobileMode() + } +}, [width]) + +// Correct: runs only on boolean transition +const isMobile = width < 768 +useEffect(() => { + if (isMobile) { + enableMobileMode() + } +}, [isMobile]) +``` + +### 5.7 Put Interaction Logic in Event Handlers + +**Impact: MEDIUM (avoids effect re-runs and duplicate side effects)** + +If a side effect is triggered by a specific user action (submit, click, drag), run it in that event handler. Do not model the action as state + effect; it makes effects re-run on unrelated changes and can duplicate the action. + +**Incorrect: event modeled as state + effect** + +```tsx +function Form() { + const [submitted, setSubmitted] = useState(false) + const theme = useContext(ThemeContext) + + useEffect(() => { + if (submitted) { + post('/api/register') + showToast('Registered', theme) + } + }, [submitted, theme]) + + return +} +``` + +**Correct: do it in the handler** + +```tsx +function Form() { + const theme = useContext(ThemeContext) + + function handleSubmit() { + post('/api/register') + showToast('Registered', theme) + } + + return +} +``` + +Reference: [https://react.dev/learn/removing-effect-dependencies#should-this-code-move-to-an-event-handler](https://react.dev/learn/removing-effect-dependencies#should-this-code-move-to-an-event-handler) + +### 5.8 Subscribe to Derived State + +**Impact: MEDIUM (reduces re-render frequency)** + +Subscribe to derived boolean state instead of continuous values to reduce re-render frequency. + +**Incorrect: re-renders on every pixel change** + +```tsx +function Sidebar() { + const width = useWindowWidth() // updates continuously + const isMobile = width < 768 + return