Feature: Add QRCode scanner for nsecbunker login (#79)

Co-authored-by: highperfocused <highperfocused@pm.me>
This commit is contained in:
mroxso
2025-04-20 16:44:27 +02:00
committed by GitHub
parent 8c54786240
commit ebaf7ce308
3 changed files with 488 additions and 202 deletions

View File

@@ -24,10 +24,19 @@ import {
import { useEffect, useRef, useState } from "react"
import { getPublicKey, generateSecretKey, nip19, SimplePool } from 'nostr-tools'
import { BunkerSigner, parseBunkerInput } from 'nostr-tools/nip46'
import { InfoIcon, Loader2 } from "lucide-react";
import { InfoIcon, Loader2, QrCode, X } from "lucide-react";
import Link from "next/link";
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
import { fetchNip65Relays, mergeAndStoreRelays } from "@/utils/nip65Utils"
import { Html5Qrcode } from "html5-qrcode";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogClose
} from "@/components/ui/dialog"
export function LoginForm() {
@@ -42,6 +51,9 @@ export function LoginForm() {
const [isNsecLoading, setIsNsecLoading] = useState(false);
const [isNpubLoading, setIsNpubLoading] = useState(false);
const [bunkerError, setBunkerError] = useState<string | null>(null);
const [isQRDialogOpen, setIsQRDialogOpen] = useState(false);
const [isScanning, setIsScanning] = useState(false);
const qrScannerRef = useRef<any>(null);
// Default relays to query for NIP-65 data
const defaultRelays = [
@@ -54,11 +66,9 @@ export function LoginForm() {
// Helper function to load NIP-65 relays for a user
const loadNip65Relays = async (pubkey: string) => {
try {
// Fetch the user's relay preferences
const nip65Relays = await fetchNip65Relays(pubkey, defaultRelays);
if (nip65Relays.length > 0) {
// Merge with existing relays and store in localStorage
mergeAndStoreRelays(nip65Relays);
console.log(`Loaded ${nip65Relays.length} relays from NIP-65 for user ${pubkey}`);
} else {
@@ -72,20 +82,16 @@ export function LoginForm() {
// Function to complete login process
const completeLogin = async (pubkey: string, loginType: string, redirect = true) => {
try {
// Store the login info
localStorage.setItem("pubkey", pubkey);
localStorage.setItem("loginType", loginType);
// Load NIP-65 relays
await loadNip65Relays(pubkey);
// Redirect if needed
if (redirect) {
window.location.href = `/profile/${nip19.npubEncode(pubkey)}`;
}
} catch (error) {
console.error("Error completing login:", error);
// Reset all loading states in case of error
setIsLoading(false);
setIsBunkerLoading(false);
setIsExtensionLoading(false);
@@ -96,7 +102,6 @@ export function LoginForm() {
};
useEffect(() => {
// handle Amber Login Response
const urlParams = new URLSearchParams(window.location.search);
const amberResponse = urlParams.get('amberResponse');
if (amberResponse !== null) {
@@ -104,12 +109,64 @@ export function LoginForm() {
completeLogin(amberResponse, "amber");
}
// Handle nostrconnect URL from bunker
if (window.location.hash && window.location.hash.startsWith('#nostrconnect://')) {
handleNostrConnect(window.location.hash.substring(1));
}
return () => {
if (qrScannerRef.current) {
qrScannerRef.current.stop().catch(console.error);
}
};
}, []);
// Handle QR Scanner dialog
const startQRScanner = () => {
setIsQRDialogOpen(true);
setTimeout(() => {
setIsScanning(true);
const qrContainer = document.getElementById('qr-reader');
if (qrContainer) {
const html5QrCode = new Html5Qrcode("qr-reader");
qrScannerRef.current = html5QrCode;
html5QrCode.start(
{ facingMode: "environment" },
{
fps: 10,
qrbox: { width: 250, height: 250 },
},
(decodedText) => {
if (decodedText) {
html5QrCode.stop().catch(console.error);
setIsQRDialogOpen(false);
setIsScanning(false);
if (bunkerUrlInput.current) {
bunkerUrlInput.current.value = decodedText;
}
}
},
(errorMessage) => {
console.error("QR Scan error:", errorMessage);
}
).catch(error => {
console.error("Starting QR Scanner failed:", error);
setIsScanning(false);
});
}
}, 300);
};
const stopQRScanner = () => {
if (qrScannerRef.current) {
qrScannerRef.current.stop().catch(console.error);
}
setIsScanning(false);
setIsQRDialogOpen(false);
};
// Handle NIP-46 connection initiated by bunker
const handleNostrConnect = async (url: string) => {
try {
@@ -117,11 +174,9 @@ export function LoginForm() {
setIsBunkerLoading(true);
setBunkerError(null);
// Generate local secret key for communicating with the bunker
const localSecretKey = generateSecretKey();
const localSecretKeyHex = bytesToHex(localSecretKey);
// Parse the nostrconnect URL
const bunkerUrl = url.includes('://') ? url : `nostrconnect://${url}`;
const bunkerPointer = await parseBunkerInput(bunkerUrl);
@@ -129,25 +184,20 @@ export function LoginForm() {
throw new Error('Invalid bunker URL');
}
// Create pool and bunker signer
const pool = new SimplePool();
const bunker = new BunkerSigner(localSecretKey, bunkerPointer, { pool });
try {
await bunker.connect();
// Get the user's public key from the bunker
const userPubkey = await bunker.getPublicKey();
// Store connection info in localStorage
localStorage.setItem("bunkerLocalKey", localSecretKeyHex);
localStorage.setItem("bunkerUrl", bunkerUrl);
// Close the pool
await bunker.close();
pool.close([]);
// Complete login and redirect
await completeLogin(userPubkey, "bunker", true);
} catch (err) {
console.error("Bunker connection error:", err);
@@ -185,7 +235,6 @@ export function LoginForm() {
}
const intent = `intent:#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=get_public_key;S.callbackUrl=http://${hostname}/login?amberResponse=;end`;
window.location.href = intent;
// The loading state will be maintained until the callback returns or page unloads
} catch (error) {
console.error("Error launching Amber:", error);
setIsAmberLoading(false);
@@ -197,7 +246,6 @@ export function LoginForm() {
try {
setIsExtensionLoading(true);
setIsLoading(true);
// eslint-disable-next-line
if (window.nostr !== undefined) {
publicKey.current = await window.nostr.getPublicKey()
console.log("Logged in with pubkey: ", publicKey.current);
@@ -266,146 +314,189 @@ export function LoginForm() {
};
return (
<Card className="w-full max-w-xl">
<CardHeader>
<CardTitle className="text-2xl">Login to Lumina</CardTitle>
<CardDescription>
Login to your account with nostr extension, bunker, or with your nsec.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<div className="grid grid-cols-8 gap-2">
<Button
className="w-full col-span-7"
onClick={handleExtensionLogin}
disabled={isLoading || isExtensionLoading}
>
{isExtensionLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : "Sign in with Extension (NIP-07)"}
</Button>
<Link target="_blank" href="https://www.getflamingo.org/">
<Button variant={"outline"} disabled={isLoading}><InfoIcon /></Button>
</Link>
</div>
<div className="grid grid-cols-8 gap-2">
<Button
className="w-full col-span-7"
onClick={handleAmber}
disabled={isLoading || isAmberLoading}
>
{isAmberLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : "Sign in with Amber"}
</Button>
<Link target="_blank" href="https://github.com/greenart7c3/Amber">
<Button variant={"outline"} disabled={isLoading}><InfoIcon /></Button>
</Link>
</div>
<hr />
or
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Login with Bunker (NIP-46)</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label htmlFor="bunkerUrl">Bunker URL</Label>
<Input
placeholder="bunker://... or nostrconnect://..."
id="bunkerUrl"
ref={bunkerUrlInput}
type="text"
disabled={isLoading || isBunkerLoading}
/>
{bunkerError && <p className="text-red-500 text-sm">{bunkerError}</p>}
<Button
className="w-full"
onClick={handleBunkerLogin}
disabled={isLoading || isBunkerLoading}
>
{isBunkerLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : "Sign in with Bunker"}
</Button>
<p className="text-sm text-muted-foreground">
Use a NIP-46 compatible bunker URL that starts with bunker:// or nostrconnect://
</p>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
or
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Login with npub (read-only)</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label htmlFor="npub">npub</Label>
<Input
placeholder="npub1..."
id="npub"
ref={npubInput}
type="text"
disabled={isLoading || isNpubLoading}
/>
<Button
className="w-full"
onClick={handleNpubLogin}
disabled={isLoading || isNpubLoading}
>
{isNpubLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Signing in...
</>
) : "Sign in"}
</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
or
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Login with nsec (not recommended)</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label htmlFor="nsec">nsec</Label>
<Input
placeholder="nsecabcdefghijklmnopqrstuvwxyz"
id="nsec"
ref={nsecInput}
type="password"
disabled={isLoading || isNsecLoading}
/>
<Button
className="w-full"
onClick={handleNsecLogin}
disabled={isLoading || isNsecLoading}
>
{isNsecLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Signing in...
</>
) : "Sign in"}
</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</CardContent>
<CardFooter>
</CardFooter>
</Card>
<>
<Card className="w-full max-w-xl">
<CardHeader>
<CardTitle className="text-2xl">Login to Lumina</CardTitle>
<CardDescription>
Login to your account with nostr extension, bunker, or with your nsec.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-4">
<div className="grid grid-cols-8 gap-2">
<Button
className="w-full col-span-7"
onClick={handleExtensionLogin}
disabled={isLoading || isExtensionLoading}
>
{isExtensionLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : "Sign in with Extension (NIP-07)"}
</Button>
<Link target="_blank" href="https://www.getflamingo.org/">
<Button variant={"outline"} disabled={isLoading}><InfoIcon /></Button>
</Link>
</div>
<div className="grid grid-cols-8 gap-2">
<Button
className="w-full col-span-7"
onClick={handleAmber}
disabled={isLoading || isAmberLoading}
>
{isAmberLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : "Sign in with Amber"}
</Button>
<Link target="_blank" href="https://github.com/greenart7c3/Amber">
<Button variant={"outline"} disabled={isLoading}><InfoIcon /></Button>
</Link>
</div>
<hr />
or
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Login with Bunker (NIP-46)</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label htmlFor="bunkerUrl">Bunker URL</Label>
<div className="flex gap-2">
<Input
placeholder="bunker://... or nostrconnect://..."
id="bunkerUrl"
ref={bunkerUrlInput}
type="text"
disabled={isLoading || isBunkerLoading}
className="flex-1"
/>
<Button
variant="outline"
onClick={startQRScanner}
disabled={isLoading || isBunkerLoading}
title="Scan QR code"
>
<QrCode className="h-4 w-4" />
</Button>
</div>
{bunkerError && <p className="text-red-500 text-sm">{bunkerError}</p>}
<Button
className="w-full"
onClick={handleBunkerLogin}
disabled={isLoading || isBunkerLoading}
>
{isBunkerLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : "Sign in with Bunker"}
</Button>
<p className="text-sm text-muted-foreground">
Use a NIP-46 compatible bunker URL that starts with bunker:// or nostrconnect://
</p>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
or
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Login with npub (read-only)</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label htmlFor="npub">npub</Label>
<Input
placeholder="npub1..."
id="npub"
ref={npubInput}
type="text"
disabled={isLoading || isNpubLoading}
/>
<Button
className="w-full"
onClick={handleNpubLogin}
disabled={isLoading || isNpubLoading}
>
{isNpubLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Signing in...
</>
) : "Sign in"}
</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
or
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Login with nsec (not recommended)</AccordionTrigger>
<AccordionContent>
<div className="grid gap-2">
<Label htmlFor="nsec">nsec</Label>
<Input
placeholder="nsecabcdefghijklmnopqrstuvwxyz"
id="nsec"
ref={nsecInput}
type="password"
disabled={isLoading || isNsecLoading}
/>
<Button
className="w-full"
onClick={handleNsecLogin}
disabled={isLoading || isNsecLoading}
>
{isNsecLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Signing in...
</>
) : "Sign in"}
</Button>
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</CardContent>
<CardFooter>
</CardFooter>
</Card>
{/* QR Code Scanner Dialog */}
<Dialog open={isQRDialogOpen} onOpenChange={(open) => {
if (!open) stopQRScanner();
setIsQRDialogOpen(open);
}}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Scan Bunker QR Code</DialogTitle>
<DialogDescription>
Position the QR code in the camera view to scan your bunker URL.
</DialogDescription>
</DialogHeader>
<div className="flex flex-col items-center justify-center">
<div id="qr-reader" style={{ width: '100%', maxWidth: '500px' }}></div>
{isScanning ? (
<p className="text-sm text-center mt-2">Scanning...</p>
) : (
<p className="text-sm text-center mt-2">Starting camera...</p>
)}
</div>
<div className="flex justify-center">
<DialogClose asChild>
<Button variant="secondary" onClick={stopQRScanner}>
<X className="h-4 w-4 mr-2" /> Cancel
</Button>
</DialogClose>
</div>
</DialogContent>
</Dialog>
</>
)
}

279
package-lock.json generated
View File

@@ -28,6 +28,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.0.0-rc21",
"html5-qrcode": "^2.3.8",
"light-bolt11-decoder": "^3.1.1",
"lucide-react": "^0.475.0",
"next": "14.2.28",
@@ -39,6 +40,7 @@
"react-dom": "^18",
"react-hook-form": "^7.51.4",
"react-icons": "^5.1.0",
"react-qr-code": "^2.0.15",
"sharp": "^0.33.5",
"tailwind-merge": "^3.0.1",
"tailwindcss-animate": "^1.0.7",
@@ -2320,7 +2322,9 @@
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.22",
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -4648,9 +4652,10 @@
}
},
"node_modules/@types/eslint": {
"version": "8.56.2",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
"integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==",
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "*",
@@ -4661,6 +4666,7 @@
"version": "3.7.7",
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint": "*",
@@ -4668,9 +4674,10 @@
}
},
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"license": "MIT",
"peer": true
},
"node_modules/@types/glob": {
@@ -4899,6 +4906,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
@@ -4909,24 +4917,28 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
@@ -4938,12 +4950,14 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -4956,6 +4970,7 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
@@ -4965,6 +4980,7 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@xtuc/long": "4.2.2"
@@ -4974,12 +4990,14 @@
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
"license": "MIT",
"peer": true
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -4996,6 +5014,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -5009,6 +5028,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -5021,6 +5041,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -5035,6 +5056,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
@@ -5045,12 +5067,14 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"license": "BSD-3-Clause",
"peer": true
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"license": "Apache-2.0",
"peer": true
},
"node_modules/acorn": {
@@ -5086,6 +5110,45 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"license": "MIT",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -5703,9 +5766,10 @@
}
},
"node_modules/chrome-trace-event": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
"integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.0"
@@ -6240,9 +6304,10 @@
}
},
"node_modules/es-module-lexer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
"integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
"license": "MIT",
"peer": true
},
"node_modules/es-set-tostringtag": {
@@ -6690,6 +6755,7 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.8.x"
@@ -6732,6 +6798,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/fastq": {
"version": "1.17.0",
"license": "ISC",
@@ -7021,6 +7103,7 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"license": "BSD-2-Clause",
"peer": true
},
"node_modules/glob/node_modules/minimatch": {
@@ -7206,6 +7289,12 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
"node_modules/html5-qrcode": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/html5-qrcode/-/html5-qrcode-2.3.8.tgz",
"integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==",
"license": "Apache-2.0"
},
"node_modules/idb": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
@@ -7801,6 +7890,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"license": "MIT",
"peer": true
},
"node_modules/json-schema": {
@@ -7928,6 +8018,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.11.5"
@@ -8077,6 +8168,7 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.6"
@@ -8086,6 +8178,7 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"peer": true,
"dependencies": {
"mime-db": "1.52.0"
@@ -8168,6 +8261,7 @@
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"license": "MIT",
"peer": true
},
"node_modules/next": {
@@ -8900,7 +8994,6 @@
},
"node_modules/prop-types": {
"version": "15.8.1",
"dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -8915,6 +9008,12 @@
"node": ">=6"
}
},
"node_modules/qr.js": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
"integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==",
"license": "MIT"
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"funding": [
@@ -8987,9 +9086,21 @@
},
"node_modules/react-is": {
"version": "16.13.1",
"dev": true,
"license": "MIT"
},
"node_modules/react-qr-code": {
"version": "2.0.15",
"resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.15.tgz",
"integrity": "sha512-MkZcjEXqVKqXEIMVE0mbcGgDpkfSdd8zhuzXEl9QzYeNcw8Hq2oVIzDLWuZN2PQBwM5PWjc2S31K8Q1UbcFMfw==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.8.1",
"qr.js": "0.0.0"
},
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-remove-scroll": {
"version": "2.5.5",
"license": "MIT",
@@ -9941,9 +10052,10 @@
}
},
"node_modules/terser": {
"version": "5.27.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz",
"integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==",
"version": "5.39.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
"integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -9958,15 +10070,16 @@
}
},
"node_modules/terser-webpack-plugin": {
"version": "5.3.10",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
"version": "5.3.14",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz",
"integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.20",
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
"schema-utils": "^3.1.1",
"serialize-javascript": "^6.0.1",
"terser": "^5.26.0"
"schema-utils": "^4.3.0",
"serialize-javascript": "^6.0.2",
"terser": "^5.31.1"
},
"engines": {
"node": ">= 10.13.0"
@@ -9990,14 +10103,50 @@
}
}
},
"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"node_modules/terser-webpack-plugin/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/terser-webpack-plugin/node_modules/schema-utils": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"license": "MIT",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"
@@ -10364,6 +10513,7 @@
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
"license": "MIT",
"peer": true,
"dependencies": {
"glob-to-regexp": "^0.4.1",
@@ -10379,9 +10529,10 @@
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
},
"node_modules/webpack": {
"version": "5.97.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
"version": "5.99.6",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.6.tgz",
"integrity": "sha512-TJOLrJ6oeccsGWPl7ujCYuc0pIq2cNsuD6GZDma8i5o5Npvcco/z+NKvZSFsP0/x6SShVb0+X2JK/JHUjKY9dQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
@@ -10402,9 +10553,9 @@
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.2.0",
"schema-utils": "^4.3.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.10",
"terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.1",
"webpack-sources": "^3.2.3"
},
@@ -10428,15 +10579,47 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/webpack/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/webpack/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/webpack/node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
@@ -10450,20 +10633,30 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=4.0"
}
},
"node_modules/webpack/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT",
"peer": true
},
"node_modules/webpack/node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
"integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
"integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
"@types/json-schema": "^7.0.9",
"ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 10.13.0"

View File

@@ -29,6 +29,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.0.0-rc21",
"html5-qrcode": "^2.3.8",
"light-bolt11-decoder": "^3.1.1",
"lucide-react": "^0.475.0",
"next": "14.2.28",
@@ -40,6 +41,7 @@
"react-dom": "^18",
"react-hook-form": "^7.51.4",
"react-icons": "^5.1.0",
"react-qr-code": "^2.0.15",
"sharp": "^0.33.5",
"tailwind-merge": "^3.0.1",
"tailwindcss-animate": "^1.0.7",