From 3c40927a7bdc2be8d8fa4f29a765fcc5419069da Mon Sep 17 00:00:00 2001 From: Jona Date: Tue, 9 Dec 2025 12:09:07 -0600 Subject: [PATCH] test: integrate db --- actions/account.ts | 54 ++++ actions/store.ts | 53 ++++ app/paydesk/page.tsx | 2 +- app/settings/pin/layout.tsx | 9 + app/settings/pin/page.tsx | 73 ++++++ components/app-dashboard.tsx | 34 ++- components/app/app-content.tsx | 2 +- components/login-view.tsx | 371 ++++++++------------------- components/payment/payment-error.tsx | 2 +- components/settings-pin-page.tsx | 163 ++++++++++++ components/ui/app.tsx | 103 ++++++++ components/ui/input-otp.tsx | 92 +++---- config/constants.ts | 2 + config/database.ts | 9 + config/schema.ts | 34 +++ context/auth.tsx | 6 +- context/error.tsx | 27 ++ lib/database.ts | 8 + lib/instantdb.ts | 244 +++++++++--------- package.json | 6 +- pnpm-lock.yaml | 357 +++++++++++++++++++++++++- 21 files changed, 1193 insertions(+), 458 deletions(-) create mode 100644 actions/account.ts create mode 100644 actions/store.ts create mode 100644 app/settings/pin/layout.tsx create mode 100644 app/settings/pin/page.tsx create mode 100644 components/settings-pin-page.tsx create mode 100644 components/ui/app.tsx create mode 100644 config/constants.ts create mode 100644 config/database.ts create mode 100644 config/schema.ts create mode 100644 context/error.tsx create mode 100644 lib/database.ts diff --git a/actions/account.ts b/actions/account.ts new file mode 100644 index 0000000..0e0c6ff --- /dev/null +++ b/actions/account.ts @@ -0,0 +1,54 @@ +'use server'; + +import { id } from '@instantdb/core'; +import { sha256 } from '@noble/hashes/sha2.js'; + +import { db } from '@/config/database'; + +export async function addAccount(props: { name: string; email: string; pubkey: string }): Promise { + const { name = null, email = null, pubkey = null } = props; + + if (!email && !pubkey) { + // return {} + } + + // TO-DO + // Format pubkey + + // Find if customer exist + const query = { + customer: { + $: { + where: { + email: email || '', + pubkey: pubkey || '', + }, + }, + }, + }; + + const { customer } = await db.query(query); + + if (customer && customer.length > 0) { + // @ts-ignore + return customer[0]?.id; + } + + // If not exist, create + const newId = id(); + + await db.transact( + // @ts-ignore + db.tx.customer[newId].update({ + // Data + name, + email, + pubkey, + + // Status + created_at: Date.now(), + }), + ); + + return newId; +} diff --git a/actions/store.ts b/actions/store.ts new file mode 100644 index 0000000..631e7c8 --- /dev/null +++ b/actions/store.ts @@ -0,0 +1,53 @@ +'use server'; + +import { id } from '@instantdb/core'; +import { sha256 } from '@noble/hashes/sha2.js'; + +import { db } from '@/config/database'; + +export async function addAccount(props: { id: string }): Promise { + const { id } = props; + + if (!id) { + // return {} + } + + // TO-DO + // Format pubkey + + // Find if customer exist + const query = { + store: { + $: { + where: { + id: id || '', + }, + }, + }, + }; + + const { store } = await db.query(query); + + if (store && store.length > 0) { + // @ts-ignore + return store[0]?.id; + } + + // If not exist, create + const newId = id(); + + // await db.transact( + // // @ts-ignore + // db.tx.customer[newId].update({ + // // Data + // name, + // email, + // pubkey, + + // // Status + // created_at: Date.now(), + // }), + // ); + + return newId; +} diff --git a/app/paydesk/page.tsx b/app/paydesk/page.tsx index 93d32ec..f1b7201 100644 --- a/app/paydesk/page.tsx +++ b/app/paydesk/page.tsx @@ -44,7 +44,7 @@ export default function PaydeskPage() {
-
+
{getCurrencySymbol()} {new Intl.NumberFormat().format(numpadData.intAmount[numpadData.usedCurrency])} {settings.currency} diff --git a/app/settings/pin/layout.tsx b/app/settings/pin/layout.tsx new file mode 100644 index 0000000..82f4492 --- /dev/null +++ b/app/settings/pin/layout.tsx @@ -0,0 +1,9 @@ +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'PIN Settings', +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return <>{children}; +} diff --git a/app/settings/pin/page.tsx b/app/settings/pin/page.tsx new file mode 100644 index 0000000..ff2fd58 --- /dev/null +++ b/app/settings/pin/page.tsx @@ -0,0 +1,73 @@ +'use client'; + +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import { ChevronLeft, Settings } from 'lucide-react'; + +import { useNumpad } from '@/hooks/use-numpad'; +import { useSettings } from '@/hooks/use-settings'; +import { useCurrencyConverter } from '@/hooks/use-currency-converter'; + +import { Button } from '@/components/ui/button'; +import { Keyboard } from '@/components/keyboard'; +import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from '@/components/ui/input-otp'; +import { AvailableCurrencies } from '@/types/config'; + +export default function Page() { + const router = useRouter(); + + const { settings } = useSettings(); + const numpadData = useNumpad('SAT'); + + const countLength = String(numpadData.intAmount['SAT']).length; + console.log('countLength', countLength); + + return ( +
+
+
+
+ +

{'Create PIN'}

+
+ {/* */} +
+
+ +
+
+
+ + + + + + + + + + + + + +
+
+
+ + 5} /> +
+
+
+ ); +} diff --git a/components/app-dashboard.tsx b/components/app-dashboard.tsx index aece66f..f1a6274 100644 --- a/components/app-dashboard.tsx +++ b/components/app-dashboard.tsx @@ -4,6 +4,7 @@ import { useEffect } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { Calculator, Store, Settings, X, User } from 'lucide-react'; +import { sha256 } from '@noble/hashes/sha2.js'; import { useAuth } from '@/context/auth'; @@ -13,6 +14,8 @@ import { JoinCloud } from '@/components/join-cloud'; import { LoadingSpinner } from '@/components/ui/loading-spinner'; import { getLocal } from '@/lib/localStorage'; +import { db } from '@/lib/database'; + const dashboardCards = [ { title: 'Shop', @@ -34,17 +37,20 @@ const dashboardCards = [ export function AppDashboard() { const router = useRouter(); - const { logout, lightningAddress, isAuthenticated, isLoading, authMethod } = useAuth(); - const waitlistEmail = getLocal('waitlist-email'); + const user = db.useAuth(); + console.log('user', user); + // const { logout, lightningAddress, isAuthenticated, isLoading, authMethod } = useAuth(); + + // const waitlistEmail = getLocal('waitlist-email'); - useEffect(() => { - if (!isAuthenticated && !isLoading) { - router.push('/login'); - } - }, [isAuthenticated, isLoading]); + // useEffect(() => { + // if (!isAuthenticated && !isLoading) { + // router.push('/login'); + // } + // }, [isAuthenticated, isLoading]); - if (isLoading) { + if (user?.isLoading) { return (
@@ -57,14 +63,14 @@ export function AppDashboard() { {/* Header */}
-
- {!waitlistEmail && } + {/* {!waitlistEmail && } */} {/* Main Content */}

Control Panel

- {!isAuthenticated && ( + {/* {!isAuthenticated && (

Running in guest mode.{' '} Setup now

- )} + )} */}
diff --git a/components/app/app-content.tsx b/components/app/app-content.tsx index 5930b9f..681d201 100644 --- a/components/app/app-content.tsx +++ b/components/app/app-content.tsx @@ -27,7 +27,7 @@ export const AppContent = React.forwardRef null); - - const [inputAddress, setInputAddress] = useState(null); - const [nwc, setNwc] = useState(null); - - const [isValidating, setIsValidating] = useState(false); - const [error, setError] = useState(null); - const [showSuccess, setShowSuccess] = useState(false); - - const [showCameraModal, setShowCameraModal] = useState(false); - - // Auto-login si ya está autenticado - useEffect(() => { - if (isAuthenticated) { - setShowSuccess(true); - setTimeout(() => { - router.push('/app'); - }, 1500); - } - }, [isAuthenticated]); +import { InputOTP, InputOTPGroup, InputOTPSlot } from '@/components/ui/input-otp'; +import { AppFooter } from '@/components/app/app-footer'; - const startCamera = () => { - if (typeof window !== 'undefined') { - setShowCameraModal(true); - } - }; +import { db } from '@/lib/database'; +import { useRouter } from 'next/navigation'; - const stopCamera = () => { - setShowCameraModal(false); - }; +export function LoginView() { + const [sentEmail, setSentEmail] = useState(''); - const handleScan = (code: string) => { - setError(null); + return <>{!sentEmail ? : }; +} - if (!code.includes('@')) { - setError('Invalid Lightning Address'); +function EmailStep({ onSendEmail }: { onSendEmail: (email: string) => void }) { + const inputRef = React.useRef(null); + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const inputEl = inputRef.current!; + const email = inputEl.value; + onSendEmail(email); + + if (!email) { + alert('Please enter a valid email address.'); + onSendEmail(''); return; } - stopCamera(); - - login(code).then((res) => { - setIsValidating(true); - - if (!res?.success) { - setError(res?.error as string); - setIsValidating(false); - } - - setShowSuccess(true); - setTimeout(() => { - router.push('/app'); - }, 1500); + db.auth.sendMagicCode({ email }).catch((err) => { + console.log('Error al enviar el código mágico:', err); + alert('Uh oh :' + err.body?.message); + onSendEmail(''); }); }; - - // const handlePaste = async () => { - // setError(''); - // try { - // const text = await navigator.clipboard.readText(); - - // if (!isValidNWC(text)) { - // setError('Invalid value'); - // return; - // } - - // setNwc(text); - // } catch (error) { - // console.log('error', error); - // } - // }; - - // const isValidNWC = (value: string) => { - // const prefix = 'nostr+walletconnect://'; - // return typeof value === 'string' && value.startsWith(prefix); - // }; - - // Mostrar loading mientras verifica sesión existente - if (isLoading) { - return ( -
- -
- ); - } - - // Mostrar pantalla de éxito - if (showSuccess) { - return ( -
-
-
- -
-

Welcome!

- {lightningAddress &&

Logged in as {lightningAddress}

} -
-
- ); - } - return ( - - -
-
- - Lightning PoS Logo - +
+ + +
+
+ + Lightning PoS Logo + +
+
+

Let's log you in

+

+ Enter your email, and we'll send you a verification code. We'll create an account for you too if you + don't already have one. +

+ +
-

- Point of Sale System
with Lightning Network -

-
- -
- - - - Lightning - - - NWC (Soon) - - - - { - setInputAddress(e.target.value); - setError(''); - }} - disabled={isValidating} - className={error ? 'border-red-500' : ''} - /> - - {error && ( -
- - {error} -
- )} - - -
- {/* -
- -
- {!!nwc ? ( - - ) : ( - - )} -
-
+ + + + + + + ); +} - {error && ( -
- - {error} -
- )} +function CodeStep({ sentEmail }: { sentEmail: string }) { + const inputRef = React.useRef(null); - -
*/} -
- - {hasCamera && ( -
- or
- )} -
- - {showCameraModal && } - - {/* PWA Install Prompt */} - - - {hasCamera && ( +
+
- - )} -
+ + ); } diff --git a/components/payment/payment-error.tsx b/components/payment/payment-error.tsx index cab9f04..f9e4509 100644 --- a/components/payment/payment-error.tsx +++ b/components/payment/payment-error.tsx @@ -22,7 +22,7 @@ export function PaymentError({ error, amount, currency }: PaymentErrorProps) { return (
-
+
diff --git a/components/settings-pin-page.tsx b/components/settings-pin-page.tsx new file mode 100644 index 0000000..5bf4a3c --- /dev/null +++ b/components/settings-pin-page.tsx @@ -0,0 +1,163 @@ +'use client'; + +import type React from 'react'; +import { useState, useCallback } from 'react'; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import { ChevronLeft, DollarSign, CheckCircle, ArrowUpRight } from 'lucide-react'; + +import { useSettings } from '@/hooks/use-settings'; + +import { AppViewport } from '@/components/app/app-viewport'; +import { AppFooter } from '@/components/app/app-footer'; +import { AppContent } from '@/components/app/app-content'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { LoadingSpinner } from '@/components/ui/loading-spinner'; +import { CTAButton } from '@/components/ui/button-cta'; + +import { AvailableCurrencies } from '@/types/config'; + +export function SettingsPinPage() { + const router = useRouter(); + const { settings, isLoading: settingsLoading, updateCurrency } = useSettings(); + + const [showSaveSuccess, setShowSaveSuccess] = useState(false); + + const currencies = [ + { value: 'ARS', label: 'ARS (Argentine Peso)', symbol: '$' }, + { value: 'USD', label: 'USD (US Dollar)', symbol: '$' }, + // { value: 'EUR', label: 'EUR (Euro)', symbol: '€' }, + ]; + + const showFeedback = (message?: string) => { + setShowSaveSuccess(true); + setTimeout(() => setShowSaveSuccess(false), 2000); + }; + + const handleCurrencyChange = (newCurrency: AvailableCurrencies) => { + updateCurrency(newCurrency); + showFeedback(); + }; + + // Mostrar loading mientras cargan las configuraciones + if (settingsLoading) { + return ( +
+ +
+ ); + } + + return ( + + {/* Header */} +
+
+ +

Set PIN

+ {showSaveSuccess && ( +
+ + Saved +
+ )} +
+
+ + {/* Main Content */} + +
+ {/* Currency Settings */} + + + + Currency + + + + +
+ +
+ Default currency in the system. +
+
+
+
+ + {/* Clear Local Storage */} + {/* + + Clear Storage + + +

+ This will clear all stored data including your Settings, Products, Categories, and Cart. This action + cannot be undone. +

+ +
+
*/} + +
+
Collaborate with us
+ + + +
+ + {/* Additional Settings Placeholder */} + {/* + + Comming Soon + + +

Tips, languages, themes and more.

+
+
*/} + +
+
Advertising
+ + + Support ⚡️ POS from $0.2 + + +
+
+
+ + {/* Back Button */} + +
+ +
+
+
+ ); +} diff --git a/components/ui/app.tsx b/components/ui/app.tsx new file mode 100644 index 0000000..6bb6d58 --- /dev/null +++ b/components/ui/app.tsx @@ -0,0 +1,103 @@ +import React, { useMemo } from 'react'; + +import { useMobileDetection } from '@/hooks/use-mobile-detection'; +import { cn } from '@/lib/utils'; + +export const AppViewport = React.forwardRef>( + ({ className, ...props }, ref) => { + const { isMobile } = useMobileDetection(); + + return ( +
+ {props?.children} +
+ ); + }, +); + +AppViewport.displayName = 'AppViewport'; + +export const AppNavbar = React.forwardRef>( + ({ className, ...props }, ref) => { + const { isMobile } = useMobileDetection(); + + return ( +
+
{props?.children}
+
+ ); + }, +); + +AppNavbar.displayName = 'AppNavbar'; + +export const AppContent = React.forwardRef>( + ({ className, ...props }, ref) => { + const { isMobile, isMobileUserAgent, isMobileScreen, isPWA } = useMobileDetection(); + + const heightStyle = useMemo(() => { + // Special case: Desktop browser with mobile screen width (narrow window) + if (!isMobileUserAgent && isMobileScreen) { + return { height: isPWA ? '90vh' : '88vh' }; + } + + // Mobile devices (actual mobile user agent or mobile screen width) + if (isMobile) { + return { height: isPWA ? '82vh' : '76vh' }; + } + + // Desktop with wide window - use flexbox + return {}; + }, [isMobileUserAgent, isMobileScreen, isMobile, isPWA]); + + return ( +
+ {props?.children} +
+ ); + }, +); + +AppContent.displayName = 'AppContent'; + +export const AppFooter = React.forwardRef>( + ({ className, ...props }, ref) => { + const { isMobile } = useMobileDetection(); + + return ( +
+
{props?.children}
+
+ ); + }, +); + +AppFooter.displayName = 'AppFooter'; diff --git a/components/ui/input-otp.tsx b/components/ui/input-otp.tsx index f66fcfa..dac3ee8 100644 --- a/components/ui/input-otp.tsx +++ b/components/ui/input-otp.tsx @@ -1,71 +1,63 @@ -"use client" +'use client'; -import * as React from "react" -import { OTPInput, OTPInputContext } from "input-otp" -import { Dot } from "lucide-react" +import * as React from 'react'; +import { OTPInput, OTPInputContext } from 'input-otp'; +import { Dot } from 'lucide-react'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; -const InputOTP = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, containerClassName, ...props }, ref) => ( - -)) -InputOTP.displayName = "InputOTP" +const InputOTP = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, containerClassName, ...props }, ref) => ( + + ), +); +InputOTP.displayName = 'InputOTP'; -const InputOTPGroup = React.forwardRef< - React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> ->(({ className, ...props }, ref) => ( -
-)) -InputOTPGroup.displayName = "InputOTPGroup" +const InputOTPGroup = React.forwardRef, React.ComponentPropsWithoutRef<'div'>>( + ({ className, ...props }, ref) =>
, +); +InputOTPGroup.displayName = 'InputOTPGroup'; const InputOTPSlot = React.forwardRef< - React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> & { index: number } + React.ElementRef<'div'>, + React.ComponentPropsWithoutRef<'div'> & { index: number } >(({ index, className, ...props }, ref) => { - const inputOTPContext = React.useContext(OTPInputContext) - const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index] + const inputOTPContext = React.useContext(OTPInputContext); + const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]; return (
{char} {hasFakeCaret && ( -
-
+
+
)}
- ) -}) -InputOTPSlot.displayName = "InputOTPSlot" - -const InputOTPSeparator = React.forwardRef< - React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> ->(({ ...props }, ref) => ( -
- -
-)) -InputOTPSeparator.displayName = "InputOTPSeparator" + ); +}); +InputOTPSlot.displayName = 'InputOTPSlot'; + +const InputOTPSeparator = React.forwardRef, React.ComponentPropsWithoutRef<'div'>>( + ({ ...props }, ref) => ( +
+ +
+ ), +); +InputOTPSeparator.displayName = 'InputOTPSeparator'; -export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } +export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }; diff --git a/config/constants.ts b/config/constants.ts new file mode 100644 index 0000000..81b6301 --- /dev/null +++ b/config/constants.ts @@ -0,0 +1,2 @@ +export const DATABASE_APP_ID = process.env.NEXT_PUBLIC_INSTANTDB_APP_ID || ''; +export const DATABASE_ADMIN_ID = process.env.INSTANTDB_ADMIN_ID || ''; diff --git a/config/database.ts b/config/database.ts new file mode 100644 index 0000000..4c59f16 --- /dev/null +++ b/config/database.ts @@ -0,0 +1,9 @@ +import { init } from '@instantdb/admin'; + +import { DATABASE_ADMIN_ID, DATABASE_APP_ID } from './constants'; + +// Initialize the database +export const db = init({ + appId: DATABASE_APP_ID, + adminToken: DATABASE_ADMIN_ID, +}); diff --git a/config/schema.ts b/config/schema.ts new file mode 100644 index 0000000..a4eb572 --- /dev/null +++ b/config/schema.ts @@ -0,0 +1,34 @@ +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + $users: i.entity({ + email: i.string().unique().indexed(), + }), + stores: i.entity({ + id: i.string().unique().indexed(), + // Status + status: i.string(), + updated_at: i.date(), + created_at: i.date(), + }), + }, + links: { + // userStores: { + // forward: { on: 'stores', has: 'one', label: '$user' }, + // reverse: { on: '$users', has: 'many', label: 'stores' }, + // }, + // storeProducts: { + // forward: { on: 'products', has: 'one', label: 'store' }, + // reverse: { on: 'stores', has: 'many', label: 'products' }, + // }, + }, +}); + +// This helps Typescript display better intellisense +type _AppSchema = typeof _schema; +interface AppSchema extends _AppSchema {} +const schema: AppSchema = _schema; + +export type { AppSchema }; +export default schema; diff --git a/context/auth.tsx b/context/auth.tsx index f1d8054..dbe7a1e 100644 --- a/context/auth.tsx +++ b/context/auth.tsx @@ -338,9 +338,9 @@ export function AuthProvider({ children }: AuthProviderProps) { }); }, [state.isInitialized]); - if (state.isLoading) { - return
Loading...
; - } + // if (state.isLoading) { + // return
Loading...
; + // } const contextValue: AuthContextType = { ...state, diff --git a/context/error.tsx b/context/error.tsx new file mode 100644 index 0000000..7544b1b --- /dev/null +++ b/context/error.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { createContext, useCallback, useEffect, useState } from 'react'; + +// Interface +export interface ErrorContext { + isAvailable: boolean; +} + +// Context +export const ErrorContext = createContext({ + isAvailable: false, +}); + +interface ErrorProviderProps { + children: React.ReactNode; +} + +export const ErrorProvider = ({ children }: ErrorProviderProps) => { + const [isAvailable, setIsAvailable] = useState(false); + + useEffect(() => { + setIsAvailable(true); + }, []); + + return {children}; +}; diff --git a/lib/database.ts b/lib/database.ts new file mode 100644 index 0000000..b077ed2 --- /dev/null +++ b/lib/database.ts @@ -0,0 +1,8 @@ +import { init, User } from '@instantdb/react'; + +import { DATABASE_APP_ID } from '@/config/constants'; + +// Initialize the database +export const db = init({ + appId: DATABASE_APP_ID, +}); diff --git a/lib/instantdb.ts b/lib/instantdb.ts index 4610c97..5bea4b3 100644 --- a/lib/instantdb.ts +++ b/lib/instantdb.ts @@ -1,7 +1,7 @@ -import { init, tx, id } from '@instantdb/react' +import { init, tx, id } from '@instantdb/react'; // Configuración de InstantDB -const APP_ID = process.env.NEXT_PUBLIC_INSTANTDB_APP_ID || 'your-app-id' +const APP_ID = process.env.NEXT_PUBLIC_INSTANTDB_APP_ID || 'your-app-id'; // Schema para los diferentes tipos de eventos export const schema = { @@ -152,150 +152,150 @@ export const schema = { browser: 'string?', is_pwa: 'boolean', user_agent: 'string?', - } -} + }, +}; // Inicializar InstantDB export const db = init({ appId: APP_ID, - schema -}) + // schema +}); // Tipos TypeScript para los eventos export type CategoryEvent = { - id: string - event_type: 'created' | 'updated' | 'deleted' | 'reordered' - category_id: string - category_name: string - old_values?: any - new_values?: any - timestamp: number - session_id: string - user_agent?: string -} + id: string; + event_type: 'created' | 'updated' | 'deleted' | 'reordered'; + category_id: string; + category_name: string; + old_values?: any; + new_values?: any; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type ProductEvent = { - id: string - event_type: 'created' | 'updated' | 'deleted' | 'reordered' - product_id: string - product_name: string - category_id: string - price?: number - old_values?: any - new_values?: any - timestamp: number - session_id: string - user_agent?: string -} + id: string; + event_type: 'created' | 'updated' | 'deleted' | 'reordered'; + product_id: string; + product_name: string; + category_id: string; + price?: number; + old_values?: any; + new_values?: any; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type CartEvent = { - id: string - event_type: 'item_added' | 'item_removed' | 'quantity_updated' | 'cleared' - product_id: string - product_name: string - quantity?: number - price?: number - timestamp: number - session_id: string - user_agent?: string -} + id: string; + event_type: 'item_added' | 'item_removed' | 'quantity_updated' | 'cleared'; + product_id: string; + product_name: string; + quantity?: number; + price?: number; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type ShopSale = { - id: string - sale_id: string - items: any[] - subtotal: number - total: number - currency: string - payment_method: string - lightning_address?: string - operator_lightning_address?: string - timestamp: number - session_id: string - user_agent?: string -} + id: string; + sale_id: string; + items: any[]; + subtotal: number; + total: number; + currency: string; + payment_method: string; + lightning_address?: string; + operator_lightning_address?: string; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type PaydeskSale = { - id: string - sale_id: string - amount: number - currency: string - amount_sats?: number - payment_method: string - lightning_address?: string - operator_lightning_address?: string - timestamp: number - session_id: string - user_agent?: string -} + id: string; + sale_id: string; + amount: number; + currency: string; + amount_sats?: number; + payment_method: string; + lightning_address?: string; + operator_lightning_address?: string; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type SettingsEvent = { - id: string - event_type: 'currency_changed' | 'operator_address_updated' | 'language_changed' - setting_key: string - old_value?: string - new_value: string - timestamp: number - session_id: string - user_agent?: string -} + id: string; + event_type: 'currency_changed' | 'operator_address_updated' | 'language_changed'; + setting_key: string; + old_value?: string; + new_value: string; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type AuthEvent = { - id: string - event_type: 'login' | 'logout' | 'validation_failed' - lightning_address?: string - success: boolean - error_message?: string - timestamp: number - session_id: string - user_agent?: string -} + id: string; + event_type: 'login' | 'logout' | 'validation_failed'; + lightning_address?: string; + success: boolean; + error_message?: string; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type NavigationEvent = { - id: string - event_type: 'page_view' | 'button_click' | 'modal_open' | 'modal_close' - page: string - component?: string - action?: string - timestamp: number - session_id: string - user_agent?: string -} + id: string; + event_type: 'page_view' | 'button_click' | 'modal_open' | 'modal_close'; + page: string; + component?: string; + action?: string; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type ErrorEvent = { - id: string - error_type: string - error_message: string - stack_trace?: string - component?: string - user_action?: string - timestamp: number - session_id: string - user_agent?: string -} + id: string; + error_type: string; + error_message: string; + stack_trace?: string; + component?: string; + user_action?: string; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type PerformanceEvent = { - id: string - metric_type: 'page_load' | 'api_call' | 'db_operation' - duration: number - page?: string - operation?: string - success: boolean - timestamp: number - session_id: string - user_agent?: string -} + id: string; + metric_type: 'page_load' | 'api_call' | 'db_operation'; + duration: number; + page?: string; + operation?: string; + success: boolean; + timestamp: number; + session_id: string; + user_agent?: string; +}; export type UserSession = { - id: string - session_id: string - lightning_address?: string - start_time: number - end_time?: number - page_views: number - actions_count: number - device_type?: 'mobile' | 'desktop' | 'tablet' - browser?: string - is_pwa: boolean - user_agent?: string -} \ No newline at end of file + id: string; + session_id: string; + lightning_address?: string; + start_time: number; + end_time?: number; + page_views: number; + actions_count: number; + device_type?: 'mobile' | 'desktop' | 'tablet'; + browser?: string; + is_pwa: boolean; + user_agent?: string; +}; diff --git a/package.json b/package.json index 19b3e22..e5a3b0c 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,11 @@ "@getalby/lightning-tools": "^5.2.0", "@getalby/sdk": "^5.1.0", "@hookform/resolvers": "^3.9.1", - "@instantdb/react": "^0.12.19", + "@instantdb/admin": "^0.22.13", + "@instantdb/core": "^0.22.13", + "@instantdb/react": "^0.12.37", "@next/third-parties": "^15.4.1", + "@noble/hashes": "^2.0.1", "@radix-ui/react-accordion": "1.2.2", "@radix-ui/react-alert-dialog": "1.1.4", "@radix-ui/react-aspect-ratio": "1.1.1", @@ -44,6 +47,7 @@ "@radix-ui/react-tooltip": "1.1.6", "autoprefixer": "^10.4.20", "axios": "^1.9.0", + "better-auth": "^1.3.27", "bolt11": "^1.4.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de93d52..9802722 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,21 @@ dependencies: '@hookform/resolvers': specifier: ^3.9.1 version: 3.10.0(react-hook-form@7.56.4) + '@instantdb/admin': + specifier: ^0.22.13 + version: 0.22.13 + '@instantdb/core': + specifier: ^0.22.13 + version: 0.22.13 '@instantdb/react': - specifier: ^0.12.19 + specifier: ^0.12.37 version: 0.12.37(react@19.1.0) '@next/third-parties': specifier: ^15.4.1 version: 15.4.1(next@15.2.4)(react@19.1.0) + '@noble/hashes': + specifier: ^2.0.1 + version: 2.0.1 '@radix-ui/react-accordion': specifier: 1.2.2 version: 1.2.2(@types/react-dom@19.1.5)(@types/react@19.1.8)(react-dom@19.1.0)(react@19.1.0) @@ -110,6 +119,9 @@ dependencies: axios: specifier: ^1.9.0 version: 1.9.0 + better-auth: + specifier: ^1.3.27 + version: 1.3.27(next@15.2.4)(react-dom@19.1.0)(react@19.1.0) bolt11: specifier: ^1.4.1 version: 1.4.1 @@ -251,6 +263,21 @@ packages: engines: {node: '>=6.9.0'} dev: false + /@better-auth/core@1.3.27: + resolution: {integrity: sha512-3Sfdax6MQyronY+znx7bOsfQHI6m1SThvJWb0RDscFEAhfqLy95k1sl+/PgGyg0cwc2cUXoEiAOSqYdFYrg3vA==} + dependencies: + better-call: 1.0.19 + zod: 4.1.12 + dev: false + + /@better-auth/utils@0.3.0: + resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} + dev: false + + /@better-fetch/fetch@1.1.18: + resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==} + dev: false + /@emnapi/runtime@1.4.3: resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} requiresBuild: true @@ -326,6 +353,10 @@ packages: - typescript dev: false + /@hexagon/base64@1.1.28: + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + dev: false + /@hookform/resolvers@3.10.0(react-hook-form@7.56.4): resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} peerDependencies: @@ -514,6 +545,14 @@ packages: dev: false optional: true + /@instantdb/admin@0.22.13: + resolution: {integrity: sha512-zS3jfIAnY3SCxDLAtLattaKl2riJUOLWqXa+0PhV4Cry8C3XIkrkJNpeO7FN8ds48MElkROWQYLJatxn+74JVA==} + dependencies: + '@instantdb/core': 0.22.13 + '@instantdb/version': 0.22.13 + eventsource: 4.0.0 + dev: false + /@instantdb/core@0.12.37: resolution: {integrity: sha512-wStIvLXYlL78o7+tJ+ztSFa+c+ikJY4fDg8ru/2Q+BhZJf+niy+d/Ig+tfZwGDrD6AP1hDYiQdNIFGMjqZhozw==} dependencies: @@ -522,6 +561,14 @@ packages: uuid: 9.0.1 dev: false + /@instantdb/core@0.22.13: + resolution: {integrity: sha512-FQJIx2xrOMbXqpWb8zKuJAB0DPVA4S1FVBSOMCkVgoBD4+HSxoWoIffp5uTVPSt2yAQsi2jQWzTd5b7KgvpSZA==} + dependencies: + '@instantdb/version': 0.22.13 + mutative: 1.3.0 + uuid: 11.1.0 + dev: false + /@instantdb/react@0.12.37(react@19.1.0): resolution: {integrity: sha512-eBECC7lD+vWUdVcyylmIOlwRa1PHCW0F25am3p5/LwN8BscUQD+nSJvKgoRp+M3cUjIkfzfHMRfofjuq4sYdMQ==} peerDependencies: @@ -531,6 +578,10 @@ packages: react: 19.1.0 dev: false + /@instantdb/version@0.22.13: + resolution: {integrity: sha512-0Ex0nGd7/xH0RPRQykaPtsXt0NhQm2ehqZmjCGzhW3smGDA3ivOS6F1hYoU5RWddZ1iv/gjKYtOPb+Y5En3UKw==} + dev: false + /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -567,6 +618,10 @@ packages: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + /@levischuck/tiny-cbor@0.2.11: + resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + dev: false + /@lightninglabs/lnc-core@0.3.2-alpha: resolution: {integrity: sha512-H6tG+X9txCIdxTR+GPsbImzP2Juo+6Uvq/Ipaijd7xPISzgEU4J4GNE5PEHuIZqbnBo1RmpuXnFG6dmsl3PTzQ==} dev: false @@ -669,6 +724,11 @@ packages: resolution: {integrity: sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==} dev: false + /@noble/ciphers@2.0.1: + resolution: {integrity: sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g==} + engines: {node: '>= 20.19.0'} + dev: false + /@noble/curves@1.1.0: resolution: {integrity: sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==} dependencies: @@ -696,6 +756,11 @@ packages: engines: {node: ^14.21.3 || >=16} dev: false + /@noble/hashes@2.0.1: + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -714,6 +779,126 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + /@peculiar/asn1-android@2.5.0: + resolution: {integrity: sha512-t8A83hgghWQkcneRsgGs2ebAlRe54ns88p7ouv8PW2tzF1nAW4yHcL4uZKrFpIU+uszIRzTkcCuie37gpkId0A==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-cms@2.5.0: + resolution: {integrity: sha512-p0SjJ3TuuleIvjPM4aYfvYw8Fk1Hn/zAVyPJZTtZ2eE9/MIer6/18ROxX6N/e6edVSfvuZBqhxAj3YgsmSjQ/A==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + '@peculiar/asn1-x509-attr': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-csr@2.5.0: + resolution: {integrity: sha512-ioigvA6WSYN9h/YssMmmoIwgl3RvZlAYx4A/9jD2qaqXZwGcNlAxaw54eSx2QG1Yu7YyBC5Rku3nNoHrQ16YsQ==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-ecc@2.5.0: + resolution: {integrity: sha512-t4eYGNhXtLRxaP50h3sfO6aJebUCDGQACoeexcelL4roMFRRVgB20yBIu2LxsPh/tdW9I282gNgMOyg3ywg/mg==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-pfx@2.5.0: + resolution: {integrity: sha512-Vj0d0wxJZA+Ztqfb7W+/iu8Uasw6hhKtCdLKXLG/P3kEPIQpqGI4P4YXlROfl7gOCqFIbgsj1HzFIFwQ5s20ug==} + dependencies: + '@peculiar/asn1-cms': 2.5.0 + '@peculiar/asn1-pkcs8': 2.5.0 + '@peculiar/asn1-rsa': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-pkcs8@2.5.0: + resolution: {integrity: sha512-L7599HTI2SLlitlpEP8oAPaJgYssByI4eCwQq2C9eC90otFpm8MRn66PpbKviweAlhinWQ3ZjDD2KIVtx7PaVw==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-pkcs9@2.5.0: + resolution: {integrity: sha512-UgqSMBLNLR5TzEZ5ZzxR45Nk6VJrammxd60WMSkofyNzd3DQLSNycGWSK5Xg3UTYbXcDFyG8pA/7/y/ztVCa6A==} + dependencies: + '@peculiar/asn1-cms': 2.5.0 + '@peculiar/asn1-pfx': 2.5.0 + '@peculiar/asn1-pkcs8': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + '@peculiar/asn1-x509-attr': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-rsa@2.5.0: + resolution: {integrity: sha512-qMZ/vweiTHy9syrkkqWFvbT3eLoedvamcUdnnvwyyUNv5FgFXA3KP8td+ATibnlZ0EANW5PYRm8E6MJzEB/72Q==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-schema@2.5.0: + resolution: {integrity: sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ==} + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-x509-attr@2.5.0: + resolution: {integrity: sha512-9f0hPOxiJDoG/bfNLAFven+Bd4gwz/VzrCIIWc1025LEI4BXO0U5fOCTNDPbbp2ll+UzqKsZ3g61mpBp74gk9A==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + dev: false + + /@peculiar/asn1-x509@2.5.0: + resolution: {integrity: sha512-CpwtMCTJvfvYTFMuiME5IH+8qmDe3yEWzKHe7OOADbGfq7ohxeLaXwQo0q4du3qs0AII3UbLCvb9NF/6q0oTKQ==} + dependencies: + '@peculiar/asn1-schema': 2.5.0 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + dev: false + + /@peculiar/x509@1.14.0: + resolution: {integrity: sha512-Yc4PDxN3OrxUPiXgU63c+ZRXKGE8YKF2McTciYhUHFtHVB0KMnjeFSU0qpztGhsp4P0uKix4+J2xEpIEDu8oXg==} + dependencies: + '@peculiar/asn1-cms': 2.5.0 + '@peculiar/asn1-csr': 2.5.0 + '@peculiar/asn1-ecc': 2.5.0 + '@peculiar/asn1-pkcs9': 2.5.0 + '@peculiar/asn1-rsa': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + dev: false + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1963,17 +2148,35 @@ packages: resolution: {integrity: sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==} dependencies: '@noble/curves': 1.1.0 - '@noble/hashes': 1.3.1 + '@noble/hashes': 1.3.2 '@scure/base': 1.1.1 dev: false /@scure/bip39@1.2.1: resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} dependencies: - '@noble/hashes': 1.3.1 + '@noble/hashes': 1.3.2 '@scure/base': 1.1.1 dev: false + /@simplewebauthn/browser@13.2.2: + resolution: {integrity: sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==} + dev: false + + /@simplewebauthn/server@13.2.2: + resolution: {integrity: sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA==} + engines: {node: '>=20.0.0'} + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.11 + '@peculiar/asn1-android': 2.5.0 + '@peculiar/asn1-ecc': 2.5.0 + '@peculiar/asn1-rsa': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + '@peculiar/x509': 1.14.0 + dev: false + /@smithy/is-array-buffer@2.2.0: resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} @@ -2121,6 +2324,15 @@ packages: tslib: 2.8.1 dev: false + /asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.3 + tslib: 2.8.1 + dev: false + /assert@2.1.0: resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} dependencies: @@ -2187,6 +2399,63 @@ packages: resolution: {integrity: sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==} dev: false + /better-auth@1.3.27(next@15.2.4)(react-dom@19.1.0)(react@19.1.0): + resolution: {integrity: sha512-SwiGAJ7yU6dBhNg0NdV1h5M8T5sa7/AszZVc4vBfMDrLLmvUfbt9JoJ0uRUJUEdKRAAxTyl9yA+F3+GhtAD80w==} + peerDependencies: + '@lynx-js/react': '*' + '@sveltejs/kit': '*' + next: '*' + react: '*' + react-dom: '*' + solid-js: '*' + svelte: '*' + vue: '*' + peerDependenciesMeta: + '@lynx-js/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vue: + optional: true + dependencies: + '@better-auth/core': 1.3.27 + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + '@noble/ciphers': 2.0.1 + '@noble/hashes': 2.0.1 + '@simplewebauthn/browser': 13.2.2 + '@simplewebauthn/server': 13.2.2 + better-call: 1.0.19 + defu: 6.1.4 + jose: 6.1.0 + kysely: 0.28.8 + nanostores: 1.0.1 + next: 15.2.4(react-dom@19.1.0)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + zod: 4.1.12 + dev: false + + /better-call@1.0.19: + resolution: {integrity: sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw==} + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.18 + rou3: 0.5.1 + set-cookie-parser: 2.7.1 + uncrypto: 0.1.3 + dev: false + /binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -2543,6 +2812,10 @@ packages: object-keys: 1.1.1 dev: false + /defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dev: false + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2664,6 +2937,18 @@ packages: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} dev: false + /eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + dev: false + + /eventsource@4.0.0: + resolution: {integrity: sha512-fvIkb9qZzdMxgZrEQDyll+9oJsyaVvY92I2Re+qK0qEJ+w5s0X3dtz+M0VAPOjP1gtU3iqWyjQ0G3nvd5CLZ2g==} + engines: {node: '>=20.0.0'} + dependencies: + eventsource-parser: 3.0.6 + dev: false + /fast-equals@5.2.2: resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==} engines: {node: '>=6.0.0'} @@ -2980,6 +3265,10 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + /jose@6.1.0: + resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==} + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: false @@ -2988,6 +3277,11 @@ packages: resolution: {integrity: sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==} dev: false + /kysely@0.28.8: + resolution: {integrity: sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA==} + engines: {node: '>=20.0.0'} + dev: false + /lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -3108,6 +3402,11 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + /mutative@1.3.0: + resolution: {integrity: sha512-8MJj6URmOZAV70dpFe1YnSppRTKC4DsMkXQiBDFayLcDI4ljGokHxmpqaBQuDWa4iAxWaJJ1PS8vAmbntjjKmQ==} + engines: {node: '>=14.0'} + dev: false + /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} dependencies: @@ -3120,6 +3419,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nanostores@1.0.1: + resolution: {integrity: sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==} + engines: {node: ^20.0.0 || >=22.0.0} + dev: false + /next-themes@0.4.6(react-dom@19.1.0)(react@19.1.0): resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} peerDependencies: @@ -3399,6 +3703,17 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false + /pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + dependencies: + tslib: 2.8.1 + dev: false + + /pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + dev: false + /qr.js@0.0.0: resolution: {integrity: sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==} dev: false @@ -3604,6 +3919,10 @@ packages: victory-vendor: 36.9.2 dev: false + /reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + dev: false + /resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} @@ -3624,6 +3943,10 @@ packages: inherits: 2.0.4 dev: false + /rou3@0.5.1: + resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==} + dev: false + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -3664,6 +3987,10 @@ packages: dev: false optional: true + /set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + dev: false + /set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3910,10 +4237,21 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: false + /tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} dev: false + /tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + dependencies: + tslib: 1.14.1 + dev: false + /typeforce@1.18.0: resolution: {integrity: sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==} dev: false @@ -3923,6 +4261,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + /uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + dev: false + /undici-types@7.8.0: resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} @@ -3997,6 +4339,11 @@ packages: which-typed-array: 1.1.19 dev: false + /uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + dev: false + /uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true @@ -4091,6 +4438,10 @@ packages: resolution: {integrity: sha512-PcALTLskaucbeHc41tU/xfjfhcz8z0GdhhDcSgrCTmSazUuqnYqiXO63M0QUBVwpBlsLsNVn5qHSC5Dw3KZvaQ==} dev: false + /zod@4.1.12: + resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + dev: false + /zustand@4.5.7(@types/react@19.1.8)(react@19.1.0): resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} engines: {node: '>=12.7.0'}