diff --git a/apps/admin-dashboard/.prettierignore b/apps/admin-dashboard/.prettierignore
deleted file mode 100644
index 0b4a1db..0000000
--- a/apps/admin-dashboard/.prettierignore
+++ /dev/null
@@ -1,7 +0,0 @@
-node_modules/
-coverage/
-.pnpm-store/
-pnpm-lock.yaml
-package-lock.json
-pnpm-lock.yaml
-yarn.lock
diff --git a/apps/admin-dashboard/.prettierrc b/apps/admin-dashboard/.prettierrc
deleted file mode 100644
index 9000bfa..0000000
--- a/apps/admin-dashboard/.prettierrc
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "endOfLine": "lf",
- "semi": false,
- "singleQuote": false,
- "tabWidth": 2,
- "trailingComma": "es5",
- "printWidth": 80,
- "plugins": ["prettier-plugin-tailwindcss"],
- "tailwindStylesheet": "src/index.css",
- "tailwindFunctions": ["cn", "cva"]
-}
diff --git a/apps/admin-dashboard/components.json b/apps/admin-dashboard/components.json
index 498a385..c2f1bde 100644
--- a/apps/admin-dashboard/components.json
+++ b/apps/admin-dashboard/components.json
@@ -1,25 +1,25 @@
{
- "$schema": "https://ui.shadcn.com/schema.json",
- "style": "radix-mira",
- "rsc": false,
- "tsx": true,
- "tailwind": {
- "config": "",
- "css": "src/index.css",
- "baseColor": "neutral",
- "cssVariables": true,
- "prefix": ""
- },
- "iconLibrary": "lucide",
- "rtl": false,
- "aliases": {
- "components": "@/components",
- "utils": "@/lib/utils",
- "ui": "@/components/ui",
- "lib": "@/lib",
- "hooks": "@/hooks"
- },
- "menuColor": "default",
- "menuAccent": "subtle",
- "registries": {}
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "radix-mira",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/index.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "iconLibrary": "lucide",
+ "rtl": false,
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "menuColor": "default",
+ "menuAccent": "subtle",
+ "registries": {}
}
diff --git a/apps/admin-dashboard/eslint.config.js b/apps/admin-dashboard/eslint.config.js
deleted file mode 100644
index 5e6b472..0000000
--- a/apps/admin-dashboard/eslint.config.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import js from '@eslint/js'
-import globals from 'globals'
-import reactHooks from 'eslint-plugin-react-hooks'
-import reactRefresh from 'eslint-plugin-react-refresh'
-import tseslint from 'typescript-eslint'
-import { defineConfig, globalIgnores } from 'eslint/config'
-
-export default defineConfig([
- globalIgnores(['dist']),
- {
- files: ['**/*.{ts,tsx}'],
- extends: [
- js.configs.recommended,
- tseslint.configs.recommended,
- reactHooks.configs.flat.recommended,
- reactRefresh.configs.vite,
- ],
- languageOptions: {
- ecmaVersion: 2020,
- globals: globals.browser,
- },
- },
-])
diff --git a/apps/admin-dashboard/index.html b/apps/admin-dashboard/index.html
index 1f738fe..cc2efb1 100644
--- a/apps/admin-dashboard/index.html
+++ b/apps/admin-dashboard/index.html
@@ -1,13 +1,13 @@
-
-
-
-
- vite-app
-
-
-
-
-
+
+
+
+
+ vite-app
+
+
+
+
+
diff --git a/apps/admin-dashboard/package.json b/apps/admin-dashboard/package.json
index a862eb4..009fc0d 100644
--- a/apps/admin-dashboard/package.json
+++ b/apps/admin-dashboard/package.json
@@ -1,48 +1,40 @@
{
- "name": "admin-dashboard",
- "private": true,
- "version": "0.0.1",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "tsc -b && vite build",
- "lint": "eslint .",
- "format": "prettier --write \"**/*.{ts,tsx}\"",
- "typecheck": "tsc --noEmit",
- "preview": "vite preview"
- },
- "dependencies": {
- "@fontsource-variable/inter": "^5.2.8",
- "@tailwindcss/vite": "^4.1.17",
- "@tanstack/react-query": "^5.95.0",
- "@tanstack/react-router": "^1.168.2",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "lucide-react": "^0.577.0",
- "next-themes": "^0.4.6",
- "radix-ui": "^1.4.3",
- "react": "^19.2.0",
- "react-dom": "^19.2.0",
- "shadcn": "^4.0.8",
- "sonner": "^2.0.7",
- "tailwind-merge": "^3.5.0",
- "tailwindcss": "^4.1.17",
- "tw-animate-css": "^1.4.0"
- },
- "devDependencies": {
- "@eslint/js": "^9.39.1",
- "@types/node": "^24.10.1",
- "@types/react": "^19.2.5",
- "@types/react-dom": "^19.2.3",
- "@vitejs/plugin-react": "^5.1.1",
- "eslint": "^9.39.1",
- "eslint-plugin-react-hooks": "^7.0.1",
- "eslint-plugin-react-refresh": "^0.4.24",
- "globals": "^16.5.0",
- "prettier": "^3.8.1",
- "prettier-plugin-tailwindcss": "^0.7.2",
- "typescript": "~5.9.3",
- "typescript-eslint": "^8.46.4",
- "vite": "^7.2.4"
- }
+ "name": "admin-dashboard",
+ "version": "0.0.1",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "oxlint .",
+ "format": "oxfmt --write .",
+ "typecheck": "tsc --noEmit",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@fontsource-variable/inter": "^5.2.8",
+ "@tailwindcss/vite": "^4.1.17",
+ "@tanstack/react-query": "^5.95.0",
+ "@tanstack/react-router": "^1.168.2",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.577.0",
+ "next-themes": "^0.4.6",
+ "radix-ui": "^1.4.3",
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0",
+ "shadcn": "^4.0.8",
+ "sonner": "^2.0.7",
+ "tailwind-merge": "^3.5.0",
+ "tailwindcss": "^4.1.17",
+ "tw-animate-css": "^1.4.0"
+ },
+ "devDependencies": {
+ "@types/node": "^24.10.1",
+ "@types/react": "^19.2.5",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^5.1.1",
+ "typescript": "~5.9.3",
+ "vite": "^7.2.4"
+ }
}
diff --git a/apps/admin-dashboard/src/App.tsx b/apps/admin-dashboard/src/App.tsx
index 6db194c..c4bc6f0 100644
--- a/apps/admin-dashboard/src/App.tsx
+++ b/apps/admin-dashboard/src/App.tsx
@@ -1,25 +1,25 @@
-import { createRouter, RouterProvider } from "@tanstack/react-router"
import { useQueryClient, type QueryClient } from "@tanstack/react-query"
+import { createRouter, RouterProvider } from "@tanstack/react-router"
import { routeTree } from "./route-tree.gen"
const router = createRouter({
- routeTree,
- defaultPreload: "intent",
- context: {
- queryClient: undefined! as QueryClient,
- },
+ routeTree,
+ defaultPreload: "intent",
+ context: {
+ queryClient: undefined! as QueryClient,
+ },
})
declare module "@tanstack/react-router" {
- interface Register {
- router: typeof router
- }
+ interface Register {
+ router: typeof router
+ }
}
export function App() {
- const queryClient = useQueryClient()
- return
+ const queryClient = useQueryClient()
+ return
}
export default App
diff --git a/apps/admin-dashboard/src/components/feed-panel.tsx b/apps/admin-dashboard/src/components/feed-panel.tsx
index 5a28a87..ff8ddad 100644
--- a/apps/admin-dashboard/src/components/feed-panel.tsx
+++ b/apps/admin-dashboard/src/components/feed-panel.tsx
@@ -1,146 +1,144 @@
import { useQuery } from "@tanstack/react-query"
-import { useState } from "react"
import { Loader2, RefreshCw, TriangleAlert } from "lucide-react"
+import { useState } from "react"
import type { FeedItem } from "@/lib/api"
-import { fetchFeed } from "@/lib/api"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { fetchFeed } from "@/lib/api"
export function FeedPanel() {
- const {
- data: feed,
- error: feedError,
- isFetching,
- refetch,
- } = useQuery({
- queryKey: ["feed"],
- queryFn: fetchFeed,
- enabled: false,
- })
+ const {
+ data: feed,
+ error: feedError,
+ isFetching,
+ refetch,
+ } = useQuery({
+ queryKey: ["feed"],
+ queryFn: fetchFeed,
+ enabled: false,
+ })
- const error = feedError?.message ?? null
+ const error = feedError?.message ?? null
- return (
-
-
-
-
Feed
-
- Query the feed as the current user.
-
-
-
-
+ return (
+
+
+
+
Feed
+
Query the feed as the current user.
+
+
+
- {error && (
-
-
-
- {error}
-
-
- )}
+ {error && (
+
+
+
+ {error}
+
+
+ )}
- {feed && feed.errors.length > 0 && (
-
-
- Source Errors
-
-
- {feed.errors.map((e) => (
-
-
- {e.sourceId}
-
- {e.error}
-
- ))}
-
-
- )}
+ {feed && feed.errors.length > 0 && (
+
+
+ Source Errors
+
+
+ {feed.errors.map((e) => (
+
+
+ {e.sourceId}
+
+ {e.error}
+
+ ))}
+
+
+ )}
- {feed && (
-
-
- {feed.items.length} {feed.items.length === 1 ? "item" : "items"}
-
- {feed.items.length === 0 && (
-
No items in feed.
- )}
- {feed.items.map((item) => (
-
- ))}
-
- )}
-
- )
+ {feed && (
+
+
+ {feed.items.length} {feed.items.length === 1 ? "item" : "items"}
+
+ {feed.items.length === 0 && (
+
No items in feed.
+ )}
+ {feed.items.map((item) => (
+
+ ))}
+
+ )}
+
+ )
}
function FeedItemCard({ item }: { item: FeedItem }) {
- const [expanded, setExpanded] = useState(false)
+ const [expanded, setExpanded] = useState(false)
- return (
-
-
-
-
- {item.type}
-
- {item.sourceId}
-
-
-
- {item.signals?.timeRelevance && (
-
- {item.signals.timeRelevance}
-
- )}
- {item.signals?.urgency !== undefined && (
-
- urgency: {item.signals.urgency}
-
- )}
-
-
- {item.id}
-
-
- {item.slots && Object.keys(item.slots).length > 0 && (
-
- {Object.entries(item.slots).map(([name, slot]) => (
-
- {name}:
-
- {slot.content ?? pending}
-
-
- ))}
-
- )}
-
- {expanded && (
-
- {JSON.stringify(item.data, null, 2)}
-
- )}
-
-
- )
+ return (
+
+
+
+
+ {item.type}
+
+ {item.sourceId}
+
+
+
+ {item.signals?.timeRelevance && (
+
+ {item.signals.timeRelevance}
+
+ )}
+ {item.signals?.urgency !== undefined && (
+
+ urgency: {item.signals.urgency}
+
+ )}
+
+
+ {item.id}
+
+
+ {item.slots && Object.keys(item.slots).length > 0 && (
+
+ {Object.entries(item.slots).map(([name, slot]) => (
+
+ {name}:
+
+ {slot.content ?? pending}
+
+
+ ))}
+
+ )}
+
+ {expanded && (
+
+ {JSON.stringify(item.data, null, 2)}
+
+ )}
+
+
+ )
}
diff --git a/apps/admin-dashboard/src/components/general-settings-panel.tsx b/apps/admin-dashboard/src/components/general-settings-panel.tsx
index 4fe74b2..7190418 100644
--- a/apps/admin-dashboard/src/components/general-settings-panel.tsx
+++ b/apps/admin-dashboard/src/components/general-settings-panel.tsx
@@ -1,75 +1,70 @@
import { useQuery } from "@tanstack/react-query"
import { CircleCheck, CircleX, Loader2 } from "lucide-react"
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { getServerUrl } from "@/lib/server-url"
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
-
async function checkHealth(serverUrl: string): Promise {
- const res = await fetch(`${serverUrl}/health`)
- if (!res.ok) throw new Error(`HTTP ${res.status}`)
- const data = (await res.json()) as { status: string }
- if (data.status !== "ok") throw new Error("Unexpected response")
- return true
+ const res = await fetch(`${serverUrl}/health`)
+ if (!res.ok) throw new Error(`HTTP ${res.status}`)
+ const data = (await res.json()) as { status: string }
+ if (data.status !== "ok") throw new Error("Unexpected response")
+ return true
}
export function GeneralSettingsPanel() {
- const serverUrl = getServerUrl()
+ const serverUrl = getServerUrl()
- const { isLoading, isError, error } = useQuery({
- queryKey: ["health", serverUrl],
- queryFn: () => checkHealth(serverUrl),
- })
+ const { isLoading, isError, error } = useQuery({
+ queryKey: ["health", serverUrl],
+ queryFn: () => checkHealth(serverUrl),
+ })
- const status = isLoading ? "checking" : isError ? "error" : "ok"
- const errorMsg = error instanceof Error ? error.message : null
+ const status = isLoading ? "checking" : isError ? "error" : "ok"
+ const errorMsg = error instanceof Error ? error.message : null
- return (
-
-
-
General
-
- Backend server information.
-
-
+ return (
+
+
+
General
+
Backend server information.
+
-
-
- Server
-
- Connected backend instance.
-
-
-
-
-
- URL
- {serverUrl}
-
-
- Status
- {status === "checking" && (
-
-
- Checking…
-
- )}
- {status === "ok" && (
-
-
- Connected
-
- )}
- {status === "error" && (
-
-
- {errorMsg ?? "Unreachable"}
-
- )}
-
-
-
-
-
- )
+
+
+ Server
+ Connected backend instance.
+
+
+
+
+ URL
+ {serverUrl}
+
+
+ Status
+ {status === "checking" && (
+
+
+ Checking…
+
+ )}
+ {status === "ok" && (
+
+
+ Connected
+
+ )}
+ {status === "error" && (
+
+
+ {errorMsg ?? "Unreachable"}
+
+ )}
+
+
+
+
+
+ )
}
diff --git a/apps/admin-dashboard/src/components/login-page.tsx b/apps/admin-dashboard/src/components/login-page.tsx
index 3260c50..ef94b60 100644
--- a/apps/admin-dashboard/src/components/login-page.tsx
+++ b/apps/admin-dashboard/src/components/login-page.tsx
@@ -1,100 +1,98 @@
import { useMutation } from "@tanstack/react-query"
-import { useState } from "react"
import { Loader2, Settings2 } from "lucide-react"
+import { useState } from "react"
import { toast } from "sonner"
import type { AuthSession } from "@/lib/auth"
-import { signIn } from "@/lib/auth"
-import { getServerUrl, setServerUrl } from "@/lib/server-url"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
+import { signIn } from "@/lib/auth"
+import { getServerUrl, setServerUrl } from "@/lib/server-url"
interface LoginPageProps {
- onLogin: (session: AuthSession) => void
+ onLogin: (session: AuthSession) => void
}
export function LoginPage({ onLogin }: LoginPageProps) {
- const [serverUrlInput, setServerUrlInput] = useState(getServerUrl)
- const [email, setEmail] = useState("")
- const [password, setPassword] = useState("")
+ const [serverUrlInput, setServerUrlInput] = useState(getServerUrl)
+ const [email, setEmail] = useState("")
+ const [password, setPassword] = useState("")
- const loginMutation = useMutation({
- mutationFn: async () => {
- setServerUrl(serverUrlInput)
- return signIn(email, password)
- },
- onSuccess(session) {
- onLogin(session)
- },
- onError(err) {
- toast.error(err.message)
- },
- })
+ const loginMutation = useMutation({
+ mutationFn: async () => {
+ setServerUrl(serverUrlInput)
+ return signIn(email, password)
+ },
+ onSuccess(session) {
+ onLogin(session)
+ },
+ onError(err) {
+ toast.error(err.message)
+ },
+ })
- function handleSubmit(e: React.FormEvent) {
- e.preventDefault()
- loginMutation.mutate()
- }
+ function handleSubmit(e: React.FormEvent) {
+ e.preventDefault()
+ loginMutation.mutate()
+ }
- const loading = loginMutation.isPending
+ const loading = loginMutation.isPending
- return (
-
-
-
-
-
-
- Admin Dashboard
- Sign in to manage source configuration.
-
-
-
+
+
+
+ )
}
diff --git a/apps/admin-dashboard/src/components/source-config-panel.tsx b/apps/admin-dashboard/src/components/source-config-panel.tsx
index 0816c2d..123f0b3 100644
--- a/apps/admin-dashboard/src/components/source-config-panel.tsx
+++ b/apps/admin-dashboard/src/components/source-config-panel.tsx
@@ -1,10 +1,9 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
-import { useState } from "react"
import { Info, Loader2, MapPin, Trash2 } from "lucide-react"
+import { useState } from "react"
import { toast } from "sonner"
import type { ConfigFieldDef, SourceDefinition } from "@/lib/api"
-import { fetchSourceConfig, pushLocation, replaceSource, updateProviderConfig } from "@/lib/api"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
@@ -12,489 +11,489 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
} from "@/components/ui/select"
import { Separator } from "@/components/ui/separator"
import { Switch } from "@/components/ui/switch"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
+import { fetchSourceConfig, pushLocation, replaceSource, updateProviderConfig } from "@/lib/api"
interface SourceConfigPanelProps {
- source: SourceDefinition
- onUpdate: () => void
+ source: SourceDefinition
+ onUpdate: () => void
}
export function SourceConfigPanel({ source, onUpdate }: SourceConfigPanelProps) {
- const queryClient = useQueryClient()
- const [dirty, setDirty] = useState>({})
+ const queryClient = useQueryClient()
+ const [dirty, setDirty] = useState>({})
- const { data: serverConfig, isLoading } = useQuery({
- queryKey: ["sourceConfig", source.id],
- queryFn: () => fetchSourceConfig(source.id),
- })
+ const { data: serverConfig, isLoading } = useQuery({
+ queryKey: ["sourceConfig", source.id],
+ queryFn: () => fetchSourceConfig(source.id),
+ })
- const enabled = serverConfig?.enabled ?? false
- const serverValues = buildInitialValues(source.fields, serverConfig?.config)
- const formValues = { ...serverValues, ...dirty }
+ const enabled = serverConfig?.enabled ?? false
+ const serverValues = buildInitialValues(source.fields, serverConfig?.config)
+ const formValues = { ...serverValues, ...dirty }
- function isCredentialField(field: ConfigFieldDef): boolean {
- return !!(field.secret && field.required)
- }
+ function isCredentialField(field: ConfigFieldDef): boolean {
+ return !!(field.secret && field.required)
+ }
- function getUserConfig(): Record {
- const result: Record = {}
- for (const [name, value] of Object.entries(formValues)) {
- const field = source.fields[name]
- if (field && !isCredentialField(field)) {
- result[name] = value
- }
- }
- return result
- }
+ function getUserConfig(): Record {
+ const result: Record = {}
+ for (const [name, value] of Object.entries(formValues)) {
+ const field = source.fields[name]
+ if (field && !isCredentialField(field)) {
+ result[name] = value
+ }
+ }
+ return result
+ }
- function getCredentialFields(): Record {
- const creds: Record = {}
- for (const [name, value] of Object.entries(formValues)) {
- const field = source.fields[name]
- if (field && isCredentialField(field)) {
- creds[name] = value
- }
- }
- return creds
- }
+ function getCredentialFields(): Record {
+ const creds: Record = {}
+ for (const [name, value] of Object.entries(formValues)) {
+ const field = source.fields[name]
+ if (field && isCredentialField(field)) {
+ creds[name] = value
+ }
+ }
+ return creds
+ }
- function invalidate() {
- queryClient.invalidateQueries({ queryKey: ["sourceConfig", source.id] })
- queryClient.invalidateQueries({ queryKey: ["configs"] })
- onUpdate()
- }
+ function invalidate() {
+ queryClient.invalidateQueries({ queryKey: ["sourceConfig", source.id] })
+ queryClient.invalidateQueries({ queryKey: ["configs"] })
+ onUpdate()
+ }
- const saveMutation = useMutation({
- mutationFn: async () => {
- const promises: Promise[] = [
- replaceSource(source.id, { enabled, config: getUserConfig() }),
- ]
+ const saveMutation = useMutation({
+ mutationFn: async () => {
+ const promises: Promise[] = [
+ replaceSource(source.id, { enabled, config: getUserConfig() }),
+ ]
- const credentialFields = getCredentialFields()
- const hasCredentials = Object.values(credentialFields).some(
- (v) => typeof v === "string" && v.length > 0,
- )
- if (hasCredentials) {
- promises.push(
- updateProviderConfig(source.id, { credentials: credentialFields }),
- )
- }
+ const credentialFields = getCredentialFields()
+ const hasCredentials = Object.values(credentialFields).some(
+ (v) => typeof v === "string" && v.length > 0,
+ )
+ if (hasCredentials) {
+ promises.push(updateProviderConfig(source.id, { credentials: credentialFields }))
+ }
- await Promise.all(promises)
- },
- onSuccess() {
- setDirty({})
- invalidate()
- toast.success("Configuration saved")
- },
- onError(err) {
- toast.error(err.message)
- },
- })
+ await Promise.all(promises)
+ },
+ onSuccess() {
+ setDirty({})
+ invalidate()
+ toast.success("Configuration saved")
+ },
+ onError(err) {
+ toast.error(err.message)
+ },
+ })
- const toggleMutation = useMutation({
- mutationFn: (checked: boolean) =>
- replaceSource(source.id, { enabled: checked, config: getUserConfig() }),
- onSuccess(_data, checked) {
- invalidate()
- toast.success(`Source ${checked ? "enabled" : "disabled"}`)
- },
- onError(err) {
- toast.error(err.message)
- },
- })
+ const toggleMutation = useMutation({
+ mutationFn: (checked: boolean) =>
+ replaceSource(source.id, { enabled: checked, config: getUserConfig() }),
+ onSuccess(_data, checked) {
+ invalidate()
+ toast.success(`Source ${checked ? "enabled" : "disabled"}`)
+ },
+ onError(err) {
+ toast.error(err.message)
+ },
+ })
- const deleteMutation = useMutation({
- mutationFn: () => replaceSource(source.id, { enabled: false, config: {} }),
- onSuccess() {
- setDirty({})
- invalidate()
- toast.success("Configuration deleted")
- },
- onError(err) {
- toast.error(err.message)
- },
- })
+ const deleteMutation = useMutation({
+ mutationFn: () => replaceSource(source.id, { enabled: false, config: {} }),
+ onSuccess() {
+ setDirty({})
+ invalidate()
+ toast.success("Configuration deleted")
+ },
+ onError(err) {
+ toast.error(err.message)
+ },
+ })
- function handleFieldChange(fieldName: string, value: unknown) {
- setDirty((prev) => ({ ...prev, [fieldName]: value }))
- }
+ function handleFieldChange(fieldName: string, value: unknown) {
+ setDirty((prev) => ({ ...prev, [fieldName]: value }))
+ }
- const fieldEntries = Object.entries(source.fields)
- const hasFields = fieldEntries.length > 0
- const busy = saveMutation.isPending || toggleMutation.isPending || deleteMutation.isPending
+ const fieldEntries = Object.entries(source.fields)
+ const hasFields = fieldEntries.length > 0
+ const busy = saveMutation.isPending || toggleMutation.isPending || deleteMutation.isPending
- const requiredFields = fieldEntries.filter(([, f]) => f.required)
- const optionalFields = fieldEntries.filter(([, f]) => !f.required)
+ const requiredFields = fieldEntries.filter(([, f]) => f.required)
+ const optionalFields = fieldEntries.filter(([, f]) => !f.required)
- if (isLoading) {
- return (
-
-
-
- )
- }
+ if (isLoading) {
+ return (
+
+
+
+ )
+ }
- return (
-
- {/* Header */}
-
-
-
-
{source.name}
- {source.alwaysEnabled ? (
-
Always on
- ) : enabled ? (
-
Enabled
- ) : (
-
Disabled
- )}
+ return (
+
+ {/* Header */}
+
+
+
+
{source.name}
+ {source.alwaysEnabled ? (
+ Always on
+ ) : enabled ? (
+ Enabled
+ ) : (
+ Disabled
+ )}
+
+
{source.description}
+
+ {!source.alwaysEnabled && (
+
toggleMutation.mutate(checked)}
+ disabled={busy}
+ />
+ )}
+
-
-
{source.description}
-
- {!source.alwaysEnabled && (
-
toggleMutation.mutate(checked)}
- disabled={busy}
- />
- )}
-
+ {/* Config form */}
+ {hasFields && !source.alwaysEnabled && (
+ <>
+ {/* Required fields */}
+ {requiredFields.length > 0 && (
+
+
+ Credentials
+ Required fields to connect this source.
+
+
+ {requiredFields.map(([name, field]) => (
+ handleFieldChange(name, v)}
+ disabled={busy}
+ />
+ ))}
+
+
+ )}
- {/* Config form */}
- {hasFields && !source.alwaysEnabled && (
- <>
- {/* Required fields */}
- {requiredFields.length > 0 && (
-
-
- Credentials
- Required fields to connect this source.
-
-
- {requiredFields.map(([name, field]) => (
- handleFieldChange(name, v)}
- disabled={busy}
- />
- ))}
-
-
- )}
+ {/* Optional fields */}
+ {optionalFields.length > 0 && (
+
+
+ Options
+ Optional configuration for this source.
+
+
+ 1 ? "grid-cols-2" : ""}`}>
+ {optionalFields.map(([name, field]) => (
+ handleFieldChange(name, v)}
+ disabled={busy}
+ />
+ ))}
+
+
+
+ )}
- {/* Optional fields */}
- {optionalFields.length > 0 && (
-
-
- Options
- Optional configuration for this source.
-
-
- 1 ? "grid-cols-2" : ""}`}>
- {optionalFields.map(([name, field]) => (
- handleFieldChange(name, v)}
- disabled={busy}
- />
- ))}
-
-
-
- )}
+ {/* Actions */}
+
+ {serverConfig && (
+
+ )}
+
+
+ >
+ )}
- {/* Actions */}
-
- {serverConfig && (
-
- )}
-
-
- >
- )}
+ {/* Always-on sources */}
+ {source.alwaysEnabled && source.id !== "aelis.location" && (
+ <>
+
+
+ This source is always enabled and requires no configuration.
+
+ >
+ )}
- {/* Always-on sources */}
- {source.alwaysEnabled && source.id !== "aelis.location" && (
- <>
-
-
- This source is always enabled and requires no configuration.
-
- >
- )}
-
- {source.id === "aelis.location" &&
}
-
- )
+ {source.id === "aelis.location" &&
}
+
+ )
}
function LocationCard() {
- const [lat, setLat] = useState("")
- const [lng, setLng] = useState("")
+ const [lat, setLat] = useState("")
+ const [lng, setLng] = useState("")
- const locationMutation = useMutation({
- mutationFn: (coords: { lat: number; lng: number }) =>
- pushLocation({ lat: coords.lat, lng: coords.lng, accuracy: 10 }),
- onSuccess() {
- toast.success("Location updated")
- },
- onError(err) {
- toast.error(err.message)
- },
- })
+ const locationMutation = useMutation({
+ mutationFn: (coords: { lat: number; lng: number }) =>
+ pushLocation({ lat: coords.lat, lng: coords.lng, accuracy: 10 }),
+ onSuccess() {
+ toast.success("Location updated")
+ },
+ onError(err) {
+ toast.error(err.message)
+ },
+ })
- function handlePush() {
- const latNum = parseFloat(lat)
- const lngNum = parseFloat(lng)
- if (isNaN(latNum) || isNaN(lngNum)) return
- locationMutation.mutate({ lat: latNum, lng: lngNum })
- }
+ function handlePush() {
+ const latNum = parseFloat(lat)
+ const lngNum = parseFloat(lng)
+ if (isNaN(latNum) || isNaN(lngNum)) return
+ locationMutation.mutate({ lat: latNum, lng: lngNum })
+ }
- function handleUseDevice() {
- navigator.geolocation.getCurrentPosition(
- (pos) => {
- setLat(String(pos.coords.latitude))
- setLng(String(pos.coords.longitude))
- locationMutation.mutate({
- lat: pos.coords.latitude,
- lng: pos.coords.longitude,
- })
- },
- (err) => {
- locationMutation.reset()
- alert(`Geolocation error: ${err.message}`)
- },
- )
- }
+ function handleUseDevice() {
+ navigator.geolocation.getCurrentPosition(
+ (pos) => {
+ setLat(String(pos.coords.latitude))
+ setLng(String(pos.coords.longitude))
+ locationMutation.mutate({
+ lat: pos.coords.latitude,
+ lng: pos.coords.longitude,
+ })
+ },
+ (err) => {
+ locationMutation.reset()
+ alert(`Geolocation error: ${err.message}`)
+ },
+ )
+ }
- return (
-
-
- Push Location
- Send a location update to the backend.
-
-
-
+ return (
+
+
+ Push Location
+ Send a location update to the backend.
+
+
+
-
-
-
-
-
-
- )
+
+
+
+
+
+
+ )
}
function FieldInput({
- name,
- field,
- value,
- onChange,
- disabled,
+ name,
+ field,
+ value,
+ onChange,
+ disabled,
}: {
- name: string
- field: ConfigFieldDef
- value: unknown
- onChange: (value: unknown) => void
- disabled?: boolean
+ name: string
+ field: ConfigFieldDef
+ value: unknown
+ onChange: (value: unknown) => void
+ disabled?: boolean
}) {
- const labelContent = (
-
- {field.label}
- {field.required && *}
- {field.description && (
-
-
-
-
-
- {field.description}
-
-
- )}
-
- )
+ const labelContent = (
+
+ {field.label}
+ {field.required && *}
+ {field.description && (
+
+
+
+
+
+ {field.description}
+
+
+ )}
+
+ )
- if (field.type === "select" && field.options) {
- return (
-
-
-
-
- )
- }
+ if (field.type === "select" && field.options) {
+ return (
+
+
+
+
+ )
+ }
- if (field.type === "multiselect" && field.options) {
- const selected = Array.isArray(value) ? (value as string[]) : []
+ if (field.type === "multiselect" && field.options) {
+ const selected = Array.isArray(value) ? (value as string[]) : []
- function toggle(optValue: string) {
- const next = selected.includes(optValue)
- ? selected.filter((v) => v !== optValue)
- : [...selected, optValue]
- onChange(next)
- }
+ function toggle(optValue: string) {
+ const next = selected.includes(optValue)
+ ? selected.filter((v) => v !== optValue)
+ : [...selected, optValue]
+ onChange(next)
+ }
- return (
-
-
-
- {field.options!.map((opt) => {
- const isSelected = selected.includes(opt.value)
- return (
- !disabled && toggle(opt.value)}
- >
- {opt.label}
-
- )
- })}
-
-
- )
- }
+ return (
+
+
+
+ {field.options!.map((opt) => {
+ const isSelected = selected.includes(opt.value)
+ return (
+ !disabled && toggle(opt.value)}
+ >
+ {opt.label}
+
+ )
+ })}
+
+
+ )
+ }
- if (field.type === "number") {
- return (
-
-
- {
- const v = e.target.value
- onChange(v === "" ? undefined : Number(v))
- }}
- placeholder={field.defaultValue !== undefined ? String(field.defaultValue) : undefined}
- disabled={disabled}
- />
-
- )
- }
+ if (field.type === "number") {
+ return (
+
+
+ {
+ const v = e.target.value
+ onChange(v === "" ? undefined : Number(v))
+ }}
+ placeholder={field.defaultValue !== undefined ? String(field.defaultValue) : undefined}
+ disabled={disabled}
+ />
+
+ )
+ }
- return (
-
-
- onChange(e.target.value)}
- placeholder={field.defaultValue !== undefined ? String(field.defaultValue) : undefined}
- disabled={disabled}
- />
-
- )
+ return (
+
+
+ onChange(e.target.value)}
+ placeholder={field.defaultValue !== undefined ? String(field.defaultValue) : undefined}
+ disabled={disabled}
+ />
+
+ )
}
function buildInitialValues(
- fields: Record,
- saved: Record | undefined,
+ fields: Record,
+ saved: Record | undefined,
): Record {
- const values: Record = {}
- for (const [name, field] of Object.entries(fields)) {
- if (saved && name in saved) {
- values[name] = saved[name]
- } else if (field.defaultValue !== undefined) {
- values[name] = field.defaultValue
- } else if (field.type === "multiselect") {
- values[name] = []
- } else {
- values[name] = field.type === "number" ? undefined : ""
- }
- }
- return values
+ const values: Record = {}
+ for (const [name, field] of Object.entries(fields)) {
+ if (saved && name in saved) {
+ values[name] = saved[name]
+ } else if (field.defaultValue !== undefined) {
+ values[name] = field.defaultValue
+ } else if (field.type === "multiselect") {
+ values[name] = []
+ } else {
+ values[name] = field.type === "number" ? undefined : ""
+ }
+ }
+ return values
}
diff --git a/apps/admin-dashboard/src/components/theme-provider.tsx b/apps/admin-dashboard/src/components/theme-provider.tsx
index 1349a0c..c3cd479 100644
--- a/apps/admin-dashboard/src/components/theme-provider.tsx
+++ b/apps/admin-dashboard/src/components/theme-provider.tsx
@@ -5,226 +5,219 @@ type Theme = "dark" | "light" | "system"
type ResolvedTheme = "dark" | "light"
type ThemeProviderProps = {
- children: React.ReactNode
- defaultTheme?: Theme
- storageKey?: string
- disableTransitionOnChange?: boolean
+ children: React.ReactNode
+ defaultTheme?: Theme
+ storageKey?: string
+ disableTransitionOnChange?: boolean
}
type ThemeProviderState = {
- theme: Theme
- setTheme: (theme: Theme) => void
+ theme: Theme
+ setTheme: (theme: Theme) => void
}
const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)"
const THEME_VALUES: Theme[] = ["dark", "light", "system"]
-const ThemeProviderContext = React.createContext<
- ThemeProviderState | undefined
->(undefined)
+const ThemeProviderContext = React.createContext(undefined)
function isTheme(value: string | null): value is Theme {
- if (value === null) {
- return false
- }
+ if (value === null) {
+ return false
+ }
- return THEME_VALUES.includes(value as Theme)
+ return THEME_VALUES.includes(value as Theme)
}
function getSystemTheme(): ResolvedTheme {
- if (window.matchMedia(COLOR_SCHEME_QUERY).matches) {
- return "dark"
- }
+ if (window.matchMedia(COLOR_SCHEME_QUERY).matches) {
+ return "dark"
+ }
- return "light"
+ return "light"
}
function disableTransitionsTemporarily() {
- const style = document.createElement("style")
- style.appendChild(
- document.createTextNode(
- "*,*::before,*::after{-webkit-transition:none!important;transition:none!important}"
- )
- )
- document.head.appendChild(style)
+ const style = document.createElement("style")
+ style.appendChild(
+ document.createTextNode(
+ "*,*::before,*::after{-webkit-transition:none!important;transition:none!important}",
+ ),
+ )
+ document.head.appendChild(style)
- return () => {
- window.getComputedStyle(document.body)
- requestAnimationFrame(() => {
- requestAnimationFrame(() => {
- style.remove()
- })
- })
- }
+ return () => {
+ window.getComputedStyle(document.body)
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ style.remove()
+ })
+ })
+ }
}
function isEditableTarget(target: EventTarget | null) {
- if (!(target instanceof HTMLElement)) {
- return false
- }
+ if (!(target instanceof HTMLElement)) {
+ return false
+ }
- if (target.isContentEditable) {
- return true
- }
+ if (target.isContentEditable) {
+ return true
+ }
- const editableParent = target.closest(
- "input, textarea, select, [contenteditable='true']"
- )
- if (editableParent) {
- return true
- }
+ const editableParent = target.closest("input, textarea, select, [contenteditable='true']")
+ if (editableParent) {
+ return true
+ }
- return false
+ return false
}
export function ThemeProvider({
- children,
- defaultTheme = "system",
- storageKey = "theme",
- disableTransitionOnChange = true,
- ...props
+ children,
+ defaultTheme = "system",
+ storageKey = "theme",
+ disableTransitionOnChange = true,
+ ...props
}: ThemeProviderProps) {
- const [theme, setThemeState] = React.useState(() => {
- const storedTheme = localStorage.getItem(storageKey)
- if (isTheme(storedTheme)) {
- return storedTheme
- }
+ const [theme, setThemeState] = React.useState(() => {
+ const storedTheme = localStorage.getItem(storageKey)
+ if (isTheme(storedTheme)) {
+ return storedTheme
+ }
- return defaultTheme
- })
+ return defaultTheme
+ })
- const setTheme = React.useCallback(
- (nextTheme: Theme) => {
- localStorage.setItem(storageKey, nextTheme)
- setThemeState(nextTheme)
- },
- [storageKey]
- )
+ const setTheme = React.useCallback(
+ (nextTheme: Theme) => {
+ localStorage.setItem(storageKey, nextTheme)
+ setThemeState(nextTheme)
+ },
+ [storageKey],
+ )
- const applyTheme = React.useCallback(
- (nextTheme: Theme) => {
- const root = document.documentElement
- const resolvedTheme =
- nextTheme === "system" ? getSystemTheme() : nextTheme
- const restoreTransitions = disableTransitionOnChange
- ? disableTransitionsTemporarily()
- : null
+ const applyTheme = React.useCallback(
+ (nextTheme: Theme) => {
+ const root = document.documentElement
+ const resolvedTheme = nextTheme === "system" ? getSystemTheme() : nextTheme
+ const restoreTransitions = disableTransitionOnChange ? disableTransitionsTemporarily() : null
- root.classList.remove("light", "dark")
- root.classList.add(resolvedTheme)
+ root.classList.remove("light", "dark")
+ root.classList.add(resolvedTheme)
- if (restoreTransitions) {
- restoreTransitions()
- }
- },
- [disableTransitionOnChange]
- )
+ if (restoreTransitions) {
+ restoreTransitions()
+ }
+ },
+ [disableTransitionOnChange],
+ )
- React.useEffect(() => {
- applyTheme(theme)
+ React.useEffect(() => {
+ applyTheme(theme)
- if (theme !== "system") {
- return undefined
- }
+ if (theme !== "system") {
+ return undefined
+ }
- const mediaQuery = window.matchMedia(COLOR_SCHEME_QUERY)
- const handleChange = () => {
- applyTheme("system")
- }
+ const mediaQuery = window.matchMedia(COLOR_SCHEME_QUERY)
+ const handleChange = () => {
+ applyTheme("system")
+ }
- mediaQuery.addEventListener("change", handleChange)
+ mediaQuery.addEventListener("change", handleChange)
- return () => {
- mediaQuery.removeEventListener("change", handleChange)
- }
- }, [theme, applyTheme])
+ return () => {
+ mediaQuery.removeEventListener("change", handleChange)
+ }
+ }, [theme, applyTheme])
- React.useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (event.repeat) {
- return
- }
+ React.useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.repeat) {
+ return
+ }
- if (event.metaKey || event.ctrlKey || event.altKey) {
- return
- }
+ if (event.metaKey || event.ctrlKey || event.altKey) {
+ return
+ }
- if (isEditableTarget(event.target)) {
- return
- }
+ if (isEditableTarget(event.target)) {
+ return
+ }
- if (event.key.toLowerCase() !== "d") {
- return
- }
+ if (event.key.toLowerCase() !== "d") {
+ return
+ }
- setThemeState((currentTheme) => {
- const nextTheme =
- currentTheme === "dark"
- ? "light"
- : currentTheme === "light"
- ? "dark"
- : getSystemTheme() === "dark"
- ? "light"
- : "dark"
+ setThemeState((currentTheme) => {
+ const nextTheme =
+ currentTheme === "dark"
+ ? "light"
+ : currentTheme === "light"
+ ? "dark"
+ : getSystemTheme() === "dark"
+ ? "light"
+ : "dark"
- localStorage.setItem(storageKey, nextTheme)
- return nextTheme
- })
- }
+ localStorage.setItem(storageKey, nextTheme)
+ return nextTheme
+ })
+ }
- window.addEventListener("keydown", handleKeyDown)
+ window.addEventListener("keydown", handleKeyDown)
- return () => {
- window.removeEventListener("keydown", handleKeyDown)
- }
- }, [storageKey])
+ return () => {
+ window.removeEventListener("keydown", handleKeyDown)
+ }
+ }, [storageKey])
- React.useEffect(() => {
- const handleStorageChange = (event: StorageEvent) => {
- if (event.storageArea !== localStorage) {
- return
- }
+ React.useEffect(() => {
+ const handleStorageChange = (event: StorageEvent) => {
+ if (event.storageArea !== localStorage) {
+ return
+ }
- if (event.key !== storageKey) {
- return
- }
+ if (event.key !== storageKey) {
+ return
+ }
- if (isTheme(event.newValue)) {
- setThemeState(event.newValue)
- return
- }
+ if (isTheme(event.newValue)) {
+ setThemeState(event.newValue)
+ return
+ }
- setThemeState(defaultTheme)
- }
+ setThemeState(defaultTheme)
+ }
- window.addEventListener("storage", handleStorageChange)
+ window.addEventListener("storage", handleStorageChange)
- return () => {
- window.removeEventListener("storage", handleStorageChange)
- }
- }, [defaultTheme, storageKey])
+ return () => {
+ window.removeEventListener("storage", handleStorageChange)
+ }
+ }, [defaultTheme, storageKey])
- const value = React.useMemo(
- () => ({
- theme,
- setTheme,
- }),
- [theme, setTheme]
- )
+ const value = React.useMemo(
+ () => ({
+ theme,
+ setTheme,
+ }),
+ [theme, setTheme],
+ )
- return (
-
- {children}
-
- )
+ return (
+
+ {children}
+
+ )
}
export const useTheme = () => {
- const context = React.useContext(ThemeProviderContext)
+ const context = React.useContext(ThemeProviderContext)
- if (context === undefined) {
- throw new Error("useTheme must be used within a ThemeProvider")
- }
+ if (context === undefined) {
+ throw new Error("useTheme must be used within a ThemeProvider")
+ }
- return context
+ return context
}
diff --git a/apps/admin-dashboard/src/components/ui/accordion.tsx b/apps/admin-dashboard/src/components/ui/accordion.tsx
index edc72ab..12e4f68 100644
--- a/apps/admin-dashboard/src/components/ui/accordion.tsx
+++ b/apps/admin-dashboard/src/components/ui/accordion.tsx
@@ -1,84 +1,84 @@
"use client"
-import * as React from "react"
+import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
import { Accordion as AccordionPrimitive } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
-import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
-function Accordion({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function Accordion({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
function AccordionItem({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return (
+
+ )
}
function AccordionTrigger({
- className,
- children,
- ...props
+ className,
+ children,
+ ...props
}: React.ComponentProps) {
- return (
-
-
- {children}
-
-
-
-
- )
+ return (
+
+
+ {children}
+
+
+
+
+ )
}
function AccordionContent({
- className,
- children,
- ...props
+ className,
+ children,
+ ...props
}: React.ComponentProps) {
- return (
-
-
- {children}
-
-
- )
+ return (
+
+
+ {children}
+
+
+ )
}
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/apps/admin-dashboard/src/components/ui/alert.tsx b/apps/admin-dashboard/src/components/ui/alert.tsx
index 78c6538..de6ca1e 100644
--- a/apps/admin-dashboard/src/components/ui/alert.tsx
+++ b/apps/admin-dashboard/src/components/ui/alert.tsx
@@ -1,76 +1,73 @@
-import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react"
import { cn } from "@/lib/utils"
const alertVariants = cva(
- "group/alert relative grid w-full gap-0.5 rounded-lg border px-2 py-1.5 text-left text-xs/relaxed has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-1.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-3.5",
- {
- variants: {
- variant: {
- default: "bg-card text-card-foreground",
- destructive:
- "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
- },
- },
- defaultVariants: {
- variant: "default",
- },
- }
+ "group/alert relative grid w-full gap-0.5 rounded-lg border px-2 py-1.5 text-left text-xs/relaxed has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-1.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-3.5",
+ {
+ variants: {
+ variant: {
+ default: "bg-card text-card-foreground",
+ destructive:
+ "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ },
)
function Alert({
- className,
- variant,
- ...props
+ className,
+ variant,
+ ...props
}: React.ComponentProps<"div"> & VariantProps) {
- return (
-
- )
+ return (
+
+ )
}
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
- svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground",
- className
- )}
- {...props}
- />
- )
+ return (
+
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground",
+ className,
+ )}
+ {...props}
+ />
+ )
}
-function AlertDescription({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- )
+function AlertDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
}
function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
export { Alert, AlertTitle, AlertDescription, AlertAction }
diff --git a/apps/admin-dashboard/src/components/ui/badge.tsx b/apps/admin-dashboard/src/components/ui/badge.tsx
index bd34736..8b3dff0 100644
--- a/apps/admin-dashboard/src/components/ui/badge.tsx
+++ b/apps/admin-dashboard/src/components/ui/badge.tsx
@@ -1,49 +1,46 @@
-import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
const badgeVariants = cva(
- "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-2.5!",
- {
- variants: {
- variant: {
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
- secondary:
- "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
- destructive:
- "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
- outline:
- "border-border bg-input/20 text-foreground dark:bg-input/30 [a]:hover:bg-muted [a]:hover:text-muted-foreground",
- ghost:
- "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
- link: "text-primary underline-offset-4 hover:underline",
- },
- },
- defaultVariants: {
- variant: "default",
- },
- }
+ "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-2.5!",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
+ destructive:
+ "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
+ outline:
+ "border-border bg-input/20 text-foreground dark:bg-input/30 [a]:hover:bg-muted [a]:hover:text-muted-foreground",
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ },
)
function Badge({
- className,
- variant = "default",
- asChild = false,
- ...props
-}: React.ComponentProps<"span"> &
- VariantProps
& { asChild?: boolean }) {
- const Comp = asChild ? Slot.Root : "span"
+ className,
+ variant = "default",
+ asChild = false,
+ ...props
+}: React.ComponentProps<"span"> & VariantProps & { asChild?: boolean }) {
+ const Comp = asChild ? Slot.Root : "span"
- return (
-
- )
+ return (
+
+ )
}
export { Badge, badgeVariants }
diff --git a/apps/admin-dashboard/src/components/ui/button.tsx b/apps/admin-dashboard/src/components/ui/button.tsx
index af98dbf..fde42a0 100644
--- a/apps/admin-dashboard/src/components/ui/button.tsx
+++ b/apps/admin-dashboard/src/components/ui/button.tsx
@@ -1,65 +1,65 @@
-import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
- "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
- {
- variants: {
- variant: {
- default: "bg-primary text-primary-foreground hover:bg-primary/80",
- outline:
- "border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30",
- secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
- ghost:
- "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
- destructive:
- "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
- link: "text-primary underline-offset-4 hover:underline",
- },
- size: {
- default:
- "h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
- xs: "h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-2.5",
- sm: "h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
- lg: "h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-4",
- icon: "size-7 [&_svg:not([class*='size-'])]:size-3.5",
- "icon-xs": "size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5",
- "icon-sm": "size-6 [&_svg:not([class*='size-'])]:size-3",
- "icon-lg": "size-8 [&_svg:not([class*='size-'])]:size-4",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- }
+ "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
+ outline:
+ "border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
+ ghost:
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
+ destructive:
+ "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default:
+ "h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
+ xs: "h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-2.5",
+ sm: "h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
+ lg: "h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-4",
+ icon: "size-7 [&_svg:not([class*='size-'])]:size-3.5",
+ "icon-xs": "size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5",
+ "icon-sm": "size-6 [&_svg:not([class*='size-'])]:size-3",
+ "icon-lg": "size-8 [&_svg:not([class*='size-'])]:size-4",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
)
function Button({
- className,
- variant = "default",
- size = "default",
- asChild = false,
- ...props
+ className,
+ variant = "default",
+ size = "default",
+ asChild = false,
+ ...props
}: React.ComponentProps<"button"> &
- VariantProps & {
- asChild?: boolean
- }) {
- const Comp = asChild ? Slot.Root : "button"
+ VariantProps & {
+ asChild?: boolean
+ }) {
+ const Comp = asChild ? Slot.Root : "button"
- return (
-
- )
+ return (
+
+ )
}
export { Button, buttonVariants }
diff --git a/apps/admin-dashboard/src/components/ui/card.tsx b/apps/admin-dashboard/src/components/ui/card.tsx
index d2c71be..54cd662 100644
--- a/apps/admin-dashboard/src/components/ui/card.tsx
+++ b/apps/admin-dashboard/src/components/ui/card.tsx
@@ -3,98 +3,81 @@ import * as React from "react"
import { cn } from "@/lib/utils"
function Card({
- className,
- size = "default",
- ...props
+ className,
+ size = "default",
+ ...props
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
- return (
- img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg",
- className
- )}
- {...props}
- />
- )
+ return (
+
img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg",
+ className,
+ )}
+ {...props}
+ />
+ )
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
-export {
- Card,
- CardHeader,
- CardFooter,
- CardTitle,
- CardAction,
- CardDescription,
- CardContent,
-}
+export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent }
diff --git a/apps/admin-dashboard/src/components/ui/collapsible.tsx b/apps/admin-dashboard/src/components/ui/collapsible.tsx
index 2f7a4e7..c803c88 100644
--- a/apps/admin-dashboard/src/components/ui/collapsible.tsx
+++ b/apps/admin-dashboard/src/components/ui/collapsible.tsx
@@ -2,32 +2,20 @@
import { Collapsible as CollapsiblePrimitive } from "radix-ui"
-function Collapsible({
- ...props
-}: React.ComponentProps
) {
- return
+function Collapsible({ ...props }: React.ComponentProps) {
+ return
}
function CollapsibleTrigger({
- ...props
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return
}
function CollapsibleContent({
- ...props
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return
}
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
diff --git a/apps/admin-dashboard/src/components/ui/input.tsx b/apps/admin-dashboard/src/components/ui/input.tsx
index edb8859..83b4c2a 100644
--- a/apps/admin-dashboard/src/components/ui/input.tsx
+++ b/apps/admin-dashboard/src/components/ui/input.tsx
@@ -3,17 +3,17 @@ import * as React from "react"
import { cn } from "@/lib/utils"
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
- return (
-
- )
+ return (
+
+ )
}
export { Input }
diff --git a/apps/admin-dashboard/src/components/ui/label.tsx b/apps/admin-dashboard/src/components/ui/label.tsx
index d3fea07..b41e059 100644
--- a/apps/admin-dashboard/src/components/ui/label.tsx
+++ b/apps/admin-dashboard/src/components/ui/label.tsx
@@ -1,22 +1,19 @@
-import * as React from "react"
import { Label as LabelPrimitive } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
-function Label({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function Label({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
export { Label }
diff --git a/apps/admin-dashboard/src/components/ui/select.tsx b/apps/admin-dashboard/src/components/ui/select.tsx
index 248268c..72adc27 100644
--- a/apps/admin-dashboard/src/components/ui/select.tsx
+++ b/apps/admin-dashboard/src/components/ui/select.tsx
@@ -1,193 +1,183 @@
-import * as React from "react"
+import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
import { Select as SelectPrimitive } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
-import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
-function Select({
- ...props
-}: React.ComponentProps) {
- return
+function Select({ ...props }: React.ComponentProps) {
+ return
}
-function SelectGroup({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function SelectGroup({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
-function SelectValue({
- ...props
-}: React.ComponentProps) {
- return
+function SelectValue({ ...props }: React.ComponentProps) {
+ return
}
function SelectTrigger({
- className,
- size = "default",
- children,
- ...props
+ className,
+ size = "default",
+ children,
+ ...props
}: React.ComponentProps & {
- size?: "sm" | "default"
+ size?: "sm" | "default"
}) {
- return (
-
- {children}
-
-
-
-
- )
+ return (
+
+ {children}
+
+
+
+
+ )
}
function SelectContent({
- className,
- children,
- position = "item-aligned",
- align = "center",
- ...props
+ className,
+ children,
+ position = "item-aligned",
+ align = "center",
+ ...props
}: React.ComponentProps) {
- return (
-
-
-
-
- {children}
-
-
-
-
- )
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ )
}
-function SelectLabel({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function SelectLabel({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
function SelectItem({
- className,
- children,
- ...props
+ className,
+ children,
+ ...props
}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- )
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
}
function SelectSeparator({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return (
+
+ )
}
function SelectScrollUpButton({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
-
-
- )
+ return (
+
+
+
+ )
}
function SelectScrollDownButton({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
-
-
- )
+ return (
+
+
+
+ )
}
export {
- Select,
- SelectContent,
- SelectGroup,
- SelectItem,
- SelectLabel,
- SelectScrollDownButton,
- SelectScrollUpButton,
- SelectSeparator,
- SelectTrigger,
- SelectValue,
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
}
diff --git a/apps/admin-dashboard/src/components/ui/separator.tsx b/apps/admin-dashboard/src/components/ui/separator.tsx
index ca11501..804f73a 100644
--- a/apps/admin-dashboard/src/components/ui/separator.tsx
+++ b/apps/admin-dashboard/src/components/ui/separator.tsx
@@ -1,26 +1,26 @@
-import * as React from "react"
import { Separator as SeparatorPrimitive } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
function Separator({
- className,
- orientation = "horizontal",
- decorative = true,
- ...props
+ className,
+ orientation = "horizontal",
+ decorative = true,
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return (
+
+ )
}
export { Separator }
diff --git a/apps/admin-dashboard/src/components/ui/sheet.tsx b/apps/admin-dashboard/src/components/ui/sheet.tsx
index 8b88aeb..fa7d36f 100644
--- a/apps/admin-dashboard/src/components/ui/sheet.tsx
+++ b/apps/admin-dashboard/src/components/ui/sheet.tsx
@@ -1,142 +1,128 @@
-import * as React from "react"
-import { Dialog as SheetPrimitive } from "radix-ui"
-
-import { cn } from "@/lib/utils"
-import { Button } from "@/components/ui/button"
import { XIcon } from "lucide-react"
+import { Dialog as SheetPrimitive } from "radix-ui"
+import * as React from "react"
+
+import { Button } from "@/components/ui/button"
+import { cn } from "@/lib/utils"
function Sheet({ ...props }: React.ComponentProps) {
- return
+ return
}
-function SheetTrigger({
- ...props
-}: React.ComponentProps) {
- return
+function SheetTrigger({ ...props }: React.ComponentProps) {
+ return
}
-function SheetClose({
- ...props
-}: React.ComponentProps) {
- return
+function SheetClose({ ...props }: React.ComponentProps) {
+ return
}
-function SheetPortal({
- ...props
-}: React.ComponentProps) {
- return
+function SheetPortal({ ...props }: React.ComponentProps) {
+ return
}
function SheetOverlay({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return (
+
+ )
}
function SheetContent({
- className,
- children,
- side = "right",
- showCloseButton = true,
- ...props
+ className,
+ children,
+ side = "right",
+ showCloseButton = true,
+ ...props
}: React.ComponentProps & {
- side?: "top" | "right" | "bottom" | "left"
- showCloseButton?: boolean
+ side?: "top" | "right" | "bottom" | "left"
+ showCloseButton?: boolean
}) {
- return (
-
-
-
- {children}
- {showCloseButton && (
-
-
-
- )}
-
-
- )
+ return (
+
+
+
+ {children}
+ {showCloseButton && (
+
+
+
+ )}
+
+
+ )
}
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
-function SheetTitle({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function SheetTitle({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
function SheetDescription({
- className,
- ...props
+ className,
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return (
+
+ )
}
export {
- Sheet,
- SheetTrigger,
- SheetClose,
- SheetContent,
- SheetHeader,
- SheetFooter,
- SheetTitle,
- SheetDescription,
+ Sheet,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
}
diff --git a/apps/admin-dashboard/src/components/ui/sidebar.tsx b/apps/admin-dashboard/src/components/ui/sidebar.tsx
index 08a18bd..dc7fa07 100644
--- a/apps/admin-dashboard/src/components/ui/sidebar.tsx
+++ b/apps/admin-dashboard/src/components/ui/sidebar.tsx
@@ -1,28 +1,24 @@
"use client"
-import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
+import { PanelLeftIcon } from "lucide-react"
import { Slot } from "radix-ui"
+import * as React from "react"
-import { useIsMobile } from "@/hooks/use-mobile"
-import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Separator } from "@/components/ui/separator"
import {
- Sheet,
- SheetContent,
- SheetDescription,
- SheetHeader,
- SheetTitle,
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
} from "@/components/ui/sheet"
import { Skeleton } from "@/components/ui/skeleton"
-import {
- Tooltip,
- TooltipContent,
- TooltipTrigger,
-} from "@/components/ui/tooltip"
-import { PanelLeftIcon } from "lucide-react"
+import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
+import { useIsMobile } from "@/hooks/use-mobile"
+import { cn } from "@/lib/utils"
const SIDEBAR_COOKIE_NAME = "sidebar_state"
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
@@ -32,677 +28,644 @@ const SIDEBAR_WIDTH_ICON = "3rem"
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
type SidebarContextProps = {
- state: "expanded" | "collapsed"
- open: boolean
- setOpen: (open: boolean) => void
- openMobile: boolean
- setOpenMobile: (open: boolean) => void
- isMobile: boolean
- toggleSidebar: () => void
+ state: "expanded" | "collapsed"
+ open: boolean
+ setOpen: (open: boolean) => void
+ openMobile: boolean
+ setOpenMobile: (open: boolean) => void
+ isMobile: boolean
+ toggleSidebar: () => void
}
const SidebarContext = React.createContext(null)
function useSidebar() {
- const context = React.useContext(SidebarContext)
- if (!context) {
- throw new Error("useSidebar must be used within a SidebarProvider.")
- }
+ const context = React.useContext(SidebarContext)
+ if (!context) {
+ throw new Error("useSidebar must be used within a SidebarProvider.")
+ }
- return context
+ return context
}
function SidebarProvider({
- defaultOpen = true,
- open: openProp,
- onOpenChange: setOpenProp,
- className,
- style,
- children,
- ...props
+ defaultOpen = true,
+ open: openProp,
+ onOpenChange: setOpenProp,
+ className,
+ style,
+ children,
+ ...props
}: React.ComponentProps<"div"> & {
- defaultOpen?: boolean
- open?: boolean
- onOpenChange?: (open: boolean) => void
+ defaultOpen?: boolean
+ open?: boolean
+ onOpenChange?: (open: boolean) => void
}) {
- const isMobile = useIsMobile()
- const [openMobile, setOpenMobile] = React.useState(false)
+ const isMobile = useIsMobile()
+ const [openMobile, setOpenMobile] = React.useState(false)
- // This is the internal state of the sidebar.
- // We use openProp and setOpenProp for control from outside the component.
- const [_open, _setOpen] = React.useState(defaultOpen)
- const open = openProp ?? _open
- const setOpen = React.useCallback(
- (value: boolean | ((value: boolean) => boolean)) => {
- const openState = typeof value === "function" ? value(open) : value
- if (setOpenProp) {
- setOpenProp(openState)
- } else {
- _setOpen(openState)
- }
+ // This is the internal state of the sidebar.
+ // We use openProp and setOpenProp for control from outside the component.
+ const [_open, _setOpen] = React.useState(defaultOpen)
+ const open = openProp ?? _open
+ const setOpen = React.useCallback(
+ (value: boolean | ((value: boolean) => boolean)) => {
+ const openState = typeof value === "function" ? value(open) : value
+ if (setOpenProp) {
+ setOpenProp(openState)
+ } else {
+ _setOpen(openState)
+ }
- // This sets the cookie to keep the sidebar state.
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
- },
- [setOpenProp, open]
- )
+ // This sets the cookie to keep the sidebar state.
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
+ },
+ [setOpenProp, open],
+ )
- // Helper to toggle the sidebar.
- const toggleSidebar = React.useCallback(() => {
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
- }, [isMobile, setOpen, setOpenMobile])
+ // Helper to toggle the sidebar.
+ const toggleSidebar = React.useCallback(() => {
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
+ }, [isMobile, setOpen, setOpenMobile])
- // Adds a keyboard shortcut to toggle the sidebar.
- React.useEffect(() => {
- const handleKeyDown = (event: KeyboardEvent) => {
- if (
- event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
- (event.metaKey || event.ctrlKey)
- ) {
- event.preventDefault()
- toggleSidebar()
- }
- }
+ // Adds a keyboard shortcut to toggle the sidebar.
+ React.useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
+ event.preventDefault()
+ toggleSidebar()
+ }
+ }
- window.addEventListener("keydown", handleKeyDown)
- return () => window.removeEventListener("keydown", handleKeyDown)
- }, [toggleSidebar])
+ window.addEventListener("keydown", handleKeyDown)
+ return () => window.removeEventListener("keydown", handleKeyDown)
+ }, [toggleSidebar])
- // We add a state so that we can do data-state="expanded" or "collapsed".
- // This makes it easier to style the sidebar with Tailwind classes.
- const state = open ? "expanded" : "collapsed"
+ // We add a state so that we can do data-state="expanded" or "collapsed".
+ // This makes it easier to style the sidebar with Tailwind classes.
+ const state = open ? "expanded" : "collapsed"
- const contextValue = React.useMemo(
- () => ({
- state,
- open,
- setOpen,
- isMobile,
- openMobile,
- setOpenMobile,
- toggleSidebar,
- }),
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
- )
+ const contextValue = React.useMemo(
+ () => ({
+ state,
+ open,
+ setOpen,
+ isMobile,
+ openMobile,
+ setOpenMobile,
+ toggleSidebar,
+ }),
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
+ )
- return (
-
-
- {children}
-
-
- )
+ return (
+
+
+ {children}
+
+
+ )
}
function Sidebar({
- side = "left",
- variant = "sidebar",
- collapsible = "offcanvas",
- className,
- children,
- dir,
- ...props
+ side = "left",
+ variant = "sidebar",
+ collapsible = "offcanvas",
+ className,
+ children,
+ dir,
+ ...props
}: React.ComponentProps<"div"> & {
- side?: "left" | "right"
- variant?: "sidebar" | "floating" | "inset"
- collapsible?: "offcanvas" | "icon" | "none"
+ side?: "left" | "right"
+ variant?: "sidebar" | "floating" | "inset"
+ collapsible?: "offcanvas" | "icon" | "none"
}) {
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
- if (collapsible === "none") {
- return (
-
- {children}
-
- )
- }
+ if (collapsible === "none") {
+ return (
+
+ {children}
+
+ )
+ }
- if (isMobile) {
- return (
-
-
-
- Sidebar
- Displays the mobile sidebar.
-
- {children}
-
-
- )
- }
+ if (isMobile) {
+ return (
+
+
+
+ Sidebar
+ Displays the mobile sidebar.
+
+ {children}
+
+
+ )
+ }
- return (
-
- {/* This is what handles the sidebar gap on desktop */}
-
-
-
- )
+ return (
+
+ {/* This is what handles the sidebar gap on desktop */}
+
+
+
+ )
}
-function SidebarTrigger({
- className,
- onClick,
- ...props
-}: React.ComponentProps) {
- const { toggleSidebar } = useSidebar()
+function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps) {
+ const { toggleSidebar } = useSidebar()
- return (
-
- )
+ return (
+
+ )
}
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar()
- return (
-
- )
+ return (
+
+ )
}
function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
- return (
-
- )
+ return (
+
+ )
}
-function SidebarInput({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function SidebarInput({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
-function SidebarSeparator({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
+function SidebarSeparator({ className, ...props }: React.ComponentProps) {
+ return (
+
+ )
}
function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
function SidebarGroupLabel({
- className,
- asChild = false,
- ...props
+ className,
+ asChild = false,
+ ...props
}: React.ComponentProps<"div"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot.Root : "div"
+ const Comp = asChild ? Slot.Root : "div"
- return (
- svg]:size-4 [&>svg]:shrink-0",
- className
- )}
- {...props}
- />
- )
+ return (
+ svg]:size-4 [&>svg]:shrink-0",
+ className,
+ )}
+ {...props}
+ />
+ )
}
function SidebarGroupAction({
- className,
- asChild = false,
- ...props
+ className,
+ asChild = false,
+ ...props
}: React.ComponentProps<"button"> & { asChild?: boolean }) {
- const Comp = asChild ? Slot.Root : "button"
+ const Comp = asChild ? Slot.Root : "button"
- return (
- svg]:size-4 [&>svg]:shrink-0",
- className
- )}
- {...props}
- />
- )
+ return (
+ svg]:size-4 [&>svg]:shrink-0",
+ className,
+ )}
+ {...props}
+ />
+ )
}
-function SidebarGroupContent({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- )
+function SidebarGroupContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
}
function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
- return (
-
- )
+ return (
+
+ )
}
function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
- return (
-
- )
+ return (
+
+ )
}
const sidebarMenuButtonVariants = cva(
- "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-[calc(var(--radius-sm)+2px)] p-2 text-left text-xs ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
- {
- variants: {
- variant: {
- default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
- outline:
- "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
- },
- size: {
- default: "h-8 text-xs",
- sm: "h-7 text-xs",
- lg: "h-12 text-xs group-data-[collapsible=icon]:p-0!",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- }
+ "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-[calc(var(--radius-sm)+2px)] p-2 text-left text-xs ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
+ {
+ variants: {
+ variant: {
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
+ outline:
+ "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
+ },
+ size: {
+ default: "h-8 text-xs",
+ sm: "h-7 text-xs",
+ lg: "h-12 text-xs group-data-[collapsible=icon]:p-0!",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
)
function SidebarMenuButton({
- asChild = false,
- isActive = false,
- variant = "default",
- size = "default",
- tooltip,
- className,
- ...props
+ asChild = false,
+ isActive = false,
+ variant = "default",
+ size = "default",
+ tooltip,
+ className,
+ ...props
}: React.ComponentProps<"button"> & {
- asChild?: boolean
- isActive?: boolean
- tooltip?: string | React.ComponentProps
+ asChild?: boolean
+ isActive?: boolean
+ tooltip?: string | React.ComponentProps
} & VariantProps) {
- const Comp = asChild ? Slot.Root : "button"
- const { isMobile, state } = useSidebar()
+ const Comp = asChild ? Slot.Root : "button"
+ const { isMobile, state } = useSidebar()
- const button = (
-
- )
+ const button = (
+
+ )
- if (!tooltip) {
- return button
- }
+ if (!tooltip) {
+ return button
+ }
- if (typeof tooltip === "string") {
- tooltip = {
- children: tooltip,
- }
- }
+ if (typeof tooltip === "string") {
+ tooltip = {
+ children: tooltip,
+ }
+ }
- return (
-
- {button}
-
-
- )
+ return (
+
+ {button}
+
+
+ )
}
function SidebarMenuAction({
- className,
- asChild = false,
- showOnHover = false,
- ...props
+ className,
+ asChild = false,
+ showOnHover = false,
+ ...props
}: React.ComponentProps<"button"> & {
- asChild?: boolean
- showOnHover?: boolean
+ asChild?: boolean
+ showOnHover?: boolean
}) {
- const Comp = asChild ? Slot.Root : "button"
+ const Comp = asChild ? Slot.Root : "button"
- return (
- svg]:size-4 [&>svg]:shrink-0",
- showOnHover &&
- "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
- className
- )}
- {...props}
- />
- )
+ return (
+ svg]:size-4 [&>svg]:shrink-0",
+ showOnHover &&
+ "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
+ className,
+ )}
+ {...props}
+ />
+ )
}
-function SidebarMenuBadge({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- )
+function SidebarMenuBadge({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
}
function SidebarMenuSkeleton({
- className,
- showIcon = false,
- ...props
+ className,
+ showIcon = false,
+ ...props
}: React.ComponentProps<"div"> & {
- showIcon?: boolean
+ showIcon?: boolean
}) {
- // Random width between 50 to 90%.
- const [width] = React.useState(() => {
- return `${Math.floor(Math.random() * 40) + 50}%`
- })
+ // Random width between 50 to 90%.
+ const [width] = React.useState(() => {
+ return `${Math.floor(Math.random() * 40) + 50}%`
+ })
- return (
-
- {showIcon && (
-
- )}
-
-
- )
+ return (
+
+ {showIcon && }
+
+
+ )
}
function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
- return (
-
- )
+ return (
+
+ )
}
-function SidebarMenuSubItem({
- className,
- ...props
-}: React.ComponentProps<"li">) {
- return (
-
- )
+function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<"li">) {
+ return (
+
+ )
}
function SidebarMenuSubButton({
- asChild = false,
- size = "md",
- isActive = false,
- className,
- ...props
+ asChild = false,
+ size = "md",
+ isActive = false,
+ className,
+ ...props
}: React.ComponentProps<"a"> & {
- asChild?: boolean
- size?: "sm" | "md"
- isActive?: boolean
+ asChild?: boolean
+ size?: "sm" | "md"
+ isActive?: boolean
}) {
- const Comp = asChild ? Slot.Root : "a"
+ const Comp = asChild ? Slot.Root : "a"
- return (
- span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
- className
- )}
- {...props}
- />
- )
+ return (
+ span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
+ className,
+ )}
+ {...props}
+ />
+ )
}
export {
- Sidebar,
- SidebarContent,
- SidebarFooter,
- SidebarGroup,
- SidebarGroupAction,
- SidebarGroupContent,
- SidebarGroupLabel,
- SidebarHeader,
- SidebarInput,
- SidebarInset,
- SidebarMenu,
- SidebarMenuAction,
- SidebarMenuBadge,
- SidebarMenuButton,
- SidebarMenuItem,
- SidebarMenuSkeleton,
- SidebarMenuSub,
- SidebarMenuSubButton,
- SidebarMenuSubItem,
- SidebarProvider,
- SidebarRail,
- SidebarSeparator,
- SidebarTrigger,
- useSidebar,
+ Sidebar,
+ SidebarContent,
+ SidebarFooter,
+ SidebarGroup,
+ SidebarGroupAction,
+ SidebarGroupContent,
+ SidebarGroupLabel,
+ SidebarHeader,
+ SidebarInput,
+ SidebarInset,
+ SidebarMenu,
+ SidebarMenuAction,
+ SidebarMenuBadge,
+ SidebarMenuButton,
+ SidebarMenuItem,
+ SidebarMenuSkeleton,
+ SidebarMenuSub,
+ SidebarMenuSubButton,
+ SidebarMenuSubItem,
+ SidebarProvider,
+ SidebarRail,
+ SidebarSeparator,
+ SidebarTrigger,
+ useSidebar,
}
diff --git a/apps/admin-dashboard/src/components/ui/skeleton.tsx b/apps/admin-dashboard/src/components/ui/skeleton.tsx
index 0118624..6c726b3 100644
--- a/apps/admin-dashboard/src/components/ui/skeleton.tsx
+++ b/apps/admin-dashboard/src/components/ui/skeleton.tsx
@@ -1,13 +1,13 @@
import { cn } from "@/lib/utils"
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
+ return (
+
+ )
}
export { Skeleton }
diff --git a/apps/admin-dashboard/src/components/ui/sonner.tsx b/apps/admin-dashboard/src/components/ui/sonner.tsx
index 082fc8c..a6296fd 100644
--- a/apps/admin-dashboard/src/components/ui/sonner.tsx
+++ b/apps/admin-dashboard/src/components/ui/sonner.tsx
@@ -1,49 +1,46 @@
"use client"
-import { useTheme } from "@/components/theme-provider"
+import {
+ CircleCheckIcon,
+ InfoIcon,
+ TriangleAlertIcon,
+ OctagonXIcon,
+ Loader2Icon,
+} from "lucide-react"
import { Toaster as Sonner, type ToasterProps } from "sonner"
-import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react"
+
+import { useTheme } from "@/components/theme-provider"
const Toaster = ({ ...props }: ToasterProps) => {
- const { theme = "system" } = useTheme()
+ const { theme = "system" } = useTheme()
- return (
-
- ),
- info: (
-
- ),
- warning: (
-
- ),
- error: (
-
- ),
- loading: (
-
- ),
- }}
- style={
- {
- "--normal-bg": "var(--popover)",
- "--normal-text": "var(--popover-foreground)",
- "--normal-border": "var(--border)",
- "--border-radius": "var(--radius)",
- } as React.CSSProperties
- }
- toastOptions={{
- classNames: {
- toast: "cn-toast",
- },
- }}
- {...props}
- />
- )
+ return (
+ ,
+ info: ,
+ warning: ,
+ error: ,
+ loading: ,
+ }}
+ style={
+ {
+ "--normal-bg": "var(--popover)",
+ "--normal-text": "var(--popover-foreground)",
+ "--normal-border": "var(--border)",
+ "--border-radius": "var(--radius)",
+ } as React.CSSProperties
+ }
+ toastOptions={{
+ classNames: {
+ toast: "cn-toast",
+ },
+ }}
+ {...props}
+ />
+ )
}
export { Toaster }
diff --git a/apps/admin-dashboard/src/components/ui/switch.tsx b/apps/admin-dashboard/src/components/ui/switch.tsx
index 1ca9db2..9ea999e 100644
--- a/apps/admin-dashboard/src/components/ui/switch.tsx
+++ b/apps/admin-dashboard/src/components/ui/switch.tsx
@@ -1,33 +1,33 @@
"use client"
-import * as React from "react"
import { Switch as SwitchPrimitive } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
function Switch({
- className,
- size = "default",
- ...props
+ className,
+ size = "default",
+ ...props
}: React.ComponentProps & {
- size?: "sm" | "default"
+ size?: "sm" | "default"
}) {
- return (
-
-
-
- )
+ return (
+
+
+
+ )
}
export { Switch }
diff --git a/apps/admin-dashboard/src/components/ui/tooltip.tsx b/apps/admin-dashboard/src/components/ui/tooltip.tsx
index bb1ea52..a9bad5d 100644
--- a/apps/admin-dashboard/src/components/ui/tooltip.tsx
+++ b/apps/admin-dashboard/src/components/ui/tooltip.tsx
@@ -1,57 +1,53 @@
"use client"
-import * as React from "react"
import { Tooltip as TooltipPrimitive } from "radix-ui"
+import * as React from "react"
import { cn } from "@/lib/utils"
function TooltipProvider({
- delayDuration = 0,
- ...props
+ delayDuration = 0,
+ ...props
}: React.ComponentProps) {
- return (
-
- )
+ return (
+
+ )
}
-function Tooltip({
- ...props
-}: React.ComponentProps) {
- return
+function Tooltip({ ...props }: React.ComponentProps) {
+ return
}
-function TooltipTrigger({
- ...props
-}: React.ComponentProps) {
- return
+function TooltipTrigger({ ...props }: React.ComponentProps) {
+ return
}
function TooltipContent({
- className,
- sideOffset = 0,
- children,
- ...props
+ className,
+ sideOffset = 0,
+ children,
+ ...props
}: React.ComponentProps) {
- return (
-
-
- {children}
-
-
-
- )
+ return (
+
+
+ {children}
+
+
+
+ )
}
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
diff --git a/apps/admin-dashboard/src/hooks/use-mobile.ts b/apps/admin-dashboard/src/hooks/use-mobile.ts
index 2b0fe1d..283bbb4 100644
--- a/apps/admin-dashboard/src/hooks/use-mobile.ts
+++ b/apps/admin-dashboard/src/hooks/use-mobile.ts
@@ -3,17 +3,17 @@ import * as React from "react"
const MOBILE_BREAKPOINT = 768
export function useIsMobile() {
- const [isMobile, setIsMobile] = React.useState(undefined)
+ const [isMobile, setIsMobile] = React.useState(undefined)
- React.useEffect(() => {
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
- const onChange = () => {
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
- }
- mql.addEventListener("change", onChange)
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
- return () => mql.removeEventListener("change", onChange)
- }, [])
+ React.useEffect(() => {
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
+ const onChange = () => {
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
+ }
+ mql.addEventListener("change", onChange)
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
+ return () => mql.removeEventListener("change", onChange)
+ }, [])
- return !!isMobile
+ return !!isMobile
}
diff --git a/apps/admin-dashboard/src/index.css b/apps/admin-dashboard/src/index.css
index 931eb05..75aedd4 100644
--- a/apps/admin-dashboard/src/index.css
+++ b/apps/admin-dashboard/src/index.css
@@ -6,124 +6,124 @@
@custom-variant dark (&:is(.dark *));
:root {
- --background: oklch(1 0 0);
- --foreground: oklch(0.145 0 0);
- --card: oklch(1 0 0);
- --card-foreground: oklch(0.145 0 0);
- --popover: oklch(1 0 0);
- --popover-foreground: oklch(0.145 0 0);
- --primary: oklch(0.511 0.096 186.391);
- --primary-foreground: oklch(0.984 0.014 180.72);
- --secondary: oklch(0.967 0.001 286.375);
- --secondary-foreground: oklch(0.21 0.006 285.885);
- --muted: oklch(0.97 0 0);
- --muted-foreground: oklch(0.556 0 0);
- --accent: oklch(0.97 0 0);
- --accent-foreground: oklch(0.205 0 0);
- --destructive: oklch(0.577 0.245 27.325);
- --border: oklch(0.922 0 0);
- --input: oklch(0.922 0 0);
- --ring: oklch(0.708 0 0);
- --chart-1: oklch(0.855 0.138 181.071);
- --chart-2: oklch(0.704 0.14 182.503);
- --chart-3: oklch(0.6 0.118 184.704);
- --chart-4: oklch(0.511 0.096 186.391);
- --chart-5: oklch(0.437 0.078 188.216);
- --radius: 0.625rem;
- --sidebar: oklch(0.985 0 0);
- --sidebar-foreground: oklch(0.145 0 0);
- --sidebar-primary: oklch(0.6 0.118 184.704);
- --sidebar-primary-foreground: oklch(0.984 0.014 180.72);
- --sidebar-accent: oklch(0.97 0 0);
- --sidebar-accent-foreground: oklch(0.205 0 0);
- --sidebar-border: oklch(0.922 0 0);
- --sidebar-ring: oklch(0.708 0 0);
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.511 0.096 186.391);
+ --primary-foreground: oklch(0.984 0.014 180.72);
+ --secondary: oklch(0.967 0.001 286.375);
+ --secondary-foreground: oklch(0.21 0.006 285.885);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.855 0.138 181.071);
+ --chart-2: oklch(0.704 0.14 182.503);
+ --chart-3: oklch(0.6 0.118 184.704);
+ --chart-4: oklch(0.511 0.096 186.391);
+ --chart-5: oklch(0.437 0.078 188.216);
+ --radius: 0.625rem;
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.6 0.118 184.704);
+ --sidebar-primary-foreground: oklch(0.984 0.014 180.72);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
}
.dark {
- --background: oklch(0.145 0 0);
- --foreground: oklch(0.985 0 0);
- --card: oklch(0.205 0 0);
- --card-foreground: oklch(0.985 0 0);
- --popover: oklch(0.205 0 0);
- --popover-foreground: oklch(0.985 0 0);
- --primary: oklch(0.437 0.078 188.216);
- --primary-foreground: oklch(0.984 0.014 180.72);
- --secondary: oklch(0.274 0.006 286.033);
- --secondary-foreground: oklch(0.985 0 0);
- --muted: oklch(0.269 0 0);
- --muted-foreground: oklch(0.708 0 0);
- --accent: oklch(0.269 0 0);
- --accent-foreground: oklch(0.985 0 0);
- --destructive: oklch(0.704 0.191 22.216);
- --border: oklch(1 0 0 / 10%);
- --input: oklch(1 0 0 / 15%);
- --ring: oklch(0.556 0 0);
- --chart-1: oklch(0.855 0.138 181.071);
- --chart-2: oklch(0.704 0.14 182.503);
- --chart-3: oklch(0.6 0.118 184.704);
- --chart-4: oklch(0.511 0.096 186.391);
- --chart-5: oklch(0.437 0.078 188.216);
- --sidebar: oklch(0.205 0 0);
- --sidebar-foreground: oklch(0.985 0 0);
- --sidebar-primary: oklch(0.704 0.14 182.503);
- --sidebar-primary-foreground: oklch(0.277 0.046 192.524);
- --sidebar-accent: oklch(0.269 0 0);
- --sidebar-accent-foreground: oklch(0.985 0 0);
- --sidebar-border: oklch(1 0 0 / 10%);
- --sidebar-ring: oklch(0.556 0 0);
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.205 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.437 0.078 188.216);
+ --primary-foreground: oklch(0.984 0.014 180.72);
+ --secondary: oklch(0.274 0.006 286.033);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.556 0 0);
+ --chart-1: oklch(0.855 0.138 181.071);
+ --chart-2: oklch(0.704 0.14 182.503);
+ --chart-3: oklch(0.6 0.118 184.704);
+ --chart-4: oklch(0.511 0.096 186.391);
+ --chart-5: oklch(0.437 0.078 188.216);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.704 0.14 182.503);
+ --sidebar-primary-foreground: oklch(0.277 0.046 192.524);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.556 0 0);
}
@theme inline {
- --font-sans: 'Inter Variable', sans-serif;
- --color-sidebar-ring: var(--sidebar-ring);
- --color-sidebar-border: var(--sidebar-border);
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
- --color-sidebar-accent: var(--sidebar-accent);
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
- --color-sidebar-primary: var(--sidebar-primary);
- --color-sidebar-foreground: var(--sidebar-foreground);
- --color-sidebar: var(--sidebar);
- --color-chart-5: var(--chart-5);
- --color-chart-4: var(--chart-4);
- --color-chart-3: var(--chart-3);
- --color-chart-2: var(--chart-2);
- --color-chart-1: var(--chart-1);
- --color-ring: var(--ring);
- --color-input: var(--input);
- --color-border: var(--border);
- --color-destructive: var(--destructive);
- --color-accent-foreground: var(--accent-foreground);
- --color-accent: var(--accent);
- --color-muted-foreground: var(--muted-foreground);
- --color-muted: var(--muted);
- --color-secondary-foreground: var(--secondary-foreground);
- --color-secondary: var(--secondary);
- --color-primary-foreground: var(--primary-foreground);
- --color-primary: var(--primary);
- --color-popover-foreground: var(--popover-foreground);
- --color-popover: var(--popover);
- --color-card-foreground: var(--card-foreground);
- --color-card: var(--card);
- --color-foreground: var(--foreground);
- --color-background: var(--background);
- --radius-sm: calc(var(--radius) * 0.6);
- --radius-md: calc(var(--radius) * 0.8);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) * 1.4);
- --radius-2xl: calc(var(--radius) * 1.8);
- --radius-3xl: calc(var(--radius) * 2.2);
- --radius-4xl: calc(var(--radius) * 2.6);
+ --font-sans: "Inter Variable", sans-serif;
+ --color-sidebar-ring: var(--sidebar-ring);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar: var(--sidebar);
+ --color-chart-5: var(--chart-5);
+ --color-chart-4: var(--chart-4);
+ --color-chart-3: var(--chart-3);
+ --color-chart-2: var(--chart-2);
+ --color-chart-1: var(--chart-1);
+ --color-ring: var(--ring);
+ --color-input: var(--input);
+ --color-border: var(--border);
+ --color-destructive: var(--destructive);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-accent: var(--accent);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-muted: var(--muted);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-secondary: var(--secondary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-primary: var(--primary);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-popover: var(--popover);
+ --color-card-foreground: var(--card-foreground);
+ --color-card: var(--card);
+ --color-foreground: var(--foreground);
+ --color-background: var(--background);
+ --radius-sm: calc(var(--radius) * 0.6);
+ --radius-md: calc(var(--radius) * 0.8);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) * 1.4);
+ --radius-2xl: calc(var(--radius) * 1.8);
+ --radius-3xl: calc(var(--radius) * 2.2);
+ --radius-4xl: calc(var(--radius) * 2.6);
}
@layer base {
- * {
- @apply border-border outline-ring/50;
- }
- body {
- @apply bg-background text-foreground select-none;
- }
- html {
- @apply font-sans;
- }
-}
\ No newline at end of file
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground select-none;
+ }
+ html {
+ @apply font-sans;
+ }
+}
diff --git a/apps/admin-dashboard/src/lib/api.ts b/apps/admin-dashboard/src/lib/api.ts
index 772b534..2c6873f 100644
--- a/apps/admin-dashboard/src/lib/api.ts
+++ b/apps/admin-dashboard/src/lib/api.ts
@@ -1,197 +1,217 @@
import { getServerUrl } from "./server-url"
function apiBase() {
- return `${getServerUrl()}/api/admin`
+ return `${getServerUrl()}/api/admin`
}
function serverBase() {
- return `${getServerUrl()}/api`
+ return `${getServerUrl()}/api`
}
export interface ConfigFieldDef {
- type: "string" | "number" | "select" | "multiselect"
- label: string
- required?: boolean
- description?: string
- secret?: boolean
- defaultValue?: string | number | string[]
- options?: { label: string; value: string }[]
+ type: "string" | "number" | "select" | "multiselect"
+ label: string
+ required?: boolean
+ description?: string
+ secret?: boolean
+ defaultValue?: string | number | string[]
+ options?: { label: string; value: string }[]
}
export interface SourceDefinition {
- id: string
- name: string
- description: string
- alwaysEnabled?: boolean
- fields: Record
+ id: string
+ name: string
+ description: string
+ alwaysEnabled?: boolean
+ fields: Record
}
export interface SourceConfig {
- sourceId: string
- enabled: boolean
- config: Record
+ sourceId: string
+ enabled: boolean
+ config: Record
}
const sourceDefinitions: SourceDefinition[] = [
- {
- id: "aelis.location",
- name: "Location",
- description: "Device location provider. Always enabled as a dependency for other sources.",
- alwaysEnabled: true,
- fields: {},
- },
- {
- id: "aelis.weather",
- name: "WeatherKit",
- description: "Apple WeatherKit weather data. Requires Apple Developer credentials.",
- fields: {
- privateKey: { type: "string", label: "Private Key", required: true, secret: true, description: "Apple WeatherKit private key (PEM format)" },
- keyId: { type: "string", label: "Key ID", required: true, secret: true },
- teamId: { type: "string", label: "Team ID", required: true, secret: true },
- serviceId: { type: "string", label: "Service ID", required: true, secret: true },
- units: { type: "select", label: "Units", options: [{ label: "Metric", value: "metric" }, { label: "Imperial", value: "imperial" }], defaultValue: "metric" },
- hourlyLimit: { type: "number", label: "Hourly Forecast Limit", defaultValue: 12, description: "Number of hourly forecasts to include" },
- dailyLimit: { type: "number", label: "Daily Forecast Limit", defaultValue: 7, description: "Number of daily forecasts to include" },
- },
- },
- {
- id: "aelis.tfl",
- name: "TfL",
- description: "Transport for London tube line status alerts.",
- fields: {
- lines: {
- type: "multiselect",
- label: "Lines",
- description: "Lines to monitor. Leave empty for all lines.",
- defaultValue: [],
- options: [
- { label: "Bakerloo", value: "bakerloo" },
- { label: "Central", value: "central" },
- { label: "Circle", value: "circle" },
- { label: "District", value: "district" },
- { label: "Hammersmith & City", value: "hammersmith-city" },
- { label: "Jubilee", value: "jubilee" },
- { label: "Metropolitan", value: "metropolitan" },
- { label: "Northern", value: "northern" },
- { label: "Piccadilly", value: "piccadilly" },
- { label: "Victoria", value: "victoria" },
- { label: "Waterloo & City", value: "waterloo-city" },
- { label: "Lioness", value: "lioness" },
- { label: "Mildmay", value: "mildmay" },
- { label: "Windrush", value: "windrush" },
- { label: "Weaver", value: "weaver" },
- { label: "Suffragette", value: "suffragette" },
- { label: "Liberty", value: "liberty" },
- { label: "Elizabeth", value: "elizabeth" },
- ],
- },
- },
- },
+ {
+ id: "aelis.location",
+ name: "Location",
+ description: "Device location provider. Always enabled as a dependency for other sources.",
+ alwaysEnabled: true,
+ fields: {},
+ },
+ {
+ id: "aelis.weather",
+ name: "WeatherKit",
+ description: "Apple WeatherKit weather data. Requires Apple Developer credentials.",
+ fields: {
+ privateKey: {
+ type: "string",
+ label: "Private Key",
+ required: true,
+ secret: true,
+ description: "Apple WeatherKit private key (PEM format)",
+ },
+ keyId: { type: "string", label: "Key ID", required: true, secret: true },
+ teamId: { type: "string", label: "Team ID", required: true, secret: true },
+ serviceId: { type: "string", label: "Service ID", required: true, secret: true },
+ units: {
+ type: "select",
+ label: "Units",
+ options: [
+ { label: "Metric", value: "metric" },
+ { label: "Imperial", value: "imperial" },
+ ],
+ defaultValue: "metric",
+ },
+ hourlyLimit: {
+ type: "number",
+ label: "Hourly Forecast Limit",
+ defaultValue: 12,
+ description: "Number of hourly forecasts to include",
+ },
+ dailyLimit: {
+ type: "number",
+ label: "Daily Forecast Limit",
+ defaultValue: 7,
+ description: "Number of daily forecasts to include",
+ },
+ },
+ },
+ {
+ id: "aelis.tfl",
+ name: "TfL",
+ description: "Transport for London tube line status alerts.",
+ fields: {
+ lines: {
+ type: "multiselect",
+ label: "Lines",
+ description: "Lines to monitor. Leave empty for all lines.",
+ defaultValue: [],
+ options: [
+ { label: "Bakerloo", value: "bakerloo" },
+ { label: "Central", value: "central" },
+ { label: "Circle", value: "circle" },
+ { label: "District", value: "district" },
+ { label: "Hammersmith & City", value: "hammersmith-city" },
+ { label: "Jubilee", value: "jubilee" },
+ { label: "Metropolitan", value: "metropolitan" },
+ { label: "Northern", value: "northern" },
+ { label: "Piccadilly", value: "piccadilly" },
+ { label: "Victoria", value: "victoria" },
+ { label: "Waterloo & City", value: "waterloo-city" },
+ { label: "Lioness", value: "lioness" },
+ { label: "Mildmay", value: "mildmay" },
+ { label: "Windrush", value: "windrush" },
+ { label: "Weaver", value: "weaver" },
+ { label: "Suffragette", value: "suffragette" },
+ { label: "Liberty", value: "liberty" },
+ { label: "Elizabeth", value: "elizabeth" },
+ ],
+ },
+ },
+ },
]
export function fetchSources(): Promise {
- return Promise.resolve(sourceDefinitions)
+ return Promise.resolve(sourceDefinitions)
}
-export async function fetchSourceConfig(
- sourceId: string,
-): Promise {
- const res = await fetch(`${serverBase()}/sources/${sourceId}`, {
- credentials: "include",
- })
- if (res.status === 404) return null
- if (!res.ok) throw new Error(`Failed to fetch source config: ${res.status}`)
- const data = (await res.json()) as { enabled: boolean; config: Record }
- return { sourceId, enabled: data.enabled, config: data.config }
+export async function fetchSourceConfig(sourceId: string): Promise {
+ const res = await fetch(`${serverBase()}/sources/${sourceId}`, {
+ credentials: "include",
+ })
+ if (res.status === 404) return null
+ if (!res.ok) throw new Error(`Failed to fetch source config: ${res.status}`)
+ const data = (await res.json()) as { enabled: boolean; config: Record }
+ return { sourceId, enabled: data.enabled, config: data.config }
}
export async function fetchConfigs(): Promise {
- const results = await Promise.all(
- sourceDefinitions.map((s) => fetchSourceConfig(s.id)),
- )
- return results.filter((c): c is SourceConfig => c !== null)
+ const results = await Promise.all(sourceDefinitions.map((s) => fetchSourceConfig(s.id)))
+ return results.filter((c): c is SourceConfig => c !== null)
}
export async function replaceSource(
- sourceId: string,
- body: { enabled: boolean; config: unknown },
+ sourceId: string,
+ body: { enabled: boolean; config: unknown },
): Promise {
- const res = await fetch(`${serverBase()}/sources/${sourceId}`, {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- credentials: "include",
- body: JSON.stringify(body),
- })
- if (!res.ok) {
- const data = (await res.json()) as { error?: string }
- throw new Error(data.error ?? `Failed to replace source config: ${res.status}`)
- }
+ const res = await fetch(`${serverBase()}/sources/${sourceId}`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ credentials: "include",
+ body: JSON.stringify(body),
+ })
+ if (!res.ok) {
+ const data = (await res.json()) as { error?: string }
+ throw new Error(data.error ?? `Failed to replace source config: ${res.status}`)
+ }
}
export async function updateProviderConfig(
- sourceId: string,
- body: Record,
+ sourceId: string,
+ body: Record,
): Promise {
- const res = await fetch(`${apiBase()}/${sourceId}/config`, {
- method: "PUT",
- headers: { "Content-Type": "application/json" },
- credentials: "include",
- body: JSON.stringify(body),
- })
- if (!res.ok) {
- const data = (await res.json()) as { error?: string }
- throw new Error(data.error ?? `Failed to update provider config: ${res.status}`)
- }
+ const res = await fetch(`${apiBase()}/${sourceId}/config`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ credentials: "include",
+ body: JSON.stringify(body),
+ })
+ if (!res.ok) {
+ const data = (await res.json()) as { error?: string }
+ throw new Error(data.error ?? `Failed to update provider config: ${res.status}`)
+ }
}
export interface LocationInput {
- lat: number
- lng: number
- accuracy: number
+ lat: number
+ lng: number
+ accuracy: number
}
export async function pushLocation(location: LocationInput): Promise {
- const res = await fetch(`${serverBase()}/location`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- credentials: "include",
- body: JSON.stringify({
- ...location,
- timestamp: new Date().toISOString(),
- }),
- })
- if (!res.ok) {
- const data = (await res.json()) as { error?: string }
- throw new Error(data.error ?? `Failed to push location: ${res.status}`)
- }
+ const res = await fetch(`${serverBase()}/location`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ credentials: "include",
+ body: JSON.stringify({
+ ...location,
+ timestamp: new Date().toISOString(),
+ }),
+ })
+ if (!res.ok) {
+ const data = (await res.json()) as { error?: string }
+ throw new Error(data.error ?? `Failed to push location: ${res.status}`)
+ }
}
export interface FeedItemSlot {
- description: string
- content: string | null
+ description: string
+ content: string | null
}
export interface FeedItem {
- id: string
- sourceId: string
- type: string
- timestamp: string
- data: Record
- signals?: {
- urgency?: number
- timeRelevance?: string
- }
- slots?: Record
- ui?: unknown
+ id: string
+ sourceId: string
+ type: string
+ timestamp: string
+ data: Record
+ signals?: {
+ urgency?: number
+ timeRelevance?: string
+ }
+ slots?: Record
+ ui?: unknown
}
export interface FeedResponse {
- items: FeedItem[]
- errors: { sourceId: string; error: string }[]
+ items: FeedItem[]
+ errors: { sourceId: string; error: string }[]
}
export async function fetchFeed(): Promise {
- const res = await fetch(`${serverBase()}/feed`, { credentials: "include" })
- if (!res.ok) throw new Error(`Failed to fetch feed: ${res.status}`)
- return res.json() as Promise
+ const res = await fetch(`${serverBase()}/feed`, { credentials: "include" })
+ if (!res.ok) throw new Error(`Failed to fetch feed: ${res.status}`)
+ return res.json() as Promise
}
diff --git a/apps/admin-dashboard/src/lib/auth.ts b/apps/admin-dashboard/src/lib/auth.ts
index 328f2d0..97304a4 100644
--- a/apps/admin-dashboard/src/lib/auth.ts
+++ b/apps/admin-dashboard/src/lib/auth.ts
@@ -1,47 +1,47 @@
import { getServerUrl } from "./server-url"
function authBase() {
- return `${getServerUrl()}/api/auth`
+ return `${getServerUrl()}/api/auth`
}
export interface AuthUser {
- id: string
- name: string
- email: string
- image: string | null
+ id: string
+ name: string
+ email: string
+ image: string | null
}
export interface AuthSession {
- user: AuthUser
- session: { id: string; token: string }
+ user: AuthUser
+ session: { id: string; token: string }
}
export async function getSession(): Promise {
- const res = await fetch(`${authBase()}/get-session`, {
- credentials: "include",
- })
- if (!res.ok) return null
- const data = (await res.json()) as AuthSession | null
- return data
+ const res = await fetch(`${authBase()}/get-session`, {
+ credentials: "include",
+ })
+ if (!res.ok) return null
+ const data = (await res.json()) as AuthSession | null
+ return data
}
export async function signIn(email: string, password: string): Promise {
- const res = await fetch(`${authBase()}/sign-in/email`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- credentials: "include",
- body: JSON.stringify({ email, password }),
- })
- if (!res.ok) {
- const data = (await res.json()) as { message?: string }
- throw new Error(data.message ?? `Sign in failed: ${res.status}`)
- }
- return (await res.json()) as AuthSession
+ const res = await fetch(`${authBase()}/sign-in/email`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ credentials: "include",
+ body: JSON.stringify({ email, password }),
+ })
+ if (!res.ok) {
+ const data = (await res.json()) as { message?: string }
+ throw new Error(data.message ?? `Sign in failed: ${res.status}`)
+ }
+ return (await res.json()) as AuthSession
}
export async function signOut(): Promise {
- await fetch(`${authBase()}/sign-out`, {
- method: "POST",
- credentials: "include",
- })
+ await fetch(`${authBase()}/sign-out`, {
+ method: "POST",
+ credentials: "include",
+ })
}
diff --git a/apps/admin-dashboard/src/lib/server-url.ts b/apps/admin-dashboard/src/lib/server-url.ts
index 77cee5c..606f594 100644
--- a/apps/admin-dashboard/src/lib/server-url.ts
+++ b/apps/admin-dashboard/src/lib/server-url.ts
@@ -2,9 +2,9 @@ const STORAGE_KEY = "aelis-server-url"
const DEFAULT_URL = "https://3000--019cf276-6ed6-7529-a425-210182693908.eu-runner.flex.doptig.cloud"
export function getServerUrl(): string {
- return localStorage.getItem(STORAGE_KEY) ?? DEFAULT_URL
+ return localStorage.getItem(STORAGE_KEY) ?? DEFAULT_URL
}
export function setServerUrl(url: string): void {
- localStorage.setItem(STORAGE_KEY, url.replace(/\/+$/, ""))
+ localStorage.setItem(STORAGE_KEY, url.replace(/\/+$/, ""))
}
diff --git a/apps/admin-dashboard/src/lib/utils.ts b/apps/admin-dashboard/src/lib/utils.ts
index bd0c391..9a7122c 100644
--- a/apps/admin-dashboard/src/lib/utils.ts
+++ b/apps/admin-dashboard/src/lib/utils.ts
@@ -2,5 +2,5 @@ import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs))
}
diff --git a/apps/admin-dashboard/src/main.tsx b/apps/admin-dashboard/src/main.tsx
index b7c5a84..4827c57 100644
--- a/apps/admin-dashboard/src/main.tsx
+++ b/apps/admin-dashboard/src/main.tsx
@@ -3,26 +3,27 @@ import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import "./index.css"
-import App from "./App.tsx"
import { ThemeProvider } from "@/components/theme-provider.tsx"
import { Toaster } from "@/components/ui/sonner.tsx"
+import App from "./App.tsx"
+
const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retry: false,
- refetchOnWindowFocus: false,
- },
- },
+ defaultOptions: {
+ queries: {
+ retry: false,
+ refetchOnWindowFocus: false,
+ },
+ },
})
createRoot(document.getElementById("root")!).render(
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ ,
)
diff --git a/apps/admin-dashboard/src/route-tree.gen.ts b/apps/admin-dashboard/src/route-tree.gen.ts
index 3e629da..606f41e 100644
--- a/apps/admin-dashboard/src/route-tree.gen.ts
+++ b/apps/admin-dashboard/src/route-tree.gen.ts
@@ -1,15 +1,11 @@
import { Route as rootRoute } from "./routes/__root"
-import { Route as loginRoute } from "./routes/login"
import { Route as dashboardRoute } from "./routes/_dashboard"
-import { Route as dashboardIndexRoute } from "./routes/_dashboard/index"
import { Route as dashboardFeedRoute } from "./routes/_dashboard/feed"
+import { Route as dashboardIndexRoute } from "./routes/_dashboard/index"
import { Route as dashboardSourceRoute } from "./routes/_dashboard/sources.$sourceId"
+import { Route as loginRoute } from "./routes/login"
export const routeTree = rootRoute.addChildren([
- loginRoute,
- dashboardRoute.addChildren([
- dashboardIndexRoute,
- dashboardFeedRoute,
- dashboardSourceRoute,
- ]),
+ loginRoute,
+ dashboardRoute.addChildren([dashboardIndexRoute, dashboardFeedRoute, dashboardSourceRoute]),
])
diff --git a/apps/admin-dashboard/src/routes/__root.tsx b/apps/admin-dashboard/src/routes/__root.tsx
index 0d007d5..efa7c25 100644
--- a/apps/admin-dashboard/src/routes/__root.tsx
+++ b/apps/admin-dashboard/src/routes/__root.tsx
@@ -1,13 +1,15 @@
-import { createRootRouteWithContext, Outlet } from "@tanstack/react-router"
import type { QueryClient } from "@tanstack/react-query"
+
+import { createRootRouteWithContext, Outlet } from "@tanstack/react-router"
+
import { TooltipProvider } from "@/components/ui/tooltip"
export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
- component: function RootLayout() {
- return (
-
-
-
- )
- },
+ component: function RootLayout() {
+ return (
+
+
+
+ )
+ },
})
diff --git a/apps/admin-dashboard/src/routes/_dashboard.tsx b/apps/admin-dashboard/src/routes/_dashboard.tsx
index eba5b8f..4e695fb 100644
--- a/apps/admin-dashboard/src/routes/_dashboard.tsx
+++ b/apps/admin-dashboard/src/routes/_dashboard.tsx
@@ -1,208 +1,219 @@
-import { createRoute, Outlet, redirect, useMatchRoute, useNavigate, Link } from "@tanstack/react-router"
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import {
- Calendar,
- CalendarDays,
- CircleDot,
- CloudSun,
- Loader2,
- TrainFront,
- LogOut,
- MapPin,
- Rss,
- Server,
- TriangleAlert,
+ createRoute,
+ Outlet,
+ redirect,
+ useMatchRoute,
+ useNavigate,
+ Link,
+} from "@tanstack/react-router"
+import {
+ Calendar,
+ CalendarDays,
+ CircleDot,
+ CloudSun,
+ Loader2,
+ TrainFront,
+ LogOut,
+ MapPin,
+ Rss,
+ Server,
+ TriangleAlert,
} from "lucide-react"
-import { fetchConfigs, fetchSources } from "@/lib/api"
-import { getSession, signOut } from "@/lib/auth"
-
import { Alert, AlertDescription } from "@/components/ui/alert"
import { Button } from "@/components/ui/button"
import { Separator } from "@/components/ui/separator"
import {
- Sidebar,
- SidebarContent,
- SidebarGroup,
- SidebarGroupContent,
- SidebarGroupLabel,
- SidebarHeader,
- SidebarInset,
- SidebarMenu,
- SidebarMenuBadge,
- SidebarMenuButton,
- SidebarMenuItem,
- SidebarProvider,
- SidebarTrigger,
+ Sidebar,
+ SidebarContent,
+ SidebarGroup,
+ SidebarGroupContent,
+ SidebarGroupLabel,
+ SidebarHeader,
+ SidebarInset,
+ SidebarMenu,
+ SidebarMenuBadge,
+ SidebarMenuButton,
+ SidebarMenuItem,
+ SidebarProvider,
+ SidebarTrigger,
} from "@/components/ui/sidebar"
+import { fetchConfigs, fetchSources } from "@/lib/api"
+import { getSession, signOut } from "@/lib/auth"
+
import { Route as rootRoute } from "./__root"
const SOURCE_ICONS: Record> = {
- "aelis.location": MapPin,
- "aelis.weather": CloudSun,
- "aelis.caldav": CalendarDays,
- "aelis.google-calendar": Calendar,
- "aelis.tfl": TrainFront,
+ "aelis.location": MapPin,
+ "aelis.weather": CloudSun,
+ "aelis.caldav": CalendarDays,
+ "aelis.google-calendar": Calendar,
+ "aelis.tfl": TrainFront,
}
export const Route = createRoute({
- getParentRoute: () => rootRoute,
- id: "dashboard",
- beforeLoad: async ({ context }) => {
- let session: Awaited> | null = null
- try {
- session = await context.queryClient.ensureQueryData({
- queryKey: ["session"],
- queryFn: getSession,
- })
- } catch {
- throw redirect({ to: "/login" })
- }
- if (!session?.user) {
- throw redirect({ to: "/login" })
- }
- return { user: session.user }
- },
- component: DashboardLayout,
- pendingComponent: () => (
-
-
-
- ),
+ getParentRoute: () => rootRoute,
+ id: "dashboard",
+ beforeLoad: async ({ context }) => {
+ let session: Awaited> | null = null
+ try {
+ session = await context.queryClient.ensureQueryData({
+ queryKey: ["session"],
+ queryFn: getSession,
+ })
+ } catch {
+ throw redirect({ to: "/login" })
+ }
+ if (!session?.user) {
+ throw redirect({ to: "/login" })
+ }
+ return { user: session.user }
+ },
+ component: DashboardLayout,
+ pendingComponent: () => (
+
+
+
+ ),
})
function DashboardLayout() {
- const { user } = Route.useRouteContext()
- const navigate = useNavigate()
- const queryClient = useQueryClient()
- const matchRoute = useMatchRoute()
+ const { user } = Route.useRouteContext()
+ const navigate = useNavigate()
+ const queryClient = useQueryClient()
+ const matchRoute = useMatchRoute()
- const { data: sources = [] } = useQuery({
- queryKey: ["sources"],
- queryFn: fetchSources,
- })
+ const { data: sources = [] } = useQuery({
+ queryKey: ["sources"],
+ queryFn: fetchSources,
+ })
- const {
- data: configs = [],
- error: configsError,
- refetch: refetchConfigs,
- } = useQuery({
- queryKey: ["configs"],
- queryFn: fetchConfigs,
- })
+ const {
+ data: configs = [],
+ error: configsError,
+ refetch: refetchConfigs,
+ } = useQuery({
+ queryKey: ["configs"],
+ queryFn: fetchConfigs,
+ })
- const logoutMutation = useMutation({
- mutationFn: signOut,
- onSuccess() {
- queryClient.setQueryData(["session"], null)
- queryClient.clear()
- navigate({ to: "/login" })
- },
- })
+ const logoutMutation = useMutation({
+ mutationFn: signOut,
+ onSuccess() {
+ queryClient.setQueryData(["session"], null)
+ queryClient.clear()
+ navigate({ to: "/login" })
+ },
+ })
- const error = configsError?.message ?? null
- const configMap = new Map(configs.map((c) => [c.sourceId, c]))
+ const error = configsError?.message ?? null
+ const configMap = new Map(configs.map((c) => [c.sourceId, c]))
- return (
-
-
-
-
-
-
{user.name}
-
{user.email}
-
-
-
-
-
-
- General
-
-
-
-
-
-
- Server
-
-
-
-
-
-
-
- Feed
-
-
-
-
-
-
+ return (
+
+
+
+
+
+
{user.name}
+
{user.email}
+
+
+
+
+
+
+ General
+
+
+
+
+
+
+ Server
+
+
+
+
+
+
+
+ Feed
+
+
+
+
+
+
-
- Sources
-
-
- {sources.map((source) => {
- const Icon = SOURCE_ICONS[source.id] ?? CircleDot
- const cfg = configMap.get(source.id)
- const isEnabled = source.alwaysEnabled || cfg?.enabled
- return (
-
-
-
-
- {source.name}
-
-
- {isEnabled && (
-
-
-
- )}
-
- )
- })}
-
-
-
-
-
+
+ Sources
+
+
+ {sources.map((source) => {
+ const Icon = SOURCE_ICONS[source.id] ?? CircleDot
+ const cfg = configMap.get(source.id)
+ const isEnabled = source.alwaysEnabled || cfg?.enabled
+ return (
+
+
+
+
+ {source.name}
+
+
+ {isEnabled && (
+
+
+
+ )}
+
+ )
+ })}
+
+
+
+
+
-
-
+
+
-
- {error && (
-
-
-
- {error}
-
-
-
- )}
+
+ {error && (
+
+
+
+ {error}
+
+
+
+ )}
-
-
-
-
- )
+
+
+
+
+ )
}
diff --git a/apps/admin-dashboard/src/routes/_dashboard/feed.tsx b/apps/admin-dashboard/src/routes/_dashboard/feed.tsx
index 4e6e900..4f3f629 100644
--- a/apps/admin-dashboard/src/routes/_dashboard/feed.tsx
+++ b/apps/admin-dashboard/src/routes/_dashboard/feed.tsx
@@ -1,10 +1,11 @@
import { createRoute } from "@tanstack/react-router"
import { FeedPanel } from "@/components/feed-panel"
+
import { Route as dashboardRoute } from "../_dashboard"
export const Route = createRoute({
- getParentRoute: () => dashboardRoute,
- path: "/feed",
- component: FeedPanel,
+ getParentRoute: () => dashboardRoute,
+ path: "/feed",
+ component: FeedPanel,
})
diff --git a/apps/admin-dashboard/src/routes/_dashboard/index.tsx b/apps/admin-dashboard/src/routes/_dashboard/index.tsx
index de13249..a0437b9 100644
--- a/apps/admin-dashboard/src/routes/_dashboard/index.tsx
+++ b/apps/admin-dashboard/src/routes/_dashboard/index.tsx
@@ -1,10 +1,11 @@
import { createRoute } from "@tanstack/react-router"
import { GeneralSettingsPanel } from "@/components/general-settings-panel"
+
import { Route as dashboardRoute } from "../_dashboard"
export const Route = createRoute({
- getParentRoute: () => dashboardRoute,
- path: "/",
- component: GeneralSettingsPanel,
+ getParentRoute: () => dashboardRoute,
+ path: "/",
+ component: GeneralSettingsPanel,
})
diff --git a/apps/admin-dashboard/src/routes/_dashboard/sources.$sourceId.tsx b/apps/admin-dashboard/src/routes/_dashboard/sources.$sourceId.tsx
index 4665830..d8154e2 100644
--- a/apps/admin-dashboard/src/routes/_dashboard/sources.$sourceId.tsx
+++ b/apps/admin-dashboard/src/routes/_dashboard/sources.$sourceId.tsx
@@ -1,34 +1,35 @@
-import { createRoute } from "@tanstack/react-router"
import { useQuery, useQueryClient } from "@tanstack/react-query"
+import { createRoute } from "@tanstack/react-router"
-import { fetchSources } from "@/lib/api"
import { SourceConfigPanel } from "@/components/source-config-panel"
+import { fetchSources } from "@/lib/api"
+
import { Route as dashboardRoute } from "../_dashboard"
export const Route = createRoute({
- getParentRoute: () => dashboardRoute,
- path: "/sources/$sourceId",
- component: SourceRoute,
+ getParentRoute: () => dashboardRoute,
+ path: "/sources/$sourceId",
+ component: SourceRoute,
})
function SourceRoute() {
- const { sourceId } = Route.useParams()
- const queryClient = useQueryClient()
- const { data: sources = [] } = useQuery({
- queryKey: ["sources"],
- queryFn: fetchSources,
- })
- const source = sources.find((s) => s.id === sourceId)
+ const { sourceId } = Route.useParams()
+ const queryClient = useQueryClient()
+ const { data: sources = [] } = useQuery({
+ queryKey: ["sources"],
+ queryFn: fetchSources,
+ })
+ const source = sources.find((s) => s.id === sourceId)
- if (!source) {
- return Source not found.
- }
+ if (!source) {
+ return Source not found.
+ }
- return (
- queryClient.invalidateQueries({ queryKey: ["configs"] })}
- />
- )
+ return (
+ queryClient.invalidateQueries({ queryKey: ["configs"] })}
+ />
+ )
}
diff --git a/apps/admin-dashboard/src/routes/login.tsx b/apps/admin-dashboard/src/routes/login.tsx
index a927b6f..16c919c 100644
--- a/apps/admin-dashboard/src/routes/login.tsx
+++ b/apps/admin-dashboard/src/routes/login.tsx
@@ -1,22 +1,24 @@
-import { createRoute, useNavigate } from "@tanstack/react-router"
import { useQueryClient } from "@tanstack/react-query"
+import { createRoute, useNavigate } from "@tanstack/react-router"
import type { AuthSession } from "@/lib/auth"
+
import { LoginPage } from "@/components/login-page"
+
import { Route as rootRoute } from "./__root"
export const Route = createRoute({
- getParentRoute: () => rootRoute,
- path: "/login",
- component: function LoginRoute() {
- const navigate = useNavigate()
- const queryClient = useQueryClient()
+ getParentRoute: () => rootRoute,
+ path: "/login",
+ component: function LoginRoute() {
+ const navigate = useNavigate()
+ const queryClient = useQueryClient()
- function handleLogin(session: AuthSession) {
- queryClient.setQueryData(["session"], session)
- navigate({ to: "/" })
- }
+ function handleLogin(session: AuthSession) {
+ queryClient.setQueryData(["session"], session)
+ navigate({ to: "/" })
+ }
- return
- },
+ return
+ },
})
diff --git a/apps/admin-dashboard/tsconfig.app.json b/apps/admin-dashboard/tsconfig.app.json
index a132313..25d77c1 100644
--- a/apps/admin-dashboard/tsconfig.app.json
+++ b/apps/admin-dashboard/tsconfig.app.json
@@ -1,32 +1,32 @@
{
- "compilerOptions": {
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
- "target": "ES2022",
- "useDefineForClassFields": true,
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "types": ["vite/client"],
- "skipLibCheck": true,
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "types": ["vite/client"],
+ "skipLibCheck": true,
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "moduleDetection": "force",
- "noEmit": true,
- "jsx": "react-jsx",
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "erasableSyntaxOnly": true,
- "noFallthroughCasesInSwitch": true,
- "noUncheckedSideEffectImports": true,
- "baseUrl": ".",
- "paths": {
- "@/*": ["./src/*"]
- }
- },
- "include": ["src"]
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src"]
}
diff --git a/apps/admin-dashboard/tsconfig.json b/apps/admin-dashboard/tsconfig.json
index fec8c8e..6c4e12b 100644
--- a/apps/admin-dashboard/tsconfig.json
+++ b/apps/admin-dashboard/tsconfig.json
@@ -1,13 +1,10 @@
{
- "files": [],
- "references": [
- { "path": "./tsconfig.app.json" },
- { "path": "./tsconfig.node.json" }
- ],
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "@/*": ["./src/*"]
- }
- }
+ "files": [],
+ "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }],
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ }
}
diff --git a/apps/admin-dashboard/tsconfig.node.json b/apps/admin-dashboard/tsconfig.node.json
index 8a67f62..e75109e 100644
--- a/apps/admin-dashboard/tsconfig.node.json
+++ b/apps/admin-dashboard/tsconfig.node.json
@@ -1,26 +1,26 @@
{
- "compilerOptions": {
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
- "target": "ES2023",
- "lib": ["ES2023"],
- "module": "ESNext",
- "types": ["node"],
- "skipLibCheck": true,
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "ES2023",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "types": ["node"],
+ "skipLibCheck": true,
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "moduleDetection": "force",
- "noEmit": true,
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "erasableSyntaxOnly": true,
- "noFallthroughCasesInSwitch": true,
- "noUncheckedSideEffectImports": true
- },
- "include": ["vite.config.ts"]
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
}
diff --git a/apps/admin-dashboard/vite.config.ts b/apps/admin-dashboard/vite.config.ts
index d617bc7..5c13684 100644
--- a/apps/admin-dashboard/vite.config.ts
+++ b/apps/admin-dashboard/vite.config.ts
@@ -1,18 +1,18 @@
-import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
+import path from "path"
import { defineConfig } from "vite"
// https://vite.dev/config/
export default defineConfig({
- plugins: [react(), tailwindcss()],
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "./src"),
- },
- },
- server: {
- port: 5174,
- allowedHosts: true,
- },
+ plugins: [react(), tailwindcss()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
+ server: {
+ port: 5174,
+ allowedHosts: true,
+ },
})
diff --git a/bun.lock b/bun.lock
index 44b6638..add849b 100644
--- a/bun.lock
+++ b/bun.lock
@@ -37,19 +37,11 @@
"tw-animate-css": "^1.4.0",
},
"devDependencies": {
- "@eslint/js": "^9.39.1",
"@types/node": "^24.10.1",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
- "eslint": "^9.39.1",
- "eslint-plugin-react-hooks": "^7.0.1",
- "eslint-plugin-react-refresh": "^0.4.24",
- "globals": "^16.5.0",
- "prettier": "^3.8.1",
- "prettier-plugin-tailwindcss": "^0.7.2",
"typescript": "~5.9.3",
- "typescript-eslint": "^8.46.4",
"vite": "^7.2.4",
},
},
@@ -1440,25 +1432,25 @@
"@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
- "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.1", "@typescript-eslint/type-utils": "8.57.1", "@typescript-eslint/utils": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ=="],
+ "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/type-utils": "8.57.0", "@typescript-eslint/utils": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ=="],
- "@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.1", "@typescript-eslint/types": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw=="],
+ "@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g=="],
- "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.1", "@typescript-eslint/types": "^8.57.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg=="],
+ "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="],
- "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.1", "", { "dependencies": { "@typescript-eslint/types": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1" } }, "sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg=="],
+ "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0" } }, "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw=="],
- "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg=="],
+ "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="],
- "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.1", "", { "dependencies": { "@typescript-eslint/types": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1", "@typescript-eslint/utils": "8.57.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA=="],
+ "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ=="],
- "@typescript-eslint/types": ["@typescript-eslint/types@8.57.1", "", {}, "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ=="],
+ "@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
- "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.1", "@typescript-eslint/tsconfig-utils": "8.57.1", "@typescript-eslint/types": "8.57.1", "@typescript-eslint/visitor-keys": "8.57.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g=="],
+ "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="],
- "@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.1", "@typescript-eslint/types": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ=="],
+ "@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ=="],
- "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.1", "", { "dependencies": { "@typescript-eslint/types": "8.57.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A=="],
+ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="],
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
@@ -1524,7 +1516,7 @@
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
- "ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
+ "ajv": ["ajv@8.11.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg=="],
"ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="],
@@ -1658,7 +1650,7 @@
"bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ=="],
- "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+ "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
@@ -1992,9 +1984,7 @@
"eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="],
- "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="],
-
- "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.26", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ=="],
+ "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
@@ -2268,9 +2258,9 @@
"headers-polyfill": ["headers-polyfill@4.0.3", "", {}, "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ=="],
- "hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="],
+ "hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
- "hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
+ "hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
"hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="],
@@ -2432,7 +2422,7 @@
"isbot": ["isbot@5.1.35", "", {}, "sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg=="],
- "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
+ "isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
"istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="],
@@ -2490,7 +2480,7 @@
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
- "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
+ "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
@@ -2736,7 +2726,7 @@
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
- "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+ "minimatch": ["minimatch@5.1.2", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
@@ -2986,8 +2976,6 @@
"prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
- "prettier-plugin-tailwindcss": ["prettier-plugin-tailwindcss@0.7.2", "", { "peerDependencies": { "@ianvs/prettier-plugin-sort-imports": "*", "@prettier/plugin-hermes": "*", "@prettier/plugin-oxc": "*", "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", "@trivago/prettier-plugin-sort-imports": "*", "@zackad/prettier-plugin-twig": "*", "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", "prettier-plugin-jsdoc": "*", "prettier-plugin-marko": "*", "prettier-plugin-multiline-arrays": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", "prettier-plugin-sort-imports": "*", "prettier-plugin-svelte": "*" }, "optionalPeers": ["@ianvs/prettier-plugin-sort-imports", "@prettier/plugin-hermes", "@prettier/plugin-oxc", "@prettier/plugin-pug", "@shopify/prettier-plugin-liquid", "@trivago/prettier-plugin-sort-imports", "@zackad/prettier-plugin-twig", "prettier-plugin-astro", "prettier-plugin-css-order", "prettier-plugin-jsdoc", "prettier-plugin-marko", "prettier-plugin-multiline-arrays", "prettier-plugin-organize-attributes", "prettier-plugin-organize-imports", "prettier-plugin-sort-imports", "prettier-plugin-svelte"] }, "sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA=="],
-
"pretty-bytes": ["pretty-bytes@5.6.0", "", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="],
"pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="],
@@ -3336,7 +3324,7 @@
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
- "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+ "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"supports-hyperlinks": ["supports-hyperlinks@2.3.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA=="],
@@ -3442,8 +3430,6 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
- "typescript-eslint": ["typescript-eslint@8.57.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.57.1", "@typescript-eslint/parser": "8.57.1", "@typescript-eslint/typescript-estree": "8.57.1", "@typescript-eslint/utils": "8.57.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA=="],
-
"ua-parser-js": ["ua-parser-js@1.0.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug=="],
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
@@ -3548,7 +3534,7 @@
"whatwg-url-without-unicode": ["whatwg-url-without-unicode@8.0.0-3", "", { "dependencies": { "buffer": "^5.4.3", "punycode": "^2.1.1", "webidl-conversions": "^5.0.0" } }, "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig=="],
- "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
+ "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
"which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],
@@ -3612,8 +3598,6 @@
"zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
- "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
-
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
@@ -3648,16 +3632,20 @@
"@dotenvx/dotenvx/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
- "@dotenvx/dotenvx/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
-
"@ecies/ciphers/@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
+ "@eslint/config-array/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
+ "@eslint/eslintrc/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
+
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
+ "@eslint/eslintrc/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
"@expo/bunyan/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
"@expo/cli/@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.6", "", { "dependencies": { "node-forge": "^1.3.3" } }, "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w=="],
@@ -3768,8 +3756,6 @@
"@expo/metro-config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
- "@expo/metro-config/hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
-
"@expo/metro-config/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
"@expo/metro-config/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="],
@@ -3854,8 +3840,6 @@
"@oclif/core/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
- "@oclif/core/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
-
"@prisma/dev/hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="],
"@prisma/dev/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
@@ -3868,8 +3852,6 @@
"@react-native/babel-preset/react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
- "@react-native/codegen/hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
-
"@react-native/community-cli-plugin/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="],
@@ -3884,8 +3866,6 @@
"@react-router/dev/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
- "@segment/ajv-human-errors/ajv": ["ajv@8.11.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg=="],
-
"@swc/helpers/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
@@ -3932,8 +3912,6 @@
"aelis-client/react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
- "ajv-formats/ajv": ["ajv@8.11.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg=="],
-
"ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
@@ -3942,8 +3920,6 @@
"babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
- "babel-plugin-syntax-hermes-parser/hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="],
-
"basic-auth/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
"better-call/set-cookie-parser": ["set-cookie-parser@3.0.1", "", {}, "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q=="],
@@ -3964,6 +3940,8 @@
"c12/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
+ "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+
"chevrotain/lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"chrome-launcher/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
@@ -3990,9 +3968,9 @@
"cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
- "dotenv-expand/dotenv": ["dotenv@16.4.7", "", {}, "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="],
+ "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
- "eas-cli/ajv": ["ajv@8.11.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg=="],
+ "dotenv-expand/dotenv": ["dotenv@16.4.7", "", {}, "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="],
"eas-cli/diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="],
@@ -4002,8 +3980,6 @@
"eas-cli/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
- "eas-cli/minimatch": ["minimatch@5.1.2", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg=="],
-
"eas-cli/node-fetch": ["node-fetch@2.6.7", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="],
"eas-cli/ora": ["ora@5.1.0", "", { "dependencies": { "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.4.0", "is-interactive": "^1.0.0", "log-symbols": "^4.0.0", "mute-stream": "0.0.8", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w=="],
@@ -4012,11 +3988,9 @@
"eciesjs/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
- "eslint-config-expo/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/type-utils": "8.57.0", "@typescript-eslint/utils": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ=="],
+ "eslint/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
- "eslint-config-expo/@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g=="],
-
- "eslint-config-expo/eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="],
+ "eslint/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
@@ -4024,16 +3998,16 @@
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
- "eslint-plugin-expo/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ=="],
-
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
+ "eslint-plugin-import/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
"eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"eslint-plugin-import/tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
+ "eslint-plugin-react/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"execa/figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="],
@@ -4050,8 +4024,6 @@
"expo-constants/@expo/env": ["@expo/env@2.0.11", "", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" } }, "sha512-xV+ps6YCW7XIPVUwFVCRN2nox09dnRwy8uIjwHWTODu0zFw4kp4omnVkl0OOjuu2XOe7tdgAHxikrkJt9xB/7Q=="],
- "expo-dev-launcher/ajv": ["ajv@8.11.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg=="],
-
"expo-manifests/@expo/config": ["@expo/config@12.0.13", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~54.0.4", "@expo/config-types": "^54.0.10", "@expo/json-file": "^10.0.8", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "~3.35.1" } }, "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ=="],
"expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
@@ -4078,14 +4050,14 @@
"figures/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
- "filelist/minimatch": ["minimatch@5.1.2", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg=="],
-
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"framer-motion/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"giget/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
+ "glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
"globby/fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
"globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
@@ -4120,8 +4092,6 @@
"jest-worker/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="],
- "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
-
"lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"log-symbols/is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="],
@@ -4274,12 +4244,16 @@
"sucrase/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
+ "supports-hyperlinks/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
+
"svix/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="],
"tar/minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
+ "test-exclude/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
"ts-node/arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="],
"ts-node/diff": ["diff@4.0.4", "", {}, "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ=="],
@@ -4334,8 +4308,6 @@
"@dotenvx/dotenvx/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
- "@dotenvx/dotenvx/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
-
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
@@ -4380,6 +4352,12 @@
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
+ "@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
+ "@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
+
+ "@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
"@expo/cli/@expo/config/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
"@expo/cli/@expo/config/@expo/config-types": ["@expo/config-types@54.0.10", "", {}, "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA=="],
@@ -4402,8 +4380,6 @@
"@expo/cli/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
- "@expo/cli/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"@expo/cli/ora/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
"@expo/cli/ora/cli-cursor": ["cli-cursor@2.1.0", "", { "dependencies": { "restore-cursor": "^2.0.0" } }, "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw=="],
@@ -4424,8 +4400,6 @@
"@expo/fingerprint/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
- "@expo/fingerprint/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"@expo/image-utils/fs-extra/universalify": ["universalify@1.0.0", "", {}, "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="],
"@expo/metro-config/@babel/code-frame/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
@@ -4444,10 +4418,6 @@
"@expo/metro-config/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
- "@expo/metro-config/hermes-parser/hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
-
- "@expo/metro-config/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"@expo/metro-config/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"@expo/metro/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="],
@@ -4470,16 +4440,12 @@
"@expo/plugin-help/@oclif/core/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
- "@expo/plugin-help/@oclif/core/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
-
"@expo/plugin-warn-if-update-available/@oclif/core/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="],
"@expo/plugin-warn-if-update-available/@oclif/core/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"@expo/plugin-warn-if-update-available/@oclif/core/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
- "@expo/plugin-warn-if-update-available/@oclif/core/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
-
"@expo/prebuild-config/@expo/json-file/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
"@expo/xcpretty/@babel/code-frame/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
@@ -4504,8 +4470,6 @@
"@jest/types/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
- "@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
-
"@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
@@ -4536,12 +4500,8 @@
"@oclif/core/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
- "@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
-
"@react-native/dev-middleware/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
- "@segment/ajv-human-errors/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
-
"@tailwindcss/node/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
"@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
@@ -4588,10 +4548,6 @@
"aelis-client/react-dom/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
- "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
-
- "babel-plugin-syntax-hermes-parser/hermes-parser/hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="],
-
"better-opn/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
"better-opn/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
@@ -4620,44 +4576,28 @@
"connect/finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="],
- "eas-cli/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
+ "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"eas-cli/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"eas-cli/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
- "eas-cli/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"eas-cli/ora/cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
"eas-cli/ora/is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="],
"eas-cli/ora/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0" } }, "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0", "@typescript-eslint/utils": "8.57.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/typescript-estree": "8.57.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0" } }, "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0" } }, "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="],
+ "eslint-plugin-import/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"eslint-plugin-import/tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
+ "eslint-plugin-react/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
+ "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
+
+ "eslint/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
"expo-asset/@expo/image-utils/getenv": ["getenv@2.0.0", "", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="],
"expo-asset/@expo/image-utils/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
@@ -4682,8 +4622,6 @@
"expo-constants/@expo/env/getenv": ["getenv@2.0.0", "", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="],
- "expo-dev-launcher/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
-
"expo-manifests/@expo/config/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
"expo-manifests/@expo/config/@expo/config-plugins": ["@expo/config-plugins@54.0.4", "", { "dependencies": { "@expo/config-types": "^54.0.10", "@expo/json-file": "~10.0.8", "@expo/plist": "^0.4.8", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q=="],
@@ -4742,10 +4680,10 @@
"fbjs/cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
- "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
+ "glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
"globby/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"jest-environment-node/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
@@ -4790,6 +4728,8 @@
"sucrase/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
+ "test-exclude/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
"twrnc/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"twrnc/tailwindcss/fast-glob": ["fast-glob@3.3.2", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="],
@@ -4890,10 +4830,6 @@
"@expo/cli/ora/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="],
- "@expo/config-plugins/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "@expo/config/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"@expo/eas-json/@babel/code-frame/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"@expo/eas-json/@babel/code-frame/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
@@ -4962,42 +4898,6 @@
"eas-cli/ora/cli-cursor/restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="],
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.0", "@typescript-eslint/tsconfig-utils": "8.57.0", "@typescript-eslint/types": "8.57.0", "@typescript-eslint/visitor-keys": "8.57.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.0", "", { "dependencies": { "@typescript-eslint/types": "8.57.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
-
"expo-constants/@expo/config/@expo/config-plugins/@expo/plist": ["@expo/plist@0.4.8", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.2.3", "xmlbuilder": "^15.1.1" } }, "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ=="],
"expo-constants/@expo/config/@expo/json-file/@babel/code-frame": ["@babel/code-frame@7.23.5", "", { "dependencies": { "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" } }, "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA=="],
@@ -5054,12 +4954,10 @@
"expo/@expo/config/sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
+ "mv/rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
- "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "sucrase/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
"twrnc/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"twrnc/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
@@ -5126,30 +5024,6 @@
"eas-cli/ora/cli-cursor/restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.0", "@typescript-eslint/types": "^8.57.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
-
"expo-constants/@expo/config/@expo/config-plugins/@expo/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="],
"expo-constants/@expo/config/@expo/config-plugins/@expo/plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="],
@@ -5198,6 +5072,8 @@
"expo/@expo/config/glob/path-scurry/lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
+ "mv/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="],
"twrnc/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
@@ -5224,14 +5100,6 @@
"@expo/xcpretty/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
-
- "eslint-config-expo/@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
-
- "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
-
"expo-constants/@expo/config/@expo/json-file/@babel/code-frame/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
"expo-constants/@expo/config/@expo/json-file/@babel/code-frame/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
@@ -5282,10 +5150,6 @@
"@expo/package-manager/@expo/json-file/@babel/code-frame/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
-
- "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
-
"expo-constants/@expo/config/@expo/json-file/@babel/code-frame/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"expo-constants/@expo/config/@expo/json-file/@babel/code-frame/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],