diff --git a/.gitignore b/.gitignore
index aade9cb..96fab4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,140 +1,38 @@
-# Logs
-logs
-*.log
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# Dependencies
+node_modules
+.pnp
+.pnp.js
+
+# Local env files
+.env
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# Testing
+coverage
+
+# Turbo
+.turbo
+
+# Vercel
+.vercel
+
+# Build Outputs
+.next/
+out/
+build
+dist
+
+
+# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-lerna-debug.log*
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-web_modules/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variable files
-.env
-.env.*
-!.env.example
-
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-.parcel-cache
-
-# Next.js build output
-.next
-out
-
-# Nuxt.js build / generate output
-.nuxt
-dist
-
-# Gatsby files
-.cache/
-# Comment in the public line in if your project uses Gatsby and not Next.js
-# https://nextjs.org/blog/next-9-1#public-directory-support
-# public
-
-# vuepress build output
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-.temp
-.cache
-
-# Sveltekit cache directory
-.svelte-kit/
-
-# vitepress build output
-**/.vitepress/dist
-
-# vitepress cache directory
-**/.vitepress/cache
-
-# Docusaurus cache and generated files
-.docusaurus
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# Firebase cache directory
-.firebase/
-
-# TernJS port file
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-.vscode-test
-
-# yarn v3
-.pnp.*
-.yarn/*
-!.yarn/patches
-!.yarn/plugins
-!.yarn/releases
-!.yarn/sdks
-!.yarn/versions
-
-# Vite logs files
-vite.config.js.timestamp-*
-vite.config.ts.timestamp-*
-**/.helix
+# Misc
+.DS_Store
+*.pem
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..e69de29
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..240569f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,135 @@
+# Turborepo starter
+
+This Turborepo starter is maintained by the Turborepo core team.
+
+## Using this example
+
+Run the following command:
+
+```sh
+npx create-turbo@latest
+```
+
+## What's inside?
+
+This Turborepo includes the following packages/apps:
+
+### Apps and Packages
+
+- `docs`: a [Next.js](https://nextjs.org/) app
+- `web`: another [Next.js](https://nextjs.org/) app
+- `@repo/ui`: a stub React component library shared by both `web` and `docs` applications
+- `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`)
+- `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo
+
+Each package/app is 100% [TypeScript](https://www.typescriptlang.org/).
+
+### Utilities
+
+This Turborepo has some additional tools already setup for you:
+
+- [TypeScript](https://www.typescriptlang.org/) for static type checking
+- [ESLint](https://eslint.org/) for code linting
+- [Prettier](https://prettier.io) for code formatting
+
+### Build
+
+To build all apps and packages, run the following command:
+
+```
+cd my-turborepo
+
+# With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended)
+turbo build
+
+# Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager
+npx turbo build
+yarn dlx turbo build
+pnpm exec turbo build
+```
+
+You can build a specific package by using a [filter](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters):
+
+```
+# With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended)
+turbo build --filter=docs
+
+# Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager
+npx turbo build --filter=docs
+yarn exec turbo build --filter=docs
+pnpm exec turbo build --filter=docs
+```
+
+### Develop
+
+To develop all apps and packages, run the following command:
+
+```
+cd my-turborepo
+
+# With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended)
+turbo dev
+
+# Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager
+npx turbo dev
+yarn exec turbo dev
+pnpm exec turbo dev
+```
+
+You can develop a specific package by using a [filter](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters):
+
+```
+# With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended)
+turbo dev --filter=web
+
+# Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager
+npx turbo dev --filter=web
+yarn exec turbo dev --filter=web
+pnpm exec turbo dev --filter=web
+```
+
+### Remote Caching
+
+> [!TIP]
+> Vercel Remote Cache is free for all plans. Get started today at [vercel.com](https://vercel.com/signup?/signup?utm_source=remote-cache-sdk&utm_campaign=free_remote_cache).
+
+Turborepo can use a technique known as [Remote Caching](https://turborepo.com/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines.
+
+By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup?utm_source=turborepo-examples), then enter the following commands:
+
+```
+cd my-turborepo
+
+# With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended)
+turbo login
+
+# Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager
+npx turbo login
+yarn exec turbo login
+pnpm exec turbo login
+```
+
+This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview).
+
+Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo:
+
+```
+# With [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation) installed (recommended)
+turbo link
+
+# Without [global `turbo`](https://turborepo.com/docs/getting-started/installation#global-installation), use your package manager
+npx turbo link
+yarn exec turbo link
+pnpm exec turbo link
+```
+
+## Useful Links
+
+Learn more about the power of Turborepo:
+
+- [Tasks](https://turborepo.com/docs/crafting-your-repository/running-tasks)
+- [Caching](https://turborepo.com/docs/crafting-your-repository/caching)
+- [Remote Caching](https://turborepo.com/docs/core-concepts/remote-caching)
+- [Filtering](https://turborepo.com/docs/crafting-your-repository/running-tasks#using-filters)
+- [Configuration Options](https://turborepo.com/docs/reference/configuration)
+- [CLI Usage](https://turborepo.com/docs/reference/command-line-reference)
diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore
new file mode 100644
index 0000000..f886745
--- /dev/null
+++ b/apps/docs/.gitignore
@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# env files (can opt-in for commiting if needed)
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/apps/docs/README.md b/apps/docs/README.md
new file mode 100644
index 0000000..a98bfa8
--- /dev/null
+++ b/apps/docs/README.md
@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load Inter, a custom Google Font.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/apps/docs/app/favicon.ico b/apps/docs/app/favicon.ico
new file mode 100644
index 0000000..718d6fe
Binary files /dev/null and b/apps/docs/app/favicon.ico differ
diff --git a/apps/docs/app/fonts/GeistMonoVF.woff b/apps/docs/app/fonts/GeistMonoVF.woff
new file mode 100644
index 0000000..f2ae185
Binary files /dev/null and b/apps/docs/app/fonts/GeistMonoVF.woff differ
diff --git a/apps/docs/app/fonts/GeistVF.woff b/apps/docs/app/fonts/GeistVF.woff
new file mode 100644
index 0000000..1b62daa
Binary files /dev/null and b/apps/docs/app/fonts/GeistVF.woff differ
diff --git a/apps/docs/app/globals.css b/apps/docs/app/globals.css
new file mode 100644
index 0000000..6af7ecb
--- /dev/null
+++ b/apps/docs/app/globals.css
@@ -0,0 +1,50 @@
+:root {
+ --background: #ffffff;
+ --foreground: #171717;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --background: #0a0a0a;
+ --foreground: #ededed;
+ }
+}
+
+html,
+body {
+ max-width: 100vw;
+ overflow-x: hidden;
+}
+
+body {
+ color: var(--foreground);
+ background: var(--background);
+}
+
+* {
+ box-sizing: border-box;
+ padding: 0;
+ margin: 0;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+.imgDark {
+ display: none;
+}
+
+@media (prefers-color-scheme: dark) {
+ html {
+ color-scheme: dark;
+ }
+
+ .imgLight {
+ display: none;
+ }
+ .imgDark {
+ display: unset;
+ }
+}
diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx
new file mode 100644
index 0000000..8469537
--- /dev/null
+++ b/apps/docs/app/layout.tsx
@@ -0,0 +1,31 @@
+import type { Metadata } from "next";
+import localFont from "next/font/local";
+import "./globals.css";
+
+const geistSans = localFont({
+ src: "./fonts/GeistVF.woff",
+ variable: "--font-geist-sans",
+});
+const geistMono = localFont({
+ src: "./fonts/GeistMonoVF.woff",
+ variable: "--font-geist-mono",
+});
+
+export const metadata: Metadata = {
+ title: "Create Next App",
+ description: "Generated by create next app",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/apps/docs/app/page.module.css b/apps/docs/app/page.module.css
new file mode 100644
index 0000000..3630662
--- /dev/null
+++ b/apps/docs/app/page.module.css
@@ -0,0 +1,188 @@
+.page {
+ --gray-rgb: 0, 0, 0;
+ --gray-alpha-200: rgba(var(--gray-rgb), 0.08);
+ --gray-alpha-100: rgba(var(--gray-rgb), 0.05);
+
+ --button-primary-hover: #383838;
+ --button-secondary-hover: #f2f2f2;
+
+ display: grid;
+ grid-template-rows: 20px 1fr 20px;
+ align-items: center;
+ justify-items: center;
+ min-height: 100svh;
+ padding: 80px;
+ gap: 64px;
+ font-synthesis: none;
+}
+
+@media (prefers-color-scheme: dark) {
+ .page {
+ --gray-rgb: 255, 255, 255;
+ --gray-alpha-200: rgba(var(--gray-rgb), 0.145);
+ --gray-alpha-100: rgba(var(--gray-rgb), 0.06);
+
+ --button-primary-hover: #ccc;
+ --button-secondary-hover: #1a1a1a;
+ }
+}
+
+.main {
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+ grid-row-start: 2;
+}
+
+.main ol {
+ font-family: var(--font-geist-mono);
+ padding-left: 0;
+ margin: 0;
+ font-size: 14px;
+ line-height: 24px;
+ letter-spacing: -0.01em;
+ list-style-position: inside;
+}
+
+.main li:not(:last-of-type) {
+ margin-bottom: 8px;
+}
+
+.main code {
+ font-family: inherit;
+ background: var(--gray-alpha-100);
+ padding: 2px 4px;
+ border-radius: 4px;
+ font-weight: 600;
+}
+
+.ctas {
+ display: flex;
+ gap: 16px;
+}
+
+.ctas a {
+ appearance: none;
+ border-radius: 128px;
+ height: 48px;
+ padding: 0 20px;
+ border: none;
+ font-family: var(--font-geist-sans);
+ border: 1px solid transparent;
+ transition: background 0.2s, color 0.2s, border-color 0.2s;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ line-height: 20px;
+ font-weight: 500;
+}
+
+a.primary {
+ background: var(--foreground);
+ color: var(--background);
+ gap: 8px;
+}
+
+a.secondary {
+ border-color: var(--gray-alpha-200);
+ min-width: 180px;
+}
+
+button.secondary {
+ appearance: none;
+ border-radius: 128px;
+ height: 48px;
+ padding: 0 20px;
+ border: none;
+ font-family: var(--font-geist-sans);
+ border: 1px solid transparent;
+ transition: background 0.2s, color 0.2s, border-color 0.2s;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ line-height: 20px;
+ font-weight: 500;
+ background: transparent;
+ border-color: var(--gray-alpha-200);
+ min-width: 180px;
+}
+
+.footer {
+ font-family: var(--font-geist-sans);
+ grid-row-start: 3;
+ display: flex;
+ gap: 24px;
+}
+
+.footer a {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.footer img {
+ flex-shrink: 0;
+}
+
+/* Enable hover only on non-touch devices */
+@media (hover: hover) and (pointer: fine) {
+ a.primary:hover {
+ background: var(--button-primary-hover);
+ border-color: transparent;
+ }
+
+ a.secondary:hover {
+ background: var(--button-secondary-hover);
+ border-color: transparent;
+ }
+
+ .footer a:hover {
+ text-decoration: underline;
+ text-underline-offset: 4px;
+ }
+}
+
+@media (max-width: 600px) {
+ .page {
+ padding: 32px;
+ padding-bottom: 80px;
+ }
+
+ .main {
+ align-items: center;
+ }
+
+ .main ol {
+ text-align: center;
+ }
+
+ .ctas {
+ flex-direction: column;
+ }
+
+ .ctas a {
+ font-size: 14px;
+ height: 40px;
+ padding: 0 16px;
+ }
+
+ a.secondary {
+ min-width: auto;
+ }
+
+ .footer {
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ .logo {
+ filter: invert();
+ }
+}
diff --git a/apps/docs/app/page.tsx b/apps/docs/app/page.tsx
new file mode 100644
index 0000000..e726335
--- /dev/null
+++ b/apps/docs/app/page.tsx
@@ -0,0 +1,102 @@
+import Image, { type ImageProps } from "next/image";
+import { Button } from "@repo/ui/button";
+import styles from "./page.module.css";
+
+type Props = Omit & {
+ srcLight: string;
+ srcDark: string;
+};
+
+const ThemeImage = (props: Props) => {
+ const { srcLight, srcDark, ...rest } = props;
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default function Home() {
+ return (
+
+
+
+
+ -
+ Get started by editing
apps/docs/app/page.tsx
+
+ - Save and see your changes instantly.
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/eslint.config.js b/apps/docs/eslint.config.js
new file mode 100644
index 0000000..47b0670
--- /dev/null
+++ b/apps/docs/eslint.config.js
@@ -0,0 +1,4 @@
+import { nextJsConfig } from "@repo/eslint-config/next-js";
+
+/** @type {import("eslint").Linter.Config[]} */
+export default nextJsConfig;
diff --git a/apps/docs/next.config.js b/apps/docs/next.config.js
new file mode 100644
index 0000000..4678774
--- /dev/null
+++ b/apps/docs/next.config.js
@@ -0,0 +1,4 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {};
+
+export default nextConfig;
diff --git a/apps/docs/package.json b/apps/docs/package.json
new file mode 100644
index 0000000..a9c661c
--- /dev/null
+++ b/apps/docs/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "docs",
+ "version": "0.1.0",
+ "type": "module",
+ "private": true,
+ "scripts": {
+ "dev": "next dev --turbopack --port 3001",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint --max-warnings 0",
+ "check-types": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@repo/ui": "workspace:*",
+ "next": "^15.5.0",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0"
+ },
+ "devDependencies": {
+ "@repo/eslint-config": "workspace:*",
+ "@repo/typescript-config": "workspace:*",
+ "@types/node": "^22.15.3",
+ "@types/react": "19.1.0",
+ "@types/react-dom": "19.1.1",
+ "eslint": "^9.34.0",
+ "typescript": "5.9.2"
+ }
+}
diff --git a/apps/docs/public/file-text.svg b/apps/docs/public/file-text.svg
new file mode 100644
index 0000000..9cfb3c9
--- /dev/null
+++ b/apps/docs/public/file-text.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/docs/public/globe.svg b/apps/docs/public/globe.svg
new file mode 100644
index 0000000..4230a3d
--- /dev/null
+++ b/apps/docs/public/globe.svg
@@ -0,0 +1,10 @@
+
diff --git a/apps/docs/public/next.svg b/apps/docs/public/next.svg
new file mode 100644
index 0000000..5174b28
--- /dev/null
+++ b/apps/docs/public/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/docs/public/turborepo-dark.svg b/apps/docs/public/turborepo-dark.svg
new file mode 100644
index 0000000..dae38fe
--- /dev/null
+++ b/apps/docs/public/turborepo-dark.svg
@@ -0,0 +1,19 @@
+
diff --git a/apps/docs/public/turborepo-light.svg b/apps/docs/public/turborepo-light.svg
new file mode 100644
index 0000000..ddea915
--- /dev/null
+++ b/apps/docs/public/turborepo-light.svg
@@ -0,0 +1,19 @@
+
diff --git a/apps/docs/public/vercel.svg b/apps/docs/public/vercel.svg
new file mode 100644
index 0000000..0164ddc
--- /dev/null
+++ b/apps/docs/public/vercel.svg
@@ -0,0 +1,10 @@
+
diff --git a/apps/docs/public/window.svg b/apps/docs/public/window.svg
new file mode 100644
index 0000000..bbc7800
--- /dev/null
+++ b/apps/docs/public/window.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json
new file mode 100644
index 0000000..7aef056
--- /dev/null
+++ b/apps/docs/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "@repo/typescript-config/nextjs.json",
+ "compilerOptions": {
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
+ },
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ "next-env.d.ts",
+ "next.config.js",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/apps/web/.gitignore b/apps/web/.gitignore
new file mode 100644
index 0000000..f886745
--- /dev/null
+++ b/apps/web/.gitignore
@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# env files (can opt-in for commiting if needed)
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/apps/web/README.md b/apps/web/README.md
new file mode 100644
index 0000000..a98bfa8
--- /dev/null
+++ b/apps/web/README.md
@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load Inter, a custom Google Font.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/apps/web/app/favicon.ico b/apps/web/app/favicon.ico
new file mode 100644
index 0000000..718d6fe
Binary files /dev/null and b/apps/web/app/favicon.ico differ
diff --git a/apps/web/app/fonts/GeistMonoVF.woff b/apps/web/app/fonts/GeistMonoVF.woff
new file mode 100644
index 0000000..f2ae185
Binary files /dev/null and b/apps/web/app/fonts/GeistMonoVF.woff differ
diff --git a/apps/web/app/fonts/GeistVF.woff b/apps/web/app/fonts/GeistVF.woff
new file mode 100644
index 0000000..1b62daa
Binary files /dev/null and b/apps/web/app/fonts/GeistVF.woff differ
diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css
new file mode 100644
index 0000000..6af7ecb
--- /dev/null
+++ b/apps/web/app/globals.css
@@ -0,0 +1,50 @@
+:root {
+ --background: #ffffff;
+ --foreground: #171717;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --background: #0a0a0a;
+ --foreground: #ededed;
+ }
+}
+
+html,
+body {
+ max-width: 100vw;
+ overflow-x: hidden;
+}
+
+body {
+ color: var(--foreground);
+ background: var(--background);
+}
+
+* {
+ box-sizing: border-box;
+ padding: 0;
+ margin: 0;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+.imgDark {
+ display: none;
+}
+
+@media (prefers-color-scheme: dark) {
+ html {
+ color-scheme: dark;
+ }
+
+ .imgLight {
+ display: none;
+ }
+ .imgDark {
+ display: unset;
+ }
+}
diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx
new file mode 100644
index 0000000..8469537
--- /dev/null
+++ b/apps/web/app/layout.tsx
@@ -0,0 +1,31 @@
+import type { Metadata } from "next";
+import localFont from "next/font/local";
+import "./globals.css";
+
+const geistSans = localFont({
+ src: "./fonts/GeistVF.woff",
+ variable: "--font-geist-sans",
+});
+const geistMono = localFont({
+ src: "./fonts/GeistMonoVF.woff",
+ variable: "--font-geist-mono",
+});
+
+export const metadata: Metadata = {
+ title: "Create Next App",
+ description: "Generated by create next app",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/apps/web/app/page.module.css b/apps/web/app/page.module.css
new file mode 100644
index 0000000..3630662
--- /dev/null
+++ b/apps/web/app/page.module.css
@@ -0,0 +1,188 @@
+.page {
+ --gray-rgb: 0, 0, 0;
+ --gray-alpha-200: rgba(var(--gray-rgb), 0.08);
+ --gray-alpha-100: rgba(var(--gray-rgb), 0.05);
+
+ --button-primary-hover: #383838;
+ --button-secondary-hover: #f2f2f2;
+
+ display: grid;
+ grid-template-rows: 20px 1fr 20px;
+ align-items: center;
+ justify-items: center;
+ min-height: 100svh;
+ padding: 80px;
+ gap: 64px;
+ font-synthesis: none;
+}
+
+@media (prefers-color-scheme: dark) {
+ .page {
+ --gray-rgb: 255, 255, 255;
+ --gray-alpha-200: rgba(var(--gray-rgb), 0.145);
+ --gray-alpha-100: rgba(var(--gray-rgb), 0.06);
+
+ --button-primary-hover: #ccc;
+ --button-secondary-hover: #1a1a1a;
+ }
+}
+
+.main {
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+ grid-row-start: 2;
+}
+
+.main ol {
+ font-family: var(--font-geist-mono);
+ padding-left: 0;
+ margin: 0;
+ font-size: 14px;
+ line-height: 24px;
+ letter-spacing: -0.01em;
+ list-style-position: inside;
+}
+
+.main li:not(:last-of-type) {
+ margin-bottom: 8px;
+}
+
+.main code {
+ font-family: inherit;
+ background: var(--gray-alpha-100);
+ padding: 2px 4px;
+ border-radius: 4px;
+ font-weight: 600;
+}
+
+.ctas {
+ display: flex;
+ gap: 16px;
+}
+
+.ctas a {
+ appearance: none;
+ border-radius: 128px;
+ height: 48px;
+ padding: 0 20px;
+ border: none;
+ font-family: var(--font-geist-sans);
+ border: 1px solid transparent;
+ transition: background 0.2s, color 0.2s, border-color 0.2s;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ line-height: 20px;
+ font-weight: 500;
+}
+
+a.primary {
+ background: var(--foreground);
+ color: var(--background);
+ gap: 8px;
+}
+
+a.secondary {
+ border-color: var(--gray-alpha-200);
+ min-width: 180px;
+}
+
+button.secondary {
+ appearance: none;
+ border-radius: 128px;
+ height: 48px;
+ padding: 0 20px;
+ border: none;
+ font-family: var(--font-geist-sans);
+ border: 1px solid transparent;
+ transition: background 0.2s, color 0.2s, border-color 0.2s;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ line-height: 20px;
+ font-weight: 500;
+ background: transparent;
+ border-color: var(--gray-alpha-200);
+ min-width: 180px;
+}
+
+.footer {
+ font-family: var(--font-geist-sans);
+ grid-row-start: 3;
+ display: flex;
+ gap: 24px;
+}
+
+.footer a {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.footer img {
+ flex-shrink: 0;
+}
+
+/* Enable hover only on non-touch devices */
+@media (hover: hover) and (pointer: fine) {
+ a.primary:hover {
+ background: var(--button-primary-hover);
+ border-color: transparent;
+ }
+
+ a.secondary:hover {
+ background: var(--button-secondary-hover);
+ border-color: transparent;
+ }
+
+ .footer a:hover {
+ text-decoration: underline;
+ text-underline-offset: 4px;
+ }
+}
+
+@media (max-width: 600px) {
+ .page {
+ padding: 32px;
+ padding-bottom: 80px;
+ }
+
+ .main {
+ align-items: center;
+ }
+
+ .main ol {
+ text-align: center;
+ }
+
+ .ctas {
+ flex-direction: column;
+ }
+
+ .ctas a {
+ font-size: 14px;
+ height: 40px;
+ padding: 0 16px;
+ }
+
+ a.secondary {
+ min-width: auto;
+ }
+
+ .footer {
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ .logo {
+ filter: invert();
+ }
+}
diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx
new file mode 100644
index 0000000..1fee7e2
--- /dev/null
+++ b/apps/web/app/page.tsx
@@ -0,0 +1,102 @@
+import Image, { type ImageProps } from "next/image";
+import { Button } from "@repo/ui/button";
+import styles from "./page.module.css";
+
+type Props = Omit & {
+ srcLight: string;
+ srcDark: string;
+};
+
+const ThemeImage = (props: Props) => {
+ const { srcLight, srcDark, ...rest } = props;
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default function Home() {
+ return (
+
+
+
+
+ -
+ Get started by editing
apps/web/app/page.tsx
+
+ - Save and see your changes instantly.
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/web/eslint.config.js b/apps/web/eslint.config.js
new file mode 100644
index 0000000..47b0670
--- /dev/null
+++ b/apps/web/eslint.config.js
@@ -0,0 +1,4 @@
+import { nextJsConfig } from "@repo/eslint-config/next-js";
+
+/** @type {import("eslint").Linter.Config[]} */
+export default nextJsConfig;
diff --git a/apps/web/next.config.js b/apps/web/next.config.js
new file mode 100644
index 0000000..4678774
--- /dev/null
+++ b/apps/web/next.config.js
@@ -0,0 +1,4 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {};
+
+export default nextConfig;
diff --git a/apps/web/package.json b/apps/web/package.json
new file mode 100644
index 0000000..f4305ad
--- /dev/null
+++ b/apps/web/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "web",
+ "version": "0.1.0",
+ "type": "module",
+ "private": true,
+ "scripts": {
+ "dev": "next dev --turbopack --port 3000",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint --max-warnings 0",
+ "check-types": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@repo/ui": "workspace:*",
+ "next": "^15.5.0",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0"
+ },
+ "devDependencies": {
+ "@repo/eslint-config": "workspace:*",
+ "@repo/typescript-config": "workspace:*",
+ "@types/node": "^22.15.3",
+ "@types/react": "19.1.0",
+ "@types/react-dom": "19.1.1",
+ "eslint": "^9.34.0",
+ "typescript": "5.9.2"
+ }
+}
diff --git a/apps/web/public/file-text.svg b/apps/web/public/file-text.svg
new file mode 100644
index 0000000..9cfb3c9
--- /dev/null
+++ b/apps/web/public/file-text.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/web/public/globe.svg b/apps/web/public/globe.svg
new file mode 100644
index 0000000..4230a3d
--- /dev/null
+++ b/apps/web/public/globe.svg
@@ -0,0 +1,10 @@
+
diff --git a/apps/web/public/next.svg b/apps/web/public/next.svg
new file mode 100644
index 0000000..5174b28
--- /dev/null
+++ b/apps/web/public/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/public/turborepo-dark.svg b/apps/web/public/turborepo-dark.svg
new file mode 100644
index 0000000..dae38fe
--- /dev/null
+++ b/apps/web/public/turborepo-dark.svg
@@ -0,0 +1,19 @@
+
diff --git a/apps/web/public/turborepo-light.svg b/apps/web/public/turborepo-light.svg
new file mode 100644
index 0000000..ddea915
--- /dev/null
+++ b/apps/web/public/turborepo-light.svg
@@ -0,0 +1,19 @@
+
diff --git a/apps/web/public/vercel.svg b/apps/web/public/vercel.svg
new file mode 100644
index 0000000..0164ddc
--- /dev/null
+++ b/apps/web/public/vercel.svg
@@ -0,0 +1,10 @@
+
diff --git a/apps/web/public/window.svg b/apps/web/public/window.svg
new file mode 100644
index 0000000..bbc7800
--- /dev/null
+++ b/apps/web/public/window.svg
@@ -0,0 +1,3 @@
+
diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json
new file mode 100644
index 0000000..7aef056
--- /dev/null
+++ b/apps/web/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "@repo/typescript-config/nextjs.json",
+ "compilerOptions": {
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
+ },
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ "next-env.d.ts",
+ "next.config.js",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/concord-client/.eslintrc.cjs b/concord-client/.eslintrc.cjs
deleted file mode 100644
index 7dbd9d1..0000000
--- a/concord-client/.eslintrc.cjs
+++ /dev/null
@@ -1,18 +0,0 @@
-module.exports = {
- root: true,
- env: { browser: true, es2020: true },
- extends: [
- 'eslint:recommended',
- 'plugin:@typescript-eslint/recommended',
- 'plugin:react-hooks/recommended',
- ],
- ignorePatterns: ['dist', '.eslintrc.cjs'],
- parser: '@typescript-eslint/parser',
- plugins: ['react-refresh'],
- rules: {
- 'react-refresh/only-export-components': [
- 'warn',
- { allowConstantExport: true },
- ],
- },
-}
diff --git a/concord-client/.gitignore b/concord-client/.gitignore
deleted file mode 100644
index f5b9d7c..0000000
--- a/concord-client/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-dist-electron
-*.local
-release/
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/concord-client/README.md b/concord-client/README.md
deleted file mode 100644
index f02aedf..0000000
--- a/concord-client/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# React + TypeScript + Vite
-
-This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
-
-Currently, two official plugins are available:
-
-- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
-- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
-
-## Expanding the ESLint configuration
-
-If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
-
-- Configure the top-level `parserOptions` property like this:
-
-```js
-export default {
- // other rules...
- parserOptions: {
- ecmaVersion: 'latest',
- sourceType: 'module',
- project: ['./tsconfig.json', './tsconfig.node.json'],
- tsconfigRootDir: __dirname,
- },
-}
-```
-
-- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
-- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
-- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
diff --git a/concord-client/bun.lock b/concord-client/bun.lock
deleted file mode 100644
index fd348f3..0000000
--- a/concord-client/bun.lock
+++ /dev/null
@@ -1,1513 +0,0 @@
-{
- "lockfileVersion": 1,
- "workspaces": {
- "": {
- "name": "concord-client",
- "dependencies": {
- "@radix-ui/react-avatar": "^1.1.10",
- "@radix-ui/react-dialog": "^1.1.15",
- "@radix-ui/react-dropdown-menu": "^2.1.16",
- "@radix-ui/react-label": "^2.1.7",
- "@radix-ui/react-scroll-area": "^1.2.10",
- "@radix-ui/react-select": "^2.2.6",
- "@radix-ui/react-separator": "^1.1.7",
- "@radix-ui/react-slider": "^1.3.6",
- "@radix-ui/react-slot": "^1.2.3",
- "@radix-ui/react-switch": "^1.2.6",
- "@radix-ui/react-tooltip": "^1.2.8",
- "@tailwindcss/vite": "^4.1.14",
- "@tanstack/react-query": "^5.90.2",
- "@tanstack/react-query-devtools": "^5.90.2",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "date-fns": "^4.1.0",
- "lucide-react": "^0.544.0",
- "next-themes": "^0.4.6",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "react-markdown": "^10.1.0",
- "react-router": "^7.9.3",
- "react-syntax-highlighter": "^15.6.6",
- "socket.io-client": "^4.8.1",
- "sonner": "^2.0.7",
- "tailwind-merge": "^3.3.1",
- "tailwindcss": "^4.1.14",
- "zustand": "^5.0.8",
- },
- "devDependencies": {
- "@types/bcrypt": "^6.0.0",
- "@types/bun": "^1.2.23",
- "@types/react": "^18.3.26",
- "@types/react-dom": "^18.3.7",
- "@types/react-syntax-highlighter": "^15.5.13",
- "@types/socket.io-client": "^3.0.0",
- "@typescript-eslint/eslint-plugin": "^7.18.0",
- "@typescript-eslint/parser": "^7.18.0",
- "@vitejs/plugin-react": "^4.7.0",
- "electron": "^30.5.1",
- "electron-builder": "^24.13.3",
- "eslint": "^8.57.1",
- "eslint-plugin-react-hooks": "^4.6.2",
- "eslint-plugin-react-refresh": "^0.4.23",
- "tw-animate-css": "^1.4.0",
- "typescript": "^5.9.3",
- "vite": "^5.4.20",
- "vite-plugin-electron": "^0.28.8",
- "vite-plugin-electron-renderer": "^0.14.6",
- },
- },
- },
- "packages": {
- "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="],
-
- "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
-
- "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="],
-
- "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="],
-
- "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="],
-
- "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
-
- "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
-
- "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
-
- "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
-
- "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
-
- "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
-
- "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
-
- "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
-
- "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
-
- "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="],
-
- "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
-
- "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
-
- "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="],
-
- "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
-
- "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="],
-
- "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
-
- "@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="],
-
- "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
-
- "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="],
-
- "@electron/notarize": ["@electron/notarize@2.2.1", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1", "promise-retry": "^2.0.1" } }, "sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg=="],
-
- "@electron/osx-sign": ["@electron/osx-sign@1.0.5", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww=="],
-
- "@electron/universal": ["@electron/universal@1.5.1", "", { "dependencies": { "@electron/asar": "^3.2.1", "@malept/cross-spawn-promise": "^1.1.0", "debug": "^4.3.1", "dir-compare": "^3.0.0", "fs-extra": "^9.0.1", "minimatch": "^3.0.4", "plist": "^3.0.4" } }, "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw=="],
-
- "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
-
- "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
-
- "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="],
-
- "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="],
-
- "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="],
-
- "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="],
-
- "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="],
-
- "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="],
-
- "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="],
-
- "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="],
-
- "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="],
-
- "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="],
-
- "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="],
-
- "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="],
-
- "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="],
-
- "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="],
-
- "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="],
-
- "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="],
-
- "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="],
-
- "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="],
-
- "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="],
-
- "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="],
-
- "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
-
- "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
-
- "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
-
- "@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="],
-
- "@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="],
-
- "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="],
-
- "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="],
-
- "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="],
-
- "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="],
-
- "@humanwhocodes/config-array": ["@humanwhocodes/config-array@0.13.0", "", { "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" } }, "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw=="],
-
- "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
-
- "@humanwhocodes/object-schema": ["@humanwhocodes/object-schema@2.0.3", "", {}, "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="],
-
- "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
-
- "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
-
- "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
-
- "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
-
- "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
-
- "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
-
- "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
-
- "@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@1.1.1", "", { "dependencies": { "cross-spawn": "^7.0.1" } }, "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ=="],
-
- "@malept/flatpak-bundler": ["@malept/flatpak-bundler@0.4.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.0", "lodash": "^4.17.15", "tmp-promise": "^3.0.2" } }, "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q=="],
-
- "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
-
- "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
-
- "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
-
- "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
-
- "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
-
- "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
-
- "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
-
- "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
-
- "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
-
- "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
-
- "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
-
- "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
-
- "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="],
-
- "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
-
- "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
-
- "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
-
- "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
-
- "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
-
- "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
-
- "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
-
- "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
-
- "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
-
- "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
-
- "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
-
- "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
-
- "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="],
-
- "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
-
- "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
-
- "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
-
- "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
-
- "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
-
- "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
-
- "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="],
-
- "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
-
- "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="],
-
- "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
-
- "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
-
- "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
-
- "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
-
- "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.2", "", { "os": "android", "cpu": "arm" }, "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ=="],
-
- "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw=="],
-
- "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA=="],
-
- "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ=="],
-
- "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw=="],
-
- "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng=="],
-
- "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.2", "", { "os": "linux", "cpu": "arm" }, "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA=="],
-
- "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.2", "", { "os": "linux", "cpu": "arm" }, "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w=="],
-
- "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg=="],
-
- "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA=="],
-
- "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.2", "", { "os": "linux", "cpu": "none" }, "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw=="],
-
- "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A=="],
-
- "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.2", "", { "os": "linux", "cpu": "none" }, "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w=="],
-
- "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.2", "", { "os": "linux", "cpu": "none" }, "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q=="],
-
- "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ=="],
-
- "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.2", "", { "os": "linux", "cpu": "x64" }, "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA=="],
-
- "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.2", "", { "os": "linux", "cpu": "x64" }, "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ=="],
-
- "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.2", "", { "os": "none", "cpu": "arm64" }, "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q=="],
-
- "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA=="],
-
- "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A=="],
-
- "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.2", "", { "os": "win32", "cpu": "x64" }, "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA=="],
-
- "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.2", "", { "os": "win32", "cpu": "x64" }, "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw=="],
-
- "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="],
-
- "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="],
-
- "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="],
-
- "@tailwindcss/node": ["@tailwindcss/node@4.1.14", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.0", "lightningcss": "1.30.1", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.14" } }, "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw=="],
-
- "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.14", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.5.1" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.14", "@tailwindcss/oxide-darwin-arm64": "4.1.14", "@tailwindcss/oxide-darwin-x64": "4.1.14", "@tailwindcss/oxide-freebsd-x64": "4.1.14", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", "@tailwindcss/oxide-linux-x64-musl": "4.1.14", "@tailwindcss/oxide-wasm32-wasi": "4.1.14", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" } }, "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw=="],
-
- "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.14", "", { "os": "android", "cpu": "arm64" }, "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ=="],
-
- "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA=="],
-
- "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw=="],
-
- "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.14", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw=="],
-
- "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14", "", { "os": "linux", "cpu": "arm" }, "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw=="],
-
- "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w=="],
-
- "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ=="],
-
- "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.14", "", { "os": "linux", "cpu": "x64" }, "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg=="],
-
- "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.14", "", { "os": "linux", "cpu": "x64" }, "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q=="],
-
- "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.14", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.5", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ=="],
-
- "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA=="],
-
- "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.14", "", { "os": "win32", "cpu": "x64" }, "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA=="],
-
- "@tailwindcss/vite": ["@tailwindcss/vite@4.1.14", "", { "dependencies": { "@tailwindcss/node": "4.1.14", "@tailwindcss/oxide": "4.1.14", "tailwindcss": "4.1.14" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA=="],
-
- "@tanstack/query-core": ["@tanstack/query-core@5.90.2", "", {}, "sha512-k/TcR3YalnzibscALLwxeiLUub6jN5EDLwKDiO7q5f4ICEoptJ+n9+7vcEFy5/x/i6Q+Lb/tXrsKCggf5uQJXQ=="],
-
- "@tanstack/query-devtools": ["@tanstack/query-devtools@5.90.1", "", {}, "sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ=="],
-
- "@tanstack/react-query": ["@tanstack/react-query@5.90.2", "", { "dependencies": { "@tanstack/query-core": "5.90.2" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-CLABiR+h5PYfOWr/z+vWFt5VsOA2ekQeRQBFSKlcoW6Ndx/f8rfyVmq4LbgOM4GG2qtxAxjLYLOpCNTYm4uKzw=="],
-
- "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.90.2", "", { "dependencies": { "@tanstack/query-devtools": "5.90.1" }, "peerDependencies": { "@tanstack/react-query": "^5.90.2", "react": "^18 || ^19" } }, "sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ=="],
-
- "@tootallnate/once": ["@tootallnate/once@2.0.0", "", {}, "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A=="],
-
- "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
-
- "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
-
- "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
-
- "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
-
- "@types/bcrypt": ["@types/bcrypt@6.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ=="],
-
- "@types/bun": ["@types/bun@1.2.23", "", { "dependencies": { "bun-types": "1.2.23" } }, "sha512-le8ueOY5b6VKYf19xT3McVbXqLqmxzPXHsQT/q9JHgikJ2X22wyTW3g3ohz2ZMnp7dod6aduIiq8A14Xyimm0A=="],
-
- "@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="],
-
- "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
-
- "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
-
- "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
-
- "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="],
-
- "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
-
- "@types/http-cache-semantics": ["@types/http-cache-semantics@4.0.4", "", {}, "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="],
-
- "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="],
-
- "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
-
- "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
-
- "@types/node": ["@types/node@20.19.17", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ=="],
-
- "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="],
-
- "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
-
- "@types/react": ["@types/react@18.3.26", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA=="],
-
- "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
-
- "@types/react-syntax-highlighter": ["@types/react-syntax-highlighter@15.5.13", "", { "dependencies": { "@types/react": "*" } }, "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA=="],
-
- "@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="],
-
- "@types/socket.io-client": ["@types/socket.io-client@3.0.0", "", { "dependencies": { "socket.io-client": "*" } }, "sha512-s+IPvFoEIjKA3RdJz/Z2dGR4gLgysKi8owcnrVwNjgvc01Lk68LJDDsG2GRqegFITcxmvCMYM7bhMpwEMlHmDg=="],
-
- "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
-
- "@types/verror": ["@types/verror@1.10.11", "", {}, "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg=="],
-
- "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
-
- "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@7.18.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/type-utils": "7.18.0", "@typescript-eslint/utils": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "peerDependencies": { "@typescript-eslint/parser": "^7.0.0", "eslint": "^8.56.0" } }, "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw=="],
-
- "@typescript-eslint/parser": ["@typescript-eslint/parser@7.18.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg=="],
-
- "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" } }, "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA=="],
-
- "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@7.18.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA=="],
-
- "@typescript-eslint/types": ["@typescript-eslint/types@7.18.0", "", {}, "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ=="],
-
- "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" } }, "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA=="],
-
- "@typescript-eslint/utils": ["@typescript-eslint/utils@7.18.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", "@typescript-eslint/typescript-estree": "7.18.0" }, "peerDependencies": { "eslint": "^8.56.0" } }, "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw=="],
-
- "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@7.18.0", "", { "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" } }, "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg=="],
-
- "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
-
- "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
-
- "@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="],
-
- "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
-
- "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
-
- "agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
-
- "ajv": ["ajv@6.12.6", "", { "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-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
-
- "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="],
-
- "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
-
- "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
-
- "app-builder-bin": ["app-builder-bin@4.0.0", "", {}, "sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA=="],
-
- "app-builder-lib": ["app-builder-lib@24.13.3", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/notarize": "2.2.1", "@electron/osx-sign": "1.0.5", "@electron/universal": "1.5.1", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", "builder-util": "24.13.1", "builder-util-runtime": "9.2.4", "chromium-pickle-js": "^0.2.0", "debug": "^4.3.4", "ejs": "^3.1.8", "electron-publish": "24.13.1", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "is-ci": "^3.0.0", "isbinaryfile": "^5.0.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "minimatch": "^5.1.1", "read-config-file": "6.3.2", "sanitize-filename": "^1.6.3", "semver": "^7.3.8", "tar": "^6.1.12", "temp-file": "^3.4.0" }, "peerDependencies": { "dmg-builder": "24.13.3", "electron-builder-squirrel-windows": "24.13.3" } }, "sha512-FAzX6IBit2POXYGnTCT8YHFO/lr5AapAII6zzhQO3Rw4cEDOgK+t1xhLc5tNcKlicTHlo9zxIwnYCX9X2DLkig=="],
-
- "archiver": ["archiver@5.3.2", "", { "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.1.2", "tar-stream": "^2.2.0", "zip-stream": "^4.1.0" } }, "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw=="],
-
- "archiver-utils": ["archiver-utils@2.1.0", "", { "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^2.0.0" } }, "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw=="],
-
- "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
-
- "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
-
- "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
-
- "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="],
-
- "astral-regex": ["astral-regex@2.0.0", "", {}, "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="],
-
- "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
-
- "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="],
-
- "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
-
- "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
-
- "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
-
- "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
-
- "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
-
- "baseline-browser-mapping": ["baseline-browser-mapping@2.8.7", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-bxxN2M3a4d1CRoQC//IqsR5XrLh0IJ8TCv2x6Y9N0nckNz/rTjZB3//GGscZziZOxmjP55rzxg/ze7usFI9FqQ=="],
-
- "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
-
- "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
-
- "bluebird-lst": ["bluebird-lst@1.0.9", "", { "dependencies": { "bluebird": "^3.5.5" } }, "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw=="],
-
- "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="],
-
- "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
-
- "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
-
- "browserslist": ["browserslist@4.26.2", "", { "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", "electron-to-chromium": "^1.5.218", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A=="],
-
- "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
-
- "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
-
- "buffer-equal": ["buffer-equal@1.0.1", "", {}, "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg=="],
-
- "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
-
- "builder-util": ["builder-util@24.13.1", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "4.0.0", "bluebird-lst": "^1.0.9", "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.1", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0" } }, "sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA=="],
-
- "builder-util-runtime": ["builder-util-runtime@9.2.4", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA=="],
-
- "bun-types": ["bun-types@1.2.23", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-R9f0hKAZXgFU3mlrA0YpE/fiDvwV0FT9rORApt2aQVWSuJDzZOyB5QLc0N/4HF57CS8IXJ6+L5E4W1bW6NS2Aw=="],
-
- "cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="],
-
- "cacheable-request": ["cacheable-request@7.0.4", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="],
-
- "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
-
- "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
-
- "caniuse-lite": ["caniuse-lite@1.0.30001745", "", {}, "sha512-ywt6i8FzvdgrrrGbr1jZVObnVv6adj+0if2/omv9cmR2oiZs30zL4DIyaptKcbOrBdOIc74QTMoJvSE2QHh5UQ=="],
-
- "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
-
- "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
-
- "character-entities": ["character-entities@1.2.4", "", {}, "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="],
-
- "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
-
- "character-entities-legacy": ["character-entities-legacy@1.1.4", "", {}, "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="],
-
- "character-reference-invalid": ["character-reference-invalid@1.1.4", "", {}, "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="],
-
- "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
-
- "chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="],
-
- "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
-
- "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
-
- "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="],
-
- "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
-
- "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="],
-
- "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
-
- "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
-
- "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
-
- "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
-
- "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
-
- "commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
-
- "compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="],
-
- "compress-commons": ["compress-commons@4.1.2", "", { "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg=="],
-
- "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
-
- "config-file-ts": ["config-file-ts@0.2.6", "", { "dependencies": { "glob": "^10.3.10", "typescript": "^5.3.3" } }, "sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w=="],
-
- "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
-
- "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
-
- "core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
-
- "crc": ["crc@3.8.0", "", { "dependencies": { "buffer": "^5.1.0" } }, "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ=="],
-
- "crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="],
-
- "crc32-stream": ["crc32-stream@4.0.3", "", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" } }, "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw=="],
-
- "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
-
- "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
-
- "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
-
- "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
-
- "decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
-
- "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
-
- "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
-
- "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="],
-
- "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
-
- "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
-
- "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
-
- "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
-
- "detect-libc": ["detect-libc@2.1.1", "", {}, "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw=="],
-
- "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="],
-
- "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
-
- "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
-
- "dir-compare": ["dir-compare@3.3.0", "", { "dependencies": { "buffer-equal": "^1.0.0", "minimatch": "^3.0.4" } }, "sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg=="],
-
- "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
-
- "dmg-builder": ["dmg-builder@24.13.3", "", { "dependencies": { "app-builder-lib": "24.13.3", "builder-util": "24.13.1", "builder-util-runtime": "9.2.4", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ=="],
-
- "dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "^3.0.1", "@types/verror": "^1.10.3", "ajv": "^6.10.0", "crc": "^3.8.0", "iconv-corefoundation": "^1.1.7", "plist": "^3.0.4", "smart-buffer": "^4.0.2", "verror": "^1.10.0" }, "os": "darwin", "bin": { "dmg-license": "bin/dmg-license.js" } }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="],
-
- "doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="],
-
- "dotenv": ["dotenv@9.0.2", "", {}, "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg=="],
-
- "dotenv-expand": ["dotenv-expand@5.1.0", "", {}, "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="],
-
- "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
-
- "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
-
- "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
-
- "electron": ["electron@30.5.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-AhL7+mZ8Lg14iaNfoYTkXQ2qee8mmsQyllKdqxlpv/zrKgfxz6jNVtcRRbQtLxtF8yzcImWdfTQROpYiPumdbw=="],
-
- "electron-builder": ["electron-builder@24.13.3", "", { "dependencies": { "app-builder-lib": "24.13.3", "builder-util": "24.13.1", "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "dmg-builder": "24.13.3", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "read-config-file": "6.3.2", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg=="],
-
- "electron-builder-squirrel-windows": ["electron-builder-squirrel-windows@24.13.3", "", { "dependencies": { "app-builder-lib": "24.13.3", "archiver": "^5.3.1", "builder-util": "24.13.1", "fs-extra": "^10.1.0" } }, "sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg=="],
-
- "electron-publish": ["electron-publish@24.13.1", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "24.13.1", "builder-util-runtime": "9.2.4", "chalk": "^4.1.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A=="],
-
- "electron-to-chromium": ["electron-to-chromium@1.5.224", "", {}, "sha512-kWAoUu/bwzvnhpdZSIc6KUyvkI1rbRXMT0Eq8pKReyOyaPZcctMli+EgvcN1PAvwVc7Tdo4Fxi2PsLNDU05mdg=="],
-
- "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
-
- "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
-
- "engine.io-client": ["engine.io-client@6.6.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w=="],
-
- "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="],
-
- "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
-
- "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="],
-
- "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="],
-
- "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
-
- "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
-
- "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
-
- "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
-
- "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="],
-
- "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
-
- "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
-
- "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
-
- "eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="],
-
- "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@4.6.2", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ=="],
-
- "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.23", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-G4j+rv0NmbIR45kni5xJOrYvCtyD3/7LjpVH8MPPcudXDcNu8gv+4ATTDXTtbRR8rTCM5HxECvCSsRmxKnWDsA=="],
-
- "eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="],
-
- "eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
-
- "espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="],
-
- "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
-
- "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
-
- "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
-
- "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="],
-
- "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
-
- "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
-
- "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="],
-
- "extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="],
-
- "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
-
- "fast-glob": ["fast-glob@3.3.3", "", { "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.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
-
- "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
-
- "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
-
- "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
-
- "fault": ["fault@1.0.4", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA=="],
-
- "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="],
-
- "file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="],
-
- "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="],
-
- "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
-
- "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
-
- "flat-cache": ["flat-cache@3.2.0", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw=="],
-
- "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
-
- "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
-
- "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
-
- "format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="],
-
- "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
-
- "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
-
- "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
-
- "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
-
- "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
-
- "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
-
- "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
-
- "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
-
- "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
-
- "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
-
- "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
-
- "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
-
- "glob": ["glob@10.4.5", "", { "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-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
-
- "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
-
- "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="],
-
- "globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="],
-
- "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
-
- "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
-
- "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
-
- "got": ["got@11.8.6", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="],
-
- "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
-
- "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
-
- "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
-
- "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
-
- "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
-
- "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
-
- "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
-
- "hast-util-parse-selector": ["hast-util-parse-selector@2.2.5", "", {}, "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ=="],
-
- "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="],
-
- "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
-
- "hastscript": ["hastscript@6.0.0", "", { "dependencies": { "@types/hast": "^2.0.0", "comma-separated-tokens": "^1.0.0", "hast-util-parse-selector": "^2.0.0", "property-information": "^5.0.0", "space-separated-tokens": "^1.0.0" } }, "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w=="],
-
- "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
-
- "highlightjs-vue": ["highlightjs-vue@1.0.0", "", {}, "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA=="],
-
- "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="],
-
- "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
-
- "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
-
- "http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
-
- "http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="],
-
- "https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
-
- "iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="],
-
- "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
-
- "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
-
- "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
-
- "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
-
- "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
-
- "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
-
- "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
-
- "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="],
-
- "is-alphabetical": ["is-alphabetical@1.0.4", "", {}, "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="],
-
- "is-alphanumerical": ["is-alphanumerical@1.0.4", "", { "dependencies": { "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0" } }, "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A=="],
-
- "is-ci": ["is-ci@3.0.1", "", { "dependencies": { "ci-info": "^3.2.0" }, "bin": { "is-ci": "bin.js" } }, "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ=="],
-
- "is-decimal": ["is-decimal@1.0.4", "", {}, "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="],
-
- "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
-
- "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
-
- "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
-
- "is-hexadecimal": ["is-hexadecimal@1.0.4", "", {}, "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="],
-
- "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
-
- "is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="],
-
- "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
-
- "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
-
- "isbinaryfile": ["isbinaryfile@5.0.6", "", {}, "sha512-I+NmIfBHUl+r2wcDd6JwE9yWje/PIVY/R5/CmV8dXLZd5K+L9X2klAOwfAHNnondLXkbHyTAleQAWonpTJBTtw=="],
-
- "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
-
- "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
-
- "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="],
-
- "jiti": ["jiti@2.6.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ=="],
-
- "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
-
- "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
-
- "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
-
- "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
-
- "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
-
- "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
-
- "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="],
-
- "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
-
- "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
-
- "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
-
- "lazy-val": ["lazy-val@1.0.5", "", {}, "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q=="],
-
- "lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="],
-
- "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
-
- "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
-
- "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
-
- "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
-
- "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
-
- "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
-
- "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
-
- "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
-
- "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
-
- "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
-
- "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
-
- "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
-
- "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
-
- "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
-
- "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="],
-
- "lodash.difference": ["lodash.difference@4.5.0", "", {}, "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA=="],
-
- "lodash.flatten": ["lodash.flatten@4.4.0", "", {}, "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="],
-
- "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
-
- "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
-
- "lodash.union": ["lodash.union@4.6.0", "", {}, "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw=="],
-
- "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
-
- "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
-
- "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="],
-
- "lowlight": ["lowlight@1.20.0", "", { "dependencies": { "fault": "^1.0.0", "highlight.js": "~10.7.0" } }, "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw=="],
-
- "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
-
- "lucide-react": ["lucide-react@0.544.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw=="],
-
- "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="],
-
- "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="],
-
- "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
-
- "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="],
-
- "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
-
- "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="],
-
- "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="],
-
- "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="],
-
- "mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="],
-
- "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="],
-
- "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="],
-
- "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
-
- "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
-
- "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
-
- "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="],
-
- "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="],
-
- "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="],
-
- "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="],
-
- "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="],
-
- "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
-
- "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="],
-
- "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="],
-
- "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="],
-
- "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="],
-
- "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="],
-
- "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="],
-
- "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="],
-
- "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="],
-
- "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="],
-
- "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="],
-
- "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="],
-
- "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
-
- "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
-
- "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
-
- "mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="],
-
- "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
-
- "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
-
- "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
-
- "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
-
- "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
-
- "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
-
- "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
-
- "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
-
- "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
-
- "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
-
- "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
-
- "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="],
-
- "node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="],
-
- "node-releases": ["node-releases@2.0.21", "", {}, "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw=="],
-
- "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
-
- "normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="],
-
- "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
-
- "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
-
- "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
-
- "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="],
-
- "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
-
- "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
-
- "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
-
- "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
-
- "parse-entities": ["parse-entities@2.0.0", "", { "dependencies": { "character-entities": "^1.0.0", "character-entities-legacy": "^1.0.0", "character-reference-invalid": "^1.0.0", "is-alphanumerical": "^1.0.0", "is-decimal": "^1.0.0", "is-hexadecimal": "^1.0.0" } }, "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ=="],
-
- "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
-
- "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
-
- "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
-
- "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
-
- "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
-
- "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
-
- "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
-
- "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
-
- "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="],
-
- "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
-
- "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
-
- "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
-
- "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
-
- "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
-
- "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="],
-
- "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
-
- "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
-
- "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
-
- "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
-
- "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="],
-
- "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
-
- "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
-
- "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
-
- "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
-
- "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="],
-
- "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
-
- "react-router": ["react-router@7.9.3", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg=="],
-
- "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
-
- "react-syntax-highlighter": ["react-syntax-highlighter@15.6.6", "", { "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.30.0", "refractor": "^3.6.0" }, "peerDependencies": { "react": ">= 0.14.0" } }, "sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw=="],
-
- "read-config-file": ["read-config-file@6.3.2", "", { "dependencies": { "config-file-ts": "^0.2.4", "dotenv": "^9.0.2", "dotenv-expand": "^5.1.0", "js-yaml": "^4.1.0", "json5": "^2.2.0", "lazy-val": "^1.0.4" } }, "sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q=="],
-
- "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
-
- "readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="],
-
- "refractor": ["refractor@3.6.0", "", { "dependencies": { "hastscript": "^6.0.0", "parse-entities": "^2.0.0", "prismjs": "~1.27.0" } }, "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA=="],
-
- "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="],
-
- "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="],
-
- "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
-
- "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="],
-
- "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
-
- "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="],
-
- "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
-
- "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
-
- "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
-
- "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
-
- "rollup": ["rollup@4.52.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.2", "@rollup/rollup-android-arm64": "4.52.2", "@rollup/rollup-darwin-arm64": "4.52.2", "@rollup/rollup-darwin-x64": "4.52.2", "@rollup/rollup-freebsd-arm64": "4.52.2", "@rollup/rollup-freebsd-x64": "4.52.2", "@rollup/rollup-linux-arm-gnueabihf": "4.52.2", "@rollup/rollup-linux-arm-musleabihf": "4.52.2", "@rollup/rollup-linux-arm64-gnu": "4.52.2", "@rollup/rollup-linux-arm64-musl": "4.52.2", "@rollup/rollup-linux-loong64-gnu": "4.52.2", "@rollup/rollup-linux-ppc64-gnu": "4.52.2", "@rollup/rollup-linux-riscv64-gnu": "4.52.2", "@rollup/rollup-linux-riscv64-musl": "4.52.2", "@rollup/rollup-linux-s390x-gnu": "4.52.2", "@rollup/rollup-linux-x64-gnu": "4.52.2", "@rollup/rollup-linux-x64-musl": "4.52.2", "@rollup/rollup-openharmony-arm64": "4.52.2", "@rollup/rollup-win32-arm64-msvc": "4.52.2", "@rollup/rollup-win32-ia32-msvc": "4.52.2", "@rollup/rollup-win32-x64-gnu": "4.52.2", "@rollup/rollup-win32-x64-msvc": "4.52.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA=="],
-
- "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
-
- "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
-
- "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
-
- "sanitize-filename": ["sanitize-filename@1.6.3", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg=="],
-
- "sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
-
- "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
-
- "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
-
- "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="],
-
- "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="],
-
- "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
-
- "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
-
- "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
-
- "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
-
- "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="],
-
- "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
-
- "slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="],
-
- "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
-
- "socket.io-client": ["socket.io-client@4.8.1", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ=="],
-
- "socket.io-parser": ["socket.io-parser@4.2.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew=="],
-
- "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
-
- "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
-
- "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
-
- "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
-
- "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
-
- "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="],
-
- "stat-mode": ["stat-mode@1.0.0", "", {}, "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg=="],
-
- "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=="],
-
- "string-width-cjs": ["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=="],
-
- "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
-
- "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
-
- "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
-
- "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
-
- "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
-
- "style-to-js": ["style-to-js@1.1.17", "", { "dependencies": { "style-to-object": "1.0.9" } }, "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA=="],
-
- "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="],
-
- "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="],
-
- "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
-
- "tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
-
- "tailwindcss": ["tailwindcss@4.1.14", "", {}, "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA=="],
-
- "tapable": ["tapable@2.2.3", "", {}, "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg=="],
-
- "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
-
- "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
-
- "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="],
-
- "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="],
-
- "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="],
-
- "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="],
-
- "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
-
- "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
-
- "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
-
- "truncate-utf8-bytes": ["truncate-utf8-bytes@1.0.2", "", { "dependencies": { "utf8-byte-length": "^1.0.1" } }, "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ=="],
-
- "ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="],
-
- "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
-
- "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
-
- "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
-
- "type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="],
-
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
-
- "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
-
- "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
-
- "unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
-
- "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
-
- "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
-
- "unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
-
- "unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
-
- "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
-
- "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
-
- "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
-
- "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
-
- "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
-
- "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
-
- "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="],
-
- "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
-
- "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="],
-
- "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
-
- "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
-
- "vite": ["vite@5.4.20", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g=="],
-
- "vite-plugin-electron": ["vite-plugin-electron@0.28.8", "", { "peerDependencies": { "vite-plugin-electron-renderer": "*" }, "optionalPeers": ["vite-plugin-electron-renderer"] }, "sha512-ir+B21oSGK9j23OEvt4EXyco9xDCaF6OGFe0V/8Zc0yL2+HMyQ6mmNQEIhXsEsZCSfIowBpwQBeHH4wVsfraeg=="],
-
- "vite-plugin-electron-renderer": ["vite-plugin-electron-renderer@0.14.6", "", {}, "sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw=="],
-
- "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
-
- "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
-
- "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
-
- "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
-
- "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
-
- "ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
-
- "xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="],
-
- "xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="],
-
- "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
-
- "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
-
- "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
-
- "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
-
- "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
-
- "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
-
- "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
-
- "zip-stream": ["zip-stream@4.1.1", "", { "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", "readable-stream": "^3.6.0" } }, "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ=="],
-
- "zustand": ["zustand@5.0.8", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw=="],
-
- "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=="],
-
- "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
- "@electron/asar/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
-
- "@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
-
- "@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
-
- "@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
-
- "@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="],
-
- "@electron/universal/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
-
- "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
-
- "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
-
- "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
-
- "@isaacs/fs-minipass/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
-
- "@malept/flatpak-bundler/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
-
- "@tailwindcss/oxide/tar": ["tar@7.5.1", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.6", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-DXj75ewm11LIWUk198QSKUTxjyRjsBwk09MuMk5DGK+GDUtyPhhEHOGP/Xwwj3DjQXXkivoBirmOnKrLfc0+9g=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
-
- "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
-
- "@types/react-syntax-highlighter/@types/react": ["@types/react@18.3.24", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A=="],
-
- "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
-
- "app-builder-lib/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
-
- "archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
-
- "archiver-utils/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
-
- "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
-
- "config-file-ts/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
-
- "decode-named-character-reference/character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
-
- "engine.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
-
- "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
-
- "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
-
- "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
-
- "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
-
- "glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
-
- "hastscript/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="],
-
- "hastscript/comma-separated-tokens": ["comma-separated-tokens@1.0.8", "", {}, "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw=="],
-
- "hastscript/property-information": ["property-information@5.6.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA=="],
-
- "hastscript/space-separated-tokens": ["space-separated-tokens@1.1.5", "", {}, "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA=="],
-
- "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
-
- "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
-
- "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
-
- "mdast-util-mdx-jsx/parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],
-
- "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
-
- "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
-
- "path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
-
- "readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
-
- "refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="],
-
- "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
-
- "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
-
- "socket.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
-
- "socket.io-parser/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
-
- "string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
-
- "stringify-entities/character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
-
- "zip-stream/archiver-utils": ["archiver-utils@3.0.4", "", { "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw=="],
-
- "@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
-
- "@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
-
- "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
-
- "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
-
- "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
-
- "@tailwindcss/oxide/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
-
- "@tailwindcss/oxide/tar/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
-
- "@tailwindcss/oxide/tar/minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
-
- "@tailwindcss/oxide/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
-
- "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "app-builder-lib/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "archiver-utils/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
-
- "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "hastscript/@types/hast/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
-
- "mdast-util-mdx-jsx/parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
-
- "mdast-util-mdx-jsx/parse-entities/character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
-
- "mdast-util-mdx-jsx/parse-entities/character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
-
- "mdast-util-mdx-jsx/parse-entities/is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="],
-
- "mdast-util-mdx-jsx/parse-entities/is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
-
- "mdast-util-mdx-jsx/parse-entities/is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
-
- "readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
-
- "zip-stream/archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
-
- "mdast-util-mdx-jsx/parse-entities/is-alphanumerical/is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
- }
-}
diff --git a/concord-client/components.json b/concord-client/components.json
deleted file mode 100644
index 2b0833f..0000000
--- a/concord-client/components.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "$schema": "https://ui.shadcn.com/schema.json",
- "style": "new-york",
- "rsc": false,
- "tsx": true,
- "tailwind": {
- "config": "",
- "css": "src/index.css",
- "baseColor": "neutral",
- "cssVariables": true,
- "prefix": ""
- },
- "iconLibrary": "lucide",
- "aliases": {
- "components": "@/components",
- "utils": "@/lib/utils",
- "ui": "@/components/ui",
- "lib": "@/lib",
- "hooks": "@/hooks"
- },
- "registries": {}
-}
diff --git a/concord-client/electron-builder.json5 b/concord-client/electron-builder.json5
deleted file mode 100644
index cd633dc..0000000
--- a/concord-client/electron-builder.json5
+++ /dev/null
@@ -1,43 +0,0 @@
-// @see - https://www.electron.build/configuration/configuration
-{
- "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
- "appId": "YourAppID",
- "asar": true,
- "productName": "YourAppName",
- "directories": {
- "output": "release/${version}"
- },
- "files": [
- "dist",
- "dist-electron"
- ],
- "mac": {
- "target": [
- "dmg"
- ],
- "artifactName": "${productName}-Mac-${version}-Installer.${ext}"
- },
- "win": {
- "target": [
- {
- "target": "nsis",
- "arch": [
- "x64"
- ]
- }
- ],
- "artifactName": "${productName}-Windows-${version}-Setup.${ext}"
- },
- "nsis": {
- "oneClick": false,
- "perMachine": false,
- "allowToChangeInstallationDirectory": true,
- "deleteAppDataOnUninstall": false
- },
- "linux": {
- "target": [
- "AppImage"
- ],
- "artifactName": "${productName}-Linux-${version}.${ext}"
- }
-}
diff --git a/concord-client/electron/electron-env.d.ts b/concord-client/electron/electron-env.d.ts
deleted file mode 100644
index 1fdef4b..0000000
--- a/concord-client/electron/electron-env.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-///
-
-declare namespace NodeJS {
- interface ProcessEnv {
- /**
- * The built directory structure
- *
- * ```tree
- * ├─┬─┬ dist
- * │ │ └── index.html
- * │ │
- * │ ├─┬ dist-electron
- * │ │ ├── main.js
- * │ │ └── preload.js
- * │
- * ```
- */
- APP_ROOT: string
- /** /dist/ or /public/ */
- VITE_PUBLIC: string
- }
-}
-
-// Used in Renderer process, expose in `preload.ts`
-interface Window {
- ipcRenderer: import('electron').IpcRenderer
-}
diff --git a/concord-client/electron/main.ts b/concord-client/electron/main.ts
deleted file mode 100644
index dd45b52..0000000
--- a/concord-client/electron/main.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import { app, BrowserWindow } from "electron";
-// import { createRequire } from 'node:module'
-import { fileURLToPath } from "node:url";
-import path from "node:path";
-
-// const require = createRequire(import.meta.url)
-const __dirname = path.dirname(fileURLToPath(import.meta.url));
-
-// The built directory structure
-//
-// ├─┬─┬ dist
-// │ │ └── index.html
-// │ │
-// │ ├─┬ dist-electron
-// │ │ ├── main.js
-// │ │ └── preload.mjs
-// │
-process.env.APP_ROOT = path.join(__dirname, "..");
-
-// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x
-export const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"];
-export const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron");
-export const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist");
-
-process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
- ? path.join(process.env.APP_ROOT, "public")
- : RENDERER_DIST;
-
-let win: BrowserWindow | null;
-
-function createWindow() {
- win = new BrowserWindow({
- icon: path.join(process.env.VITE_PUBLIC, "electron-vite.svg"),
- webPreferences: {
- preload: path.join(__dirname, "preload.mjs"),
- },
- });
-
- // Test active push message to Renderer-process.
- win.webContents.on("did-finish-load", () => {
- win?.webContents.send("main-process-message", new Date().toLocaleString());
- });
-
- if (VITE_DEV_SERVER_URL) {
- win.loadURL(VITE_DEV_SERVER_URL);
- } else {
- // win.loadFile('dist/index.html')
- win.loadFile(path.join(RENDERER_DIST, "index.html"));
- }
-}
-
-// Quit when all windows are closed, except on macOS. There, it's common
-// for applications and their menu bar to stay active until the user quits
-// explicitly with Cmd + Q.
-app.on("window-all-closed", () => {
- if (process.platform !== "darwin") {
- app.quit();
- win = null;
- }
-});
-
-app.on("activate", () => {
- // On OS X it's common to re-create a window in the app when the
- // dock icon is clicked and there are no other windows open.
- if (BrowserWindow.getAllWindows().length === 0) {
- createWindow();
- }
-});
-
-app.whenReady().then(createWindow);
diff --git a/concord-client/electron/preload.ts b/concord-client/electron/preload.ts
deleted file mode 100644
index 05e341d..0000000
--- a/concord-client/electron/preload.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { ipcRenderer, contextBridge } from 'electron'
-
-// --------- Expose some API to the Renderer process ---------
-contextBridge.exposeInMainWorld('ipcRenderer', {
- on(...args: Parameters) {
- const [channel, listener] = args
- return ipcRenderer.on(channel, (event, ...args) => listener(event, ...args))
- },
- off(...args: Parameters) {
- const [channel, ...omit] = args
- return ipcRenderer.off(channel, ...omit)
- },
- send(...args: Parameters) {
- const [channel, ...omit] = args
- return ipcRenderer.send(channel, ...omit)
- },
- invoke(...args: Parameters) {
- const [channel, ...omit] = args
- return ipcRenderer.invoke(channel, ...omit)
- },
-
- // You can expose other APTs you need here.
- // ...
-})
diff --git a/concord-client/index.html b/concord-client/index.html
deleted file mode 100644
index 1136dde..0000000
--- a/concord-client/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
- Vite + React + TS
-
-
-
-
-
-
diff --git a/concord-client/package.json b/concord-client/package.json
deleted file mode 100644
index 961da11..0000000
--- a/concord-client/package.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "name": "concord-client",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev:web": "VITE_APP_MODE=web bunx --bun vite",
- "dev:electron": "bunx --bun vite --open",
- "build": "tsc && bunx --bun vite build && electron-builder",
- "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
- "preview": "bunx --bun vite preview"
- },
- "dependencies": {
- "@radix-ui/react-avatar": "^1.1.10",
- "@radix-ui/react-dialog": "^1.1.15",
- "@radix-ui/react-dropdown-menu": "^2.1.16",
- "@radix-ui/react-label": "^2.1.7",
- "@radix-ui/react-scroll-area": "^1.2.10",
- "@radix-ui/react-select": "^2.2.6",
- "@radix-ui/react-separator": "^1.1.7",
- "@radix-ui/react-slider": "^1.3.6",
- "@radix-ui/react-slot": "^1.2.3",
- "@radix-ui/react-switch": "^1.2.6",
- "@radix-ui/react-tooltip": "^1.2.8",
- "@tailwindcss/vite": "^4.1.14",
- "@tanstack/react-query": "^5.90.2",
- "@tanstack/react-query-devtools": "^5.90.2",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "date-fns": "^4.1.0",
- "lucide-react": "^0.544.0",
- "next-themes": "^0.4.6",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
- "react-markdown": "^10.1.0",
- "react-router": "^7.9.3",
- "react-syntax-highlighter": "^15.6.6",
- "socket.io-client": "^4.8.1",
- "sonner": "^2.0.7",
- "tailwind-merge": "^3.3.1",
- "tailwindcss": "^4.1.14",
- "zustand": "^5.0.8"
- },
- "devDependencies": {
- "@types/bcrypt": "^6.0.0",
- "@types/bun": "^1.2.23",
- "@types/react": "^18.3.26",
- "@types/react-dom": "^18.3.7",
- "@types/react-syntax-highlighter": "^15.5.13",
- "@types/socket.io-client": "^3.0.0",
- "@typescript-eslint/eslint-plugin": "^7.18.0",
- "@typescript-eslint/parser": "^7.18.0",
- "@vitejs/plugin-react": "^4.7.0",
- "electron": "^30.5.1",
- "electron-builder": "^24.13.3",
- "eslint": "^8.57.1",
- "eslint-plugin-react-hooks": "^4.6.2",
- "eslint-plugin-react-refresh": "^0.4.23",
- "tw-animate-css": "^1.4.0",
- "typescript": "^5.9.3",
- "vite": "^5.4.20",
- "vite-plugin-electron": "^0.28.8",
- "vite-plugin-electron-renderer": "^0.14.6"
- },
- "main": "dist-electron/main.js"
-}
diff --git a/concord-client/public/electron-vite.animate.svg b/concord-client/public/electron-vite.animate.svg
deleted file mode 100644
index ea3e777..0000000
--- a/concord-client/public/electron-vite.animate.svg
+++ /dev/null
@@ -1,34 +0,0 @@
-
diff --git a/concord-client/public/electron-vite.svg b/concord-client/public/electron-vite.svg
deleted file mode 100644
index 8a6aefe..0000000
--- a/concord-client/public/electron-vite.svg
+++ /dev/null
@@ -1,26 +0,0 @@
-
diff --git a/concord-client/public/vite.svg b/concord-client/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/concord-client/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/concord-client/src/App.tsx b/concord-client/src/App.tsx
deleted file mode 100644
index bf875e0..0000000
--- a/concord-client/src/App.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import React, { useEffect } from "react";
-import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router";
-import { QueryClientProvider } from "@tanstack/react-query";
-import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
-import { Toaster } from "@/components/ui/sonner";
-
-import { ThemeProvider } from "@/components/theme-provider";
-import AppLayout from "@/components/layout/AppLayout";
-import LoginPage from "@/pages/LoginPage";
-import ChatPage from "@/pages/ChatPage";
-import SettingsPage from "@/pages/SettingsPage";
-import NotFoundPage from "@/pages/NotFoundPage";
-import { useVoiceStore } from "@/stores/voiceStore";
-
-import { queryClient } from "@/lib/api-client";
-import { useAuthStore } from "@/stores/authStore";
-import ErrorBoundary from "@/components/common/ErrorBoundary";
-import { Home } from "lucide-react";
-import { Socket } from "socket.io-client";
-
-// Protected Route wrapper
-const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({
- children,
-}) => {
- const { isAuthenticated } = useAuthStore();
-
- // Enable this when you want to enforce authentication
- if (!isAuthenticated) {
- return ;
- }
-
- return <>{children}>;
-};
-
-// Home page component - shows server selection
-const HomePage: React.FC = () => {
- return (
-
-
-
-
-
-
- Welcome to Concord
-
-
- Select a server from the sidebar to start chatting, or create a new
- server
-
-
-
- );
-};
-
-function App(props: { socket: Socket }) {
- const initVoiceStore = useVoiceStore((state) => state.init);
-
- useEffect(() => {
- initVoiceStore(props.socket);
- return () => {
- useVoiceStore.getState().cleanup();
- };
- }, [props.socket, initVoiceStore]);
-
- return (
-
-
-
-
-
-
- {/* Auth routes */}
- } />
-
- {/* Protected routes with layout */}
-
-
-
- }
- >
- {/* Default redirect to home */}
- } />
-
- {/* Server and channel routes */}
- } />
- }
- />
-
- {/* Settings */}
- } />
- } />
-
-
- {/* 404 */}
- } />
-
-
-
-
- {import.meta.env.DEV === true && }
- {/* Toast notifications */}
-
-
-
-
- );
-}
-
-export default App;
diff --git a/concord-client/src/README.md b/concord-client/src/README.md
deleted file mode 100644
index 87f2d27..0000000
--- a/concord-client/src/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# TODO
-
-- Messages
- - Channels should include messages
- - sample data
- - message components
-- User
- - Set up fake user with auth to:
- - Confirm userpanel is ok
- - test login flow
-- Add server ui
-- Add channel ui
-- Role based for above ^
diff --git a/concord-client/src/assets/react.svg b/concord-client/src/assets/react.svg
deleted file mode 100644
index 6c87de9..0000000
--- a/concord-client/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/concord-client/src/components/channel/ChannelItem.tsx b/concord-client/src/components/channel/ChannelItem.tsx
deleted file mode 100644
index b06f892..0000000
--- a/concord-client/src/components/channel/ChannelItem.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import React from "react";
-import { Hash, Volume2 } from "lucide-react";
-import { useNavigate, useParams } from "react-router";
-import { Channel } from "@/lib/api-client";
-import { useVoiceStore } from "@/stores/voiceStore";
-import { useInstanceMembers } from "@/hooks/useServers";
-import { useAuthStore } from "@/stores/authStore";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-
-interface ChannelItemProps {
- channel: Channel;
-}
-
-const ChannelItem: React.FC = ({ channel }) => {
- const { instanceId, channelId: activeChannelId } = useParams();
- const navigate = useNavigate();
-
- // Voice store hooks
- const {
- joinChannel,
- leaveChannel,
- activeVoiceChannelId,
- remoteStreams,
- localStream,
- } = useVoiceStore();
-
- // Data hooks
- const { data: members } = useInstanceMembers(instanceId);
- const { user: currentUser, token } = useAuthStore(); // Get token from auth store
-
- const isConnectedToThisChannel = activeVoiceChannelId === channel.id;
- const isActive = activeChannelId === channel.id;
-
- const handleChannelClick = () => {
- if (channel.type === "text") {
- navigate(`/channels/${instanceId}/${channel.id}`);
- } else if (channel.type === "voice") {
- if (isConnectedToThisChannel) {
- leaveChannel();
- } else if (currentUser && token) {
- joinChannel(channel.id, currentUser.id, token);
- }
- }
- };
-
- const Icon = channel.type === "voice" ? Volume2 : Hash;
- const connectedUserIds = Array.from(remoteStreams.keys());
-
- return (
-
-
-
- {/* Render connected users for this voice channel */}
- {isConnectedToThisChannel && (
-
- {/* Current User */}
- {localStream && currentUser && (
-
-
-
-
- {currentUser.username.slice(0, 2)}
-
-
-
- {currentUser.nickname || currentUser.username}
-
-
- )}
-
- {/* Remote Users */}
- {connectedUserIds.map((userId) => {
- const member = members?.find((m) => m.id === userId);
- if (!member) return null;
- return (
-
-
-
- {member.username.slice(0, 2)}
-
-
- {member.nickname || member.username}
-
-
- );
- })}
-
- )}
-
- );
-};
-
-export default ChannelItem;
diff --git a/concord-client/src/components/channel/ChannelList.tsx b/concord-client/src/components/channel/ChannelList.tsx
deleted file mode 100644
index 6862c86..0000000
--- a/concord-client/src/components/channel/ChannelList.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import React, { useState } from "react";
-import { ChevronDown, ChevronRight } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { CategoryWithChannels } from "@/types/api";
-import ChannelItem from "@/components/channel/ChannelItem";
-
-interface CategoryHeaderProps {
- category: CategoryWithChannels;
- isExpanded: boolean;
- onToggle: () => void;
-}
-
-const CategoryHeader: React.FC = ({
- category,
- isExpanded,
- onToggle,
-}) => {
- return (
-
- );
-};
-
-interface ChannelListProps {
- categories: CategoryWithChannels[];
-}
-
-const ChannelList: React.FC = ({ categories }) => {
- // Track expanded categories
- const [expandedCategories, setExpandedCategories] = useState>(
- new Set(categories.map((cat) => cat.id)), // Start with all expanded
- );
-
- const toggleCategory = (categoryId: string) => {
- setExpandedCategories((prev) => {
- const newSet = new Set(prev);
- if (newSet.has(categoryId)) {
- newSet.delete(categoryId);
- } else {
- newSet.add(categoryId);
- }
- return newSet;
- });
- };
-
- if (!categories || categories.length === 0) {
- return (
-
- No channels available
-
- );
- }
-
- return (
-
- {categories
- .sort((a, b) => a.position - b.position)
- .map((category) => {
- const isExpanded = expandedCategories.has(category.id);
-
- return (
-
- {/* Category Header */}
-
toggleCategory(category.id)}
- />
-
-
- {category.channels
- .sort((a, b) => a.position - b.position)
- .map((channel) => (
-
- ))}
-
-
- );
- })}
-
- );
-};
-
-export default ChannelList;
diff --git a/concord-client/src/components/common/Avatar.tsx b/concord-client/src/components/common/Avatar.tsx
deleted file mode 100644
index c75e9f7..0000000
--- a/concord-client/src/components/common/Avatar.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import React from "react";
-import {
- Avatar as ShadcnAvatar,
- AvatarFallback,
- AvatarImage,
-} from "@/components/ui/avatar";
-import { User } from "@/types/database";
-import { cn } from "@/lib/utils";
-
-interface AvatarProps {
- user: Pick;
- size?: "xs" | "sm" | "md" | "lg" | "xl";
- showStatus?: boolean;
- className?: string;
- onClick?: () => void;
-}
-
-const sizeClasses = {
- xs: "h-6 w-6",
- sm: "h-8 w-8",
- md: "h-10 w-10",
- lg: "h-12 w-12",
- xl: "h-16 w-16",
-};
-
-const statusSizes = {
- xs: "w-2 h-2",
- sm: "w-3 h-3",
- md: "w-3 h-3",
- lg: "w-4 h-4",
- xl: "w-5 h-5",
-};
-
-const statusPositions = {
- xs: "-bottom-0.5 -right-0.5",
- sm: "-bottom-0.5 -right-0.5",
- md: "-bottom-0.5 -right-0.5",
- lg: "-bottom-1 -right-1",
- xl: "-bottom-1 -right-1",
-};
-
-const Avatar: React.FC = ({
- user,
- size = "md",
- showStatus = false,
- className,
- onClick,
-}) => {
- const getStatusColor = (status: string) => {
- switch (status) {
- case "online":
- return "bg-status-online";
- case "away":
- return "bg-status-away";
- case "busy":
- return "bg-status-busy";
- case "offline":
- default:
- return "bg-status-offline";
- }
- };
-
- const getUserInitials = (username: string, nickname: string | null) => {
- const name = nickname || username;
- return name
- .split(" ")
- .map((word) => word[0])
- .join("")
- .toUpperCase()
- .slice(0, 2);
- };
-
- const getFallbackColor = (userId: string) => {
- // Generate a consistent color based on user ID using theme colors
- const colors = [
- "bg-red-500",
- "bg-blue-500",
- "bg-green-500",
- "bg-yellow-500",
- "bg-purple-500",
- "bg-pink-500",
- "bg-indigo-500",
- "bg-teal-500",
- ];
-
- const hash = userId.split("").reduce((a, b) => {
- a = (a << 5) - a + b.charCodeAt(0);
- return a & a;
- }, 0);
-
- return colors[Math.abs(hash) % colors.length];
- };
-
- return (
-
-
-
-
- {getUserInitials(user.username, user.nickname ? user.nickname : null)}
-
-
-
- {showStatus && (
-
- )}
-
- );
-};
-
-export default Avatar;
diff --git a/concord-client/src/components/common/ErrorBoundary.tsx b/concord-client/src/components/common/ErrorBoundary.tsx
deleted file mode 100644
index 114999a..0000000
--- a/concord-client/src/components/common/ErrorBoundary.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import { Component, ErrorInfo, ReactNode } from "react";
-import { AlertTriangle, RotateCcw } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
-import { Card } from "../ui/card";
-
-interface Props {
- children: ReactNode;
- fallback?: ReactNode;
-}
-
-interface State {
- hasError: boolean;
- error?: Error;
- errorInfo?: ErrorInfo;
-}
-
-class ErrorBoundary extends Component {
- public state: State = {
- hasError: false,
- };
-
- public static getDerivedStateFromError(error: Error): State {
- return { hasError: true, error };
- }
-
- public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
- console.error("ErrorBoundary caught an error:", error, errorInfo);
-
- this.setState({
- error,
- errorInfo,
- });
- }
-
- private handleReload = () => {
- window.location.reload();
- };
-
- private handleReset = () => {
- this.setState({ hasError: false, error: undefined, errorInfo: undefined });
- };
-
- public render() {
- if (this.state.hasError) {
- // Custom fallback UI
- if (this.props.fallback) {
- return this.props.fallback;
- }
-
- return (
-
-
-
-
-
- Something went wrong
-
-
- The application encountered an unexpected error. This might be a
- temporary issue.
-
-
-
-
-
-
-
-
-
- {/* Error details in development */}
- {process.env.NODE_ENV === "development" && this.state.error && (
-
-
- Error Details (Development)
-
-
-
- Error: {this.state.error.message}
-
-
-
Stack:
-
- {this.state.error.stack}
-
-
- {this.state.errorInfo && (
-
-
Component Stack:
-
- {this.state.errorInfo.componentStack}
-
-
- )}
-
-
- )}
-
-
- );
- }
-
- return this.props.children;
- }
-}
-
-export default ErrorBoundary;
diff --git a/concord-client/src/components/common/LoadingSpinner.tsx b/concord-client/src/components/common/LoadingSpinner.tsx
deleted file mode 100644
index df06b08..0000000
--- a/concord-client/src/components/common/LoadingSpinner.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from "react";
-import { cn } from "@/lib/utils";
-
-interface LoadingSpinnerProps {
- size?: "xs" | "sm" | "md" | "lg" | "xl";
- className?: string;
- color?: "white" | "blue" | "gray";
-}
-
-const sizeClasses = {
- xs: "h-3 w-3",
- sm: "h-4 w-4",
- md: "h-6 w-6",
- lg: "h-8 w-8",
- xl: "h-12 w-12",
-};
-
-const colorClasses = {
- white: "border-white",
- blue: "border-blue-500",
- gray: "border-gray-400",
-};
-
-const LoadingSpinner: React.FC = ({
- size = "md",
- className,
- color = "white",
-}) => {
- return (
-
- );
-};
-
-export default LoadingSpinner;
diff --git a/concord-client/src/components/layout/AppLayout.tsx b/concord-client/src/components/layout/AppLayout.tsx
deleted file mode 100644
index 2ce90d8..0000000
--- a/concord-client/src/components/layout/AppLayout.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React, { useEffect } from "react";
-import { Outlet, useLocation } from "react-router";
-import { useAuthStore } from "@/stores/authStore";
-import { useUiStore } from "@/stores/uiStore";
-
-import ServerSidebar from "@/components/layout/ServerSidebar";
-import ChannelSidebar from "@/components/layout/ChannelSidebar";
-import UserPanel from "@/components/layout/UserPanel";
-import MemberList from "@/components/layout/MemberList";
-import LoadingSpinner from "@/components/common/LoadingSpinner";
-import VoiceConnectionManager from "@/components/voice/VoiceConnectionManager";
-
-const AppLayout: React.FC = () => {
- const { isLoading } = useAuthStore();
- const {
- showMemberList,
- sidebarCollapsed,
- shouldShowChannelSidebar,
- updateSidebarVisibility,
- } = useUiStore();
- const location = useLocation();
-
- // Update sidebar visibility when route changes
- useEffect(() => {
- updateSidebarVisibility(location.pathname);
- }, [location.pathname, updateSidebarVisibility]);
-
- if (isLoading) {
- return (
-
-
-
- );
- }
-
- return (
-
- {/* This component handles playing audio from remote users */}
-
-
- {/* Server List Sidebar - Always visible on desktop, overlay on mobile */}
-
-
-
- {/* Channel Sidebar - Only shown when in a server context and not collapsed */}
- {shouldShowChannelSidebar && (
-
- )}
- {/* Main Content Area */}
-
-
-
- {/* Member List - Only shown when in a channel and member list is enabled */}
- {showMemberList && shouldShowChannelSidebar && (
-
-
-
- )}
-
- );
-};
-
-export default AppLayout;
diff --git a/concord-client/src/components/layout/ChannelSidebar.tsx b/concord-client/src/components/layout/ChannelSidebar.tsx
deleted file mode 100644
index 1181e54..0000000
--- a/concord-client/src/components/layout/ChannelSidebar.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import React from "react";
-import { useParams } from "react-router";
-import { ChevronDown, Plus } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { ScrollArea } from "@/components/ui/scroll-area";
-import { useInstanceDetails } from "@/hooks/useServers";
-import { useUiStore } from "@/stores/uiStore";
-import ChannelList from "@/components/channel/ChannelList";
-import { CreateChannelModal } from "@/components/modals/CreateChannelModal";
-
-const ChannelSidebar: React.FC = () => {
- const { instanceId } = useParams();
- const { data: instance, isLoading: instanceLoading } =
- useInstanceDetails(instanceId);
- const categories = instance?.categories;
- const {
- showCreateChannel,
- closeCreateChannel,
- openCreateChannel,
- openServerSettings,
- } = useUiStore();
-
- // Only show for valid instance IDs
- if (!instanceId) {
- return null;
- }
-
- if (instanceLoading) {
- return (
-
- );
- }
-
- if (!instance) {
- return (
-
- );
- }
-
- return (
-
-
- {/* Server Header */}
-
-
-
-
-
-
- {/* Channel Categories and Channels */}
-
-
- {categories && categories.length > 0 ? (
-
- ) : (
-
- No channels yet
-
- )}
-
-
-
- {/* Bottom Actions */}
-
-
-
-
- );
-};
-
-export default ChannelSidebar;
diff --git a/concord-client/src/components/layout/MemberList.tsx b/concord-client/src/components/layout/MemberList.tsx
deleted file mode 100644
index 776143c..0000000
--- a/concord-client/src/components/layout/MemberList.tsx
+++ /dev/null
@@ -1,265 +0,0 @@
-import React from "react";
-import { useParams } from "react-router";
-import { Crown, Shield, UserIcon } from "lucide-react";
-import { ScrollArea } from "@/components/ui/scroll-area";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import { Button } from "@/components/ui/button";
-import { Role, User } from "@/types/database";
-import { useInstanceMembers } from "@/hooks/useServers";
-import { useAuthStore } from "@/stores/authStore";
-
-const getStatusColor = (status: string) => {
- switch (status) {
- case "online":
- return "bg-status-online";
- case "away":
- return "bg-status-away";
- case "busy":
- return "bg-status-busy";
- default:
- return "bg-status-offline";
- }
-};
-
-interface MemberItemProps {
- member: User;
- instanceId: string;
- isOwner?: boolean;
- currentUserRolePriority: number;
-}
-
-const getUserRoleForInstance = (roles: Role[], instanceId: string): string => {
- if (!instanceId) return "member";
- const roleEntry = roles.find((r) => r.instanceId === instanceId);
- return roleEntry?.role || "member";
-};
-
-const getRoleInfo = (role: string) => {
- const lowerRole = role.toLowerCase();
- switch (lowerRole) {
- case "admin":
- return { color: "#ff6b6b", priority: 3, name: "Admin" };
- case "mod":
- return { color: "#4ecdc4", priority: 2, name: "Moderator" };
- case "member":
- return { color: null, priority: 1, name: "Member" };
- default:
- return {
- color: null,
- priority: 0,
- name: role.charAt(0).toUpperCase() + role.slice(1),
- };
- }
-};
-
-const MemberItem: React.FC = ({
- member,
- instanceId,
- isOwner = false,
- currentUserRolePriority,
-}) => {
- // Determine the role for this specific instance
- const userRole = getUserRoleForInstance(member.roles, instanceId);
- const roleInfo = getRoleInfo(userRole);
- const memberRolePriority = roleInfo.priority;
-
- // Consider if this member is a global admin as well
- const isGlobalAdmin = member.admin || false;
- let effectiveRoleInfo = roleInfo;
- let effectiveMemberRolePriority = memberRolePriority;
-
- if (isGlobalAdmin && roleInfo.priority < 3) {
- effectiveRoleInfo = getRoleInfo("admin");
- effectiveMemberRolePriority = 3;
- }
-
- return (
-
- );
-};
-
-const MemberList: React.FC = () => {
- const { instanceId } = useParams<{ instanceId: string }>();
- const { data: members, isLoading } = useInstanceMembers(instanceId);
- const { user: currentUser } = useAuthStore();
-
- const currentUserRoleInfo = React.useMemo(() => {
- if (!currentUser || !instanceId) {
- return { role: "member", priority: 1, name: "Member", color: null };
- }
-
- // If the current user is a global admin, they are effectively an admin of any instance.
- if (currentUser.admin) {
- return { role: "admin", priority: 3, name: "Admin", color: "#ff6b6b" };
- }
-
- const role = getUserRoleForInstance(currentUser.roles, instanceId);
- return { ...getRoleInfo(role), role: role };
- }, [currentUser, instanceId]);
-
- if (!instanceId) {
- return null;
- }
-
- if (isLoading) {
- return (
-
- );
- }
-
- if (!members || members.length === 0) {
- return (
-
- );
- }
-
- // Group members by their role for the current instance.
- const groupedMembers = members.reduce(
- (acc, member) => {
- // Determine the effective role for this instance.
- let effectiveRoleName = getUserRoleForInstance(
- member.roles as Role[],
- instanceId,
- );
-
- // Global admin is instance admin
- if (member.admin && effectiveRoleName !== "admin") {
- effectiveRoleName = "admin";
- }
-
- const roleInfo = getRoleInfo(effectiveRoleName);
-
- if (!acc[roleInfo.name]) {
- acc[roleInfo.name] = [];
- }
- acc[roleInfo.name].push(member as User);
- return acc;
- },
- {} as Record,
- );
-
- // Get all unique role names present and sort them by priority.
- const sortedRoleNames = Object.keys(groupedMembers).sort(
- (roleNameA, roleNameB) => {
- const priorityA = getRoleInfo(roleNameA).priority;
- const priorityB = getRoleInfo(roleNameB).priority;
- return priorityB - priorityA;
- },
- );
-
- return (
-
- {/* Header */}
-
-
-
- {members.length}
-
-
-
- {/* Member List */}
-
-
- {sortedRoleNames.map((roleName) => {
- const roleMembers = groupedMembers[roleName];
- // Sort members within each role group alphabetically by username.
- const sortedMembers = roleMembers.sort((a, b) =>
- (a.nickname || a.username).localeCompare(
- b.nickname || b.username,
- ),
- );
-
- return (
-
- {/* Role Header */}
-
-
- {roleName} — {roleMembers.length}
-
-
-
- {/* Role Members */}
-
- {sortedMembers.map((member) => (
-
- ))}
-
-
- );
- })}
-
-
-
- );
-};
-
-export default MemberList;
diff --git a/concord-client/src/components/layout/ServerSidebar.tsx b/concord-client/src/components/layout/ServerSidebar.tsx
deleted file mode 100644
index 4ef3a90..0000000
--- a/concord-client/src/components/layout/ServerSidebar.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import React from "react";
-import { useNavigate, useParams } from "react-router";
-import { Plus, Home } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-import { useServers } from "@/hooks/useServers";
-import { useUiStore } from "@/stores/uiStore";
-import { useAuthStore } from "@/stores/authStore";
-import ServerIcon from "@/components/server/ServerIcon";
-import { getAccessibleInstances, isGlobalAdmin } from "@/utils/permissions";
-
-const ServerSidebar: React.FC = () => {
- const navigate = useNavigate();
- const { instanceId } = useParams();
- const { data: allServers = [], isLoading } = useServers();
- const { openCreateServer, setActiveInstance, getSelectedChannelForInstance } =
- useUiStore();
- const { user: currentUser } = useAuthStore();
-
- // Filter servers based on user permissions
- const accessibleServers = getAccessibleInstances(currentUser, allServers);
- const canCreateServer = isGlobalAdmin(currentUser);
-
- const handleServerClick = (serverId: string) => {
- setActiveInstance(serverId);
- const lastChannelId = getSelectedChannelForInstance(serverId);
-
- if (lastChannelId) {
- navigate(`/channels/${serverId}/${lastChannelId}`);
- } else {
- // Fallback: navigate to the server, let the page component handle finding a channel
- navigate(`/channels/${serverId}`);
- }
- };
-
- const handleHomeClick = () => {
- setActiveInstance(null);
- navigate("/");
- };
-
- const handleCreateServer = () => {
- if (canCreateServer) {
- openCreateServer();
- }
- };
-
- return (
-
-
- {/* Home/DM Button */}
-
-
-
-
-
- {isGlobalAdmin(currentUser) ? "Admin Dashboard" : "Home"}
-
-
- {/* Separator */}
-
{" "}
- {/* Server List */}
-
- {isLoading ? (
-
- ) : accessibleServers.length > 0 ? (
- accessibleServers.map((server) => (
-
-
-
- handleServerClick(server.id)}
- />
-
-
-
- {server.name}
-
-
- ))
- ) : currentUser ? (
-
-
- No servers available
-
- {canCreateServer && (
-
- )}
-
- ) : null}
- {/* Add Server Button - Only show if user can create servers */}
- {canCreateServer && (
-
-
-
-
-
- Add a Server
-
-
- )}
-
-
-
- );
-};
-
-export default ServerSidebar;
diff --git a/concord-client/src/components/layout/UserPanel.tsx b/concord-client/src/components/layout/UserPanel.tsx
deleted file mode 100644
index 0d45c2c..0000000
--- a/concord-client/src/components/layout/UserPanel.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-import React from "react";
-import { Settings, Mic, MicOff, Headphones } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-
-import { useAuthStore } from "@/stores/authStore";
-import { useVoiceStore } from "@/stores/voiceStore";
-import { useNavigate } from "react-router";
-
-// Status color utility
-const getStatusColor = (status: string) => {
- switch (status) {
- case "online":
- return "bg-status-online";
- case "away":
- return "bg-status-away";
- case "busy":
- return "bg-status-busy";
- default:
- return "bg-status-offline";
- }
-};
-
-// Voice Controls Component
-interface VoiceControlsProps {
- isMuted: boolean;
- isDeafened: boolean;
- onMuteToggle: () => void;
- onDeafenToggle: () => void;
-}
-
-const VoiceControls: React.FC = ({
- isMuted,
- isDeafened,
- onMuteToggle,
- onDeafenToggle,
-}) => {
- return (
-
-
- {/* Mute/Unmute */}
-
-
-
-
-
- {isMuted ? "Unmute" : "Mute"}
-
-
-
- {/* Deafen/Undeafen */}
-
-
-
-
-
- {isDeafened ? "Undeafen" : "Deafen"}
-
-
-
- {/* Settings */}
-
-
- );
-};
-
-// User Avatar Component
-interface UserAvatarProps {
- user: any;
- size?: "sm" | "md" | "lg";
- showStatus?: boolean;
-}
-
-const UserAvatar: React.FC = ({
- user,
- size = "md",
- showStatus = true,
-}) => {
- const sizeClasses = {
- sm: "h-6 w-6",
- md: "h-8 w-8",
- lg: "h-10 w-10",
- };
-
- const statusSizeClasses = {
- sm: "w-2 h-2",
- md: "w-3 h-3",
- lg: "w-4 h-4",
- };
-
- return (
-
-
-
-
- {user.username.slice(0, 2).toUpperCase()}
-
-
- {showStatus && (
-
- )}
-
- );
-};
-
-const UserPanel: React.FC = () => {
- const { user } = useAuthStore();
- const navigate = useNavigate();
-
- const { isConnected, isMuted, isDeafened, toggleMute, toggleDeafen } =
- useVoiceStore();
-
- return (
-
- {/* User Info */}
-
-
-
- {user?.nickname || user?.username}
-
-
- {user?.status}
-
-
-
- {/* Voice Controls */}
- {isConnected && (
-
- )}
-
-
-
-
-
-
-
- User Settings
-
-
-
-
- );
-};
-
-export default UserPanel;
diff --git a/concord-client/src/components/message/MessageActionsDropdown.tsx b/concord-client/src/components/message/MessageActionsDropdown.tsx
deleted file mode 100644
index 3feb71f..0000000
--- a/concord-client/src/components/message/MessageActionsDropdown.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from "react";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-import { Button } from "@/components/ui/button";
-import { Copy, Reply, MoreHorizontal } from "lucide-react";
-import { Message } from "@/lib/api-client";
-
-interface MessageActionsModalProps {
- message: Message;
- // isOwnMessage?: boolean;
- onReply?: (messageId: string) => void;
-}
-
-export const MessageActionsDropdown: React.FC = ({
- message,
- onReply,
- // isOwnMessage,
-}) => {
- const handleReply = () => {
- onReply?.(message.id);
- };
-
- const handleCopyText = () => {
- navigator.clipboard.writeText(message.text);
- };
-
- return (
-
-
-
-
-
-
-
- Reply
-
-
-
- Copy Text
-
-
-
- );
-};
diff --git a/concord-client/src/components/message/MessageComponent.tsx b/concord-client/src/components/message/MessageComponent.tsx
deleted file mode 100644
index 54ca920..0000000
--- a/concord-client/src/components/message/MessageComponent.tsx
+++ /dev/null
@@ -1,244 +0,0 @@
-import { Copy, Reply, Pin } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import ReactMarkdown from "react-markdown";
-import { formatDistanceToNow, isValid, parseISO } from "date-fns";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import SyntaxHighlighter from "react-syntax-highlighter";
-import {
- dark,
- solarizedLight,
-} from "react-syntax-highlighter/dist/esm/styles/hljs";
-import { useTheme } from "@/components/theme-provider";
-import { Message } from "@/lib/api-client";
-import { useState } from "react";
-
-// User type for message component
-interface MessageUser {
- id: string;
- username?: string;
- nickname?: string | null;
- picture?: string | null;
-}
-
-// Message Props interface
-interface MessageProps {
- message: Message;
- user: MessageUser;
- replyTo?: Message;
- replyToUser?: MessageUser;
- onReply?: (messageId: string) => void;
-}
-
-export const MessageComponent: React.FC = ({
- message,
- user,
- replyTo,
- replyToUser,
- onReply,
-}) => {
- const [isHovered, setIsHovered] = useState(false);
-
- const formatTimestamp = (timestamp: string) => {
- try {
- // First try parsing as ISO string
- let date = parseISO(timestamp);
-
- // If that fails, try regular Date constructor
- if (!isValid(date)) {
- date = new Date(timestamp);
- }
-
- // Final check if date is valid
- if (!isValid(date)) {
- console.error("Invalid timestamp:", timestamp);
- return "Invalid date";
- }
-
- return formatDistanceToNow(date, { addSuffix: true });
- } catch (error) {
- console.error("Error formatting timestamp:", timestamp, error);
- return "Invalid date";
- }
- };
- // const isOwnMessage = currentUser?.id === message.userId;
- const { mode } = useTheme();
-
- // Get username with fallback
- const username = user.username || user.username || "Unknown User";
- const displayName = user.nickname || user.nickname || username;
-
- const isDeleted = message.deleted;
-
- if (isDeleted) {
- return (
-
-
-
-
-
- This message has been deleted
-
-
-
-
- );
- }
-
- return (
- <>
- setIsHovered(true)}
- onMouseLeave={() => setIsHovered(false)}
- >
-
- {/* Avatar - always show */}
-
-
-
-
- {username.slice(0, 2).toUpperCase()}
-
-
-
-
- {/* Message content */}
-
- {/* Reply line and reference */}
- {replyTo && replyToUser && (
-
-
-
- {replyToUser.nickname || replyToUser.username}
-
-
- {replyTo.text.replace(/```[\s\S]*?```/g, "[code]")}
-
-
- )}
-
- {/* Header - always show */}
-
-
- {displayName}
-
-
- {formatTimestamp(message.createdAt)}
-
- {message.edited && (
-
- (edited)
-
- )}
- {(message as any).pinned && (
-
- )}
-
-
- {/* Message content with markdown */}
-
-
{
- const match = /language-(\w+)/.exec(className || "");
- return match ? (
-
-
-
- ) : (
- {children}
- );
- },
- blockquote: ({ children }) => (
-
- {children}
-
- ),
- p: ({ children }) => (
- {children}
- ),
- strong: ({ children }) => (
-
- {children}
-
- ),
- em: ({ children }) => (
- {children}
- ),
- ul: ({ children }) => (
-
- ),
- ol: ({ children }) => (
-
- {children}
-
- ),
- h1: ({ children }) => (
-
- {children}
-
- ),
- h2: ({ children }) => (
-
- {children}
-
- ),
- h3: ({ children }) => (
-
- {children}
-
- ),
- a: ({ children, href }) => (
-
- {children}
-
- ),
- }}
- >
- {message.text}
-
-
-
-
- {/* Message actions */}
- {isHovered && (
-
-
-
- {/* onReply?.(message.id)}
- />*/}
-
- )}
-
-
- >
- );
-};
diff --git a/concord-client/src/components/message/MessageInput.tsx b/concord-client/src/components/message/MessageInput.tsx
deleted file mode 100644
index 32213d9..0000000
--- a/concord-client/src/components/message/MessageInput.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { Message } from "@/lib/api-client";
-import { useState, useRef, useEffect } from "react";
-import { useSendMessage } from "@/hooks/useMessages";
-import { Button } from "@/components/ui/button";
-import { Textarea } from "@/components/ui/textarea";
-
-interface MessageUser {
- id: string;
- username?: string;
- nickname?: string | null;
- picture?: string | null;
-}
-interface MessageInputProps {
- channelId: string;
- channelName?: string;
- replyingTo?: Message | null;
- onCancelReply?: () => void;
- replyingToUser: MessageUser | null;
-}
-
-export const MessageInput: React.FC = ({
- channelId,
- channelName,
- replyingTo,
- onCancelReply,
- replyingToUser,
-}) => {
- const [content, setContent] = useState("");
- const formRef = useRef(null);
-
- // Use the API hook for sending messages
- const sendMessageMutation = useSendMessage();
-
- // Auto-resize textarea (using direct DOM access as a fallback, no ref needed)
- useEffect(() => {
- const textarea = document.getElementById(
- "message-input-textarea",
- ) as HTMLTextAreaElement | null;
- if (textarea) {
- textarea.style.height = "auto";
- textarea.style.height = `${textarea.scrollHeight}px`;
- }
- }, [content]);
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- if (content.trim() && !sendMessageMutation.isPending) {
- try {
- await sendMessageMutation.mutateAsync({
- channelId,
- content: content.trim(),
- repliedMessageId: replyingTo?.id || null,
- });
- setContent("");
- onCancelReply?.();
- } catch (error) {
- console.error("Failed to send message:", error);
- }
- }
- };
-
- const handleKeyDown = (e: React.KeyboardEvent) => {
- if (e.key === "Enter" && !e.shiftKey) {
- e.preventDefault();
- formRef.current?.requestSubmit();
- }
- };
-
- return (
-
- {replyingTo && replyingToUser && (
-
-
-
-
-
- {replyingToUser.nickname || replyingToUser.username}
-
-
-
-
-
- {replyingTo.text.replace(/```[\s\S]*?```/g, "[code]")}
-
-
- )}
-
-
-
- );
-};
diff --git a/concord-client/src/components/modals/CreateChannelModal.tsx b/concord-client/src/components/modals/CreateChannelModal.tsx
deleted file mode 100644
index 7288755..0000000
--- a/concord-client/src/components/modals/CreateChannelModal.tsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import React, { useState, useEffect } from "react";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Textarea } from "@/components/ui/textarea";
-import { Hash, Volume2, Loader2 } from "lucide-react";
-import { useCreateChannel } from "@/hooks/useServers";
-import { CategoryWithChannels } from "@/types";
-
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { toast } from "sonner";
-
-interface CreateChannelModalProps {
- isOpen: boolean;
- onClose: () => void;
- instanceId: string;
- categories: CategoryWithChannels[] | undefined;
-}
-
-export const CreateChannelModal: React.FC = ({
- isOpen,
- onClose,
- categories,
-}) => {
- const [name, setName] = useState("");
- const [description, setDescription] = useState("");
- const [type, setType] = useState<"text" | "voice">("text");
- const [categoryId, setCategoryId] = useState("");
-
- const createChannelMutation = useCreateChannel();
-
- // Reset form when modal opens or closes
- useEffect(() => {
- if (!isOpen) {
- setName("");
- setDescription("");
- setType("text");
- setCategoryId("");
- } else {
- setCategoryId("");
- }
- }, [isOpen]);
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- // Basic validation: ensure name is not empty and a category is selected
- if (!name.trim() || !categoryId || categoryId === "no-categories") {
- console.warn("Channel name and a valid category are required.");
- toast("Error", {
- description: "Channel name and a valid category are required.",
- });
- return;
- }
-
- try {
- await createChannelMutation.mutateAsync({
- name: name.trim(),
- description: description.trim(),
- type,
- categoryId,
- });
-
- // Reset form after successful creation
- setName("");
- setDescription("");
- setType("text");
- setCategoryId(""); // Reset to default or empty
- onClose();
- } catch (error) {
- console.error("Failed to create channel:", error);
- toast("Error", { description: {`${error}`}
});
- }
- };
-
- // Helper to determine if the form is in a valid state for submission
- const isFormInvalid =
- !name.trim() || // Name is required and cannot be just whitespace
- !categoryId || // Category must be selected
- categoryId === "no-categories" || // Handle the "no categories available" placeholder
- createChannelMutation.isPending; // Disable while mutation is in progress
-
- return (
-
- );
-};
diff --git a/concord-client/src/components/modals/CreateServerModal.tsx b/concord-client/src/components/modals/CreateServerModal.tsx
deleted file mode 100644
index a917123..0000000
--- a/concord-client/src/components/modals/CreateServerModal.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import React, { useState } from "react";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { useCreateInstance } from "@/hooks/useServers";
-
-interface CreateServerModalProps {
- isOpen: boolean;
- onClose: () => void;
-}
-
-export const CreateServerModal: React.FC = ({
- isOpen,
- onClose,
-}) => {
- const [name, setName] = useState("");
- const [icon, setIcon] = useState("");
-
- const createInstanceMutation = useCreateInstance();
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- if (!name.trim()) return;
-
- try {
- await createInstanceMutation.mutateAsync({
- name: name.trim(),
- icon: icon.trim() || undefined,
- });
-
- // Reset form
- setName("");
- setIcon("");
- onClose();
- } catch (error) {
- console.error("Failed to create server:", error);
- }
- };
-
- return (
-
- );
-};
diff --git a/concord-client/src/components/server/ServerIcon.tsx b/concord-client/src/components/server/ServerIcon.tsx
deleted file mode 100644
index 8f4b0c9..0000000
--- a/concord-client/src/components/server/ServerIcon.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from "react";
-import { Button } from "@/components/ui/button";
-import { Instance } from "@/types/database";
-
-interface ServerIconProps {
- server: Instance;
- isActive: boolean;
- onClick: () => void;
-}
-
-const ServerIcon: React.FC = ({
- server,
- isActive,
- onClick,
-}) => {
- const getServerInitials = (name: string) => {
- return name
- .split(" ")
- .map((word) => word[0])
- .join("")
- .toUpperCase()
- .slice(0, 2);
- };
-
- return (
-
- {/* Active indicator - Positioned outside to the left */}
-
-
-
- );
-};
-
-export default ServerIcon;
diff --git a/concord-client/src/components/theme-provider.tsx b/concord-client/src/components/theme-provider.tsx
deleted file mode 100644
index 2823fee..0000000
--- a/concord-client/src/components/theme-provider.tsx
+++ /dev/null
@@ -1,500 +0,0 @@
-import { createContext, useContext, useEffect, useState } from "react";
-
-export interface ThemeColors {
- background: string;
- foreground: string;
- card: string;
- cardForeground: string;
- popover: string;
- popoverForeground: string;
- primary: string;
- primaryForeground: string;
- secondary: string;
- secondaryForeground: string;
- muted: string;
- mutedForeground: string;
- accent: string;
- accentForeground: string;
- destructive: string;
- border: string;
- input: string;
- ring: string;
- // Chart colors
- chart1: string;
- chart2: string;
- chart3: string;
- chart4: string;
- chart5: string;
- // Sidebar colors
- sidebar: string;
- sidebarForeground: string;
- sidebarPrimary: string;
- sidebarPrimaryForeground: string;
- sidebarAccent: string;
- sidebarAccentForeground: string;
- sidebarBorder: string;
- sidebarRing: string;
-}
-
-export interface ThemeDefinition {
- id: string;
- name: string;
- description?: string;
- mode: "light" | "dark";
- colors: ThemeColors;
- isCustom?: boolean;
-}
-
-// Fixed themes using proper OKLCH format
-const DEFAULT_THEMES: ThemeDefinition[] = [
- {
- id: "default-light",
- name: "Default Light",
- mode: "light",
- colors: {
- background: "oklch(1 0 0)",
- foreground: "oklch(0.145 0 0)",
- card: "oklch(1 0 0)",
- cardForeground: "oklch(0.145 0 0)",
- popover: "oklch(1 0 0)",
- popoverForeground: "oklch(0.145 0 0)",
- primary: "oklch(0.205 0 0)",
- primaryForeground: "oklch(0.985 0 0)",
- secondary: "oklch(0.97 0 0)",
- secondaryForeground: "oklch(0.205 0 0)",
- muted: "oklch(0.97 0 0)",
- mutedForeground: "oklch(0.556 0 0)",
- accent: "oklch(0.97 0 0)",
- accentForeground: "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)",
- chart1: "oklch(0.646 0.222 41.116)",
- chart2: "oklch(0.6 0.118 184.704)",
- chart3: "oklch(0.398 0.07 227.392)",
- chart4: "oklch(0.828 0.189 84.429)",
- chart5: "oklch(0.769 0.188 70.08)",
- sidebar: "oklch(0.985 0 0)",
- sidebarForeground: "oklch(0.145 0 0)",
- sidebarPrimary: "oklch(0.205 0 0)",
- sidebarPrimaryForeground: "oklch(0.985 0 0)",
- sidebarAccent: "oklch(0.97 0 0)",
- sidebarAccentForeground: "oklch(0.205 0 0)",
- sidebarBorder: "oklch(0.922 0 0)",
- sidebarRing: "oklch(0.708 0 0)",
- },
- },
- {
- id: "default-dark",
- name: "Default Dark",
- mode: "dark",
- colors: {
- background: "oklch(0.145 0 0)",
- foreground: "oklch(0.985 0 0)",
- card: "oklch(0.205 0 0)",
- cardForeground: "oklch(0.985 0 0)",
- popover: "oklch(0.205 0 0)",
- popoverForeground: "oklch(0.985 0 0)",
- primary: "oklch(0.922 0 0)",
- primaryForeground: "oklch(0.205 0 0)",
- secondary: "oklch(0.269 0 0)",
- secondaryForeground: "oklch(0.985 0 0)",
- muted: "oklch(0.269 0 0)",
- mutedForeground: "oklch(0.708 0 0)",
- accent: "oklch(0.269 0 0)",
- accentForeground: "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)",
- chart1: "oklch(0.488 0.243 264.376)",
- chart2: "oklch(0.696 0.17 162.48)",
- chart3: "oklch(0.769 0.188 70.08)",
- chart4: "oklch(0.627 0.265 303.9)",
- chart5: "oklch(0.645 0.246 16.439)",
- sidebar: "oklch(0.205 0 0)",
- sidebarForeground: "oklch(0.985 0 0)",
- sidebarPrimary: "oklch(0.488 0.243 264.376)",
- sidebarPrimaryForeground: "oklch(0.985 0 0)",
- sidebarAccent: "oklch(0.269 0 0)",
- sidebarAccentForeground: "oklch(0.985 0 0)",
- sidebarBorder: "oklch(1 0 0 / 10%)",
- sidebarRing: "oklch(0.556 0 0)",
- },
- },
- {
- id: "paper-light",
- name: "Paper",
- description: "Clean paper-like theme",
- mode: "light",
- colors: {
- background: "oklch(0.99 0.01 85)",
- foreground: "oklch(0.15 0.02 65)",
- card: "oklch(0.99 0.01 85)",
- cardForeground: "oklch(0.15 0.02 65)",
- popover: "oklch(1 0 0)",
- popoverForeground: "oklch(0.15 0.02 65)",
- primary: "oklch(0.25 0.03 45)",
- primaryForeground: "oklch(0.98 0.01 85)",
- secondary: "oklch(0.96 0.01 75)",
- secondaryForeground: "oklch(0.25 0.03 45)",
- muted: "oklch(0.96 0.01 75)",
- mutedForeground: "oklch(0.45 0.02 55)",
- accent: "oklch(0.96 0.01 75)",
- accentForeground: "oklch(0.25 0.03 45)",
- destructive: "oklch(0.577 0.245 27.325)",
- border: "oklch(0.90 0.01 65)",
- input: "oklch(0.90 0.01 65)",
- ring: "oklch(0.25 0.03 45)",
- chart1: "oklch(0.646 0.222 41.116)",
- chart2: "oklch(0.6 0.118 184.704)",
- chart3: "oklch(0.398 0.07 227.392)",
- chart4: "oklch(0.828 0.189 84.429)",
- chart5: "oklch(0.769 0.188 70.08)",
- sidebar: "oklch(0.97 0.01 80)",
- sidebarForeground: "oklch(0.15 0.02 65)",
- sidebarPrimary: "oklch(0.25 0.03 45)",
- sidebarPrimaryForeground: "oklch(0.98 0.01 85)",
- sidebarAccent: "oklch(0.94 0.01 75)",
- sidebarAccentForeground: "oklch(0.25 0.03 45)",
- sidebarBorder: "oklch(0.88 0.01 65)",
- sidebarRing: "oklch(0.25 0.03 45)",
- },
- },
- {
- id: "comfy-brown-dark",
- name: "Comfy Brown",
- description: "Warm brown theme for dark mode",
- mode: "dark",
- colors: {
- background: "oklch(0.15 0.03 65)",
- foreground: "oklch(0.95 0.01 85)",
- card: "oklch(0.20 0.03 55)",
- cardForeground: "oklch(0.95 0.01 85)",
- popover: "oklch(0.20 0.03 55)",
- popoverForeground: "oklch(0.95 0.01 85)",
- primary: "oklch(0.65 0.15 45)",
- primaryForeground: "oklch(0.95 0.01 85)",
- secondary: "oklch(0.25 0.04 50)",
- secondaryForeground: "oklch(0.95 0.01 85)",
- muted: "oklch(0.25 0.04 50)",
- mutedForeground: "oklch(0.70 0.02 65)",
- accent: "oklch(0.25 0.04 50)",
- accentForeground: "oklch(0.95 0.01 85)",
- destructive: "oklch(0.704 0.191 22.216)",
- border: "oklch(0.30 0.04 55)",
- input: "oklch(0.30 0.04 55)",
- ring: "oklch(0.65 0.15 45)",
- chart1: "oklch(0.65 0.15 45)",
- chart2: "oklch(0.55 0.12 85)",
- chart3: "oklch(0.75 0.18 25)",
- chart4: "oklch(0.60 0.14 105)",
- chart5: "oklch(0.70 0.16 65)",
- sidebar: "oklch(0.18 0.03 60)",
- sidebarForeground: "oklch(0.95 0.01 85)",
- sidebarPrimary: "oklch(0.65 0.15 45)",
- sidebarPrimaryForeground: "oklch(0.95 0.01 85)",
- sidebarAccent: "oklch(0.22 0.04 50)",
- sidebarAccentForeground: "oklch(0.95 0.01 85)",
- sidebarBorder: "oklch(0.28 0.04 55)",
- sidebarRing: "oklch(0.65 0.15 45)",
- },
- },
- {
- id: "midnight-dark",
- name: "Midnight",
- description: "Deep blue midnight theme",
- mode: "dark",
- colors: {
- background: "oklch(0.12 0.08 250)",
- foreground: "oklch(0.95 0.01 230)",
- card: "oklch(0.18 0.06 240)",
- cardForeground: "oklch(0.95 0.01 230)",
- popover: "oklch(0.18 0.06 240)",
- popoverForeground: "oklch(0.95 0.01 230)",
- primary: "oklch(0.60 0.20 240)",
- primaryForeground: "oklch(0.95 0.01 230)",
- secondary: "oklch(0.22 0.05 235)",
- secondaryForeground: "oklch(0.95 0.01 230)",
- muted: "oklch(0.22 0.05 235)",
- mutedForeground: "oklch(0.70 0.02 230)",
- accent: "oklch(0.22 0.05 235)",
- accentForeground: "oklch(0.95 0.01 230)",
- destructive: "oklch(0.704 0.191 22.216)",
- border: "oklch(0.25 0.05 235)",
- input: "oklch(0.25 0.05 235)",
- ring: "oklch(0.60 0.20 240)",
- chart1: "oklch(0.60 0.20 240)",
- chart2: "oklch(0.50 0.15 200)",
- chart3: "oklch(0.65 0.18 280)",
- chart4: "oklch(0.55 0.16 160)",
- chart5: "oklch(0.70 0.22 300)",
- sidebar: "oklch(0.15 0.07 245)",
- sidebarForeground: "oklch(0.95 0.01 230)",
- sidebarPrimary: "oklch(0.60 0.20 240)",
- sidebarPrimaryForeground: "oklch(0.95 0.01 230)",
- sidebarAccent: "oklch(0.20 0.05 235)",
- sidebarAccentForeground: "oklch(0.95 0.01 230)",
- sidebarBorder: "oklch(0.22 0.05 235)",
- sidebarRing: "oklch(0.60 0.20 240)",
- },
- },
-];
-
-type ThemeMode = "light" | "dark" | "system";
-
-type ThemeProviderProps = {
- children: React.ReactNode;
- defaultTheme?: ThemeMode;
- storageKey?: string;
-};
-
-type ThemeProviderState = {
- mode: ThemeMode;
- currentTheme: ThemeDefinition;
- currentLightTheme: ThemeDefinition;
- currentDarkTheme: ThemeDefinition;
- themes: ThemeDefinition[];
- setMode: (mode: ThemeMode) => void;
- setTheme: (themeId: string) => void;
- addCustomTheme: (theme: Omit) => void;
- removeCustomTheme: (themeId: string) => void;
- getThemesForMode: (mode: "light" | "dark") => ThemeDefinition[];
-};
-
-const initialState: ThemeProviderState = {
- mode: "system",
- currentTheme: DEFAULT_THEMES[1], // Default to dark theme
- currentLightTheme: DEFAULT_THEMES[0], // Default light
- currentDarkTheme: DEFAULT_THEMES[1], // Default dark
- themes: DEFAULT_THEMES,
- setMode: () => null,
- setTheme: () => null,
- addCustomTheme: () => null,
- removeCustomTheme: () => null,
- getThemesForMode: () => [],
-};
-
-const ThemeProviderContext = createContext(initialState);
-
-export function ThemeProvider({
- children,
- defaultTheme = "system",
- storageKey = "concord-theme",
- ...props
-}: ThemeProviderProps) {
- const [mode, setMode] = useState(
- () =>
- (localStorage.getItem(storageKey + "-mode") as ThemeMode) || defaultTheme,
- );
-
- const [themes, setThemes] = useState(() => {
- const saved = localStorage.getItem(storageKey + "-themes");
- const customThemes = saved ? JSON.parse(saved) : [];
- return [...DEFAULT_THEMES, ...customThemes];
- });
-
- const [currentLightThemeId, setCurrentLightThemeId] = useState(() => {
- const saved = localStorage.getItem(storageKey + "-light");
- return saved || "default-light";
- });
-
- const [currentDarkThemeId, setCurrentDarkThemeId] = useState(() => {
- const saved = localStorage.getItem(storageKey + "-dark");
- return saved || "default-dark";
- });
-
- const currentLightTheme =
- themes.find((t) => t.id === currentLightThemeId) || DEFAULT_THEMES[0];
- const currentDarkTheme =
- themes.find((t) => t.id === currentDarkThemeId) || DEFAULT_THEMES[2];
-
- // Determine the current theme based on mode and system preference
- const getCurrentTheme = (): ThemeDefinition => {
- switch (mode) {
- case "light":
- return currentLightTheme;
- case "dark":
- return currentDarkTheme;
- case "system":
- const systemPrefersDark = window.matchMedia(
- "(prefers-color-scheme: dark)",
- ).matches;
- return systemPrefersDark ? currentDarkTheme : currentLightTheme;
- default:
- return currentDarkTheme;
- }
- };
-
- const currentTheme = getCurrentTheme();
-
- const applyTheme = (theme: ThemeDefinition) => {
- const root = window.document.documentElement;
-
- // Remove existing theme classes
- root.classList.remove("light", "dark");
-
- // Apply mode class
- root.classList.add(theme.mode);
-
- // Apply CSS custom properties with proper mapping
- Object.entries(theme.colors).forEach(([key, value]) => {
- // Convert camelCase to kebab-case and map to CSS variables
- const cssVarMap: Record = {
- background: "--background",
- foreground: "--foreground",
- card: "--card",
- cardForeground: "--card-foreground",
- popover: "--popover",
- popoverForeground: "--popover-foreground",
- primary: "--primary",
- primaryForeground: "--primary-foreground",
- secondary: "--secondary",
- secondaryForeground: "--secondary-foreground",
- muted: "--muted",
- mutedForeground: "--muted-foreground",
- accent: "--accent",
- accentForeground: "--accent-foreground",
- destructive: "--destructive",
- border: "--border",
- input: "--input",
- ring: "--ring",
- chart1: "--chart-1",
- chart2: "--chart-2",
- chart3: "--chart-3",
- chart4: "--chart-4",
- chart5: "--chart-5",
- sidebar: "--sidebar",
- sidebarForeground: "--sidebar-foreground",
- sidebarPrimary: "--sidebar-primary",
- sidebarPrimaryForeground: "--sidebar-primary-foreground",
- sidebarAccent: "--sidebar-accent",
- sidebarAccentForeground: "--sidebar-accent-foreground",
- sidebarBorder: "--sidebar-border",
- sidebarRing: "--sidebar-ring",
- };
-
- const cssVar = cssVarMap[key];
- if (cssVar) {
- root.style.setProperty(cssVar, value);
- }
- });
- };
-
- useEffect(() => {
- applyTheme(currentTheme);
- }, [currentTheme]);
-
- useEffect(() => {
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
- const handleChange = () => {
- if (mode === "system") {
- // Theme will be recalculated due to getCurrentTheme dependency
- const newTheme = getCurrentTheme();
- applyTheme(newTheme);
- }
- };
-
- mediaQuery.addEventListener("change", handleChange);
- return () => mediaQuery.removeEventListener("change", handleChange);
- }, [mode, currentLightTheme, currentDarkTheme]);
-
- const setTheme = (themeId: string) => {
- const theme = themes.find((t) => t.id === themeId);
- if (!theme) return;
-
- // Update the appropriate theme based on the theme's mode
- if (theme.mode === "light") {
- setCurrentLightThemeId(themeId);
- localStorage.setItem(storageKey + "-light", themeId);
- } else {
- setCurrentDarkThemeId(themeId);
- localStorage.setItem(storageKey + "-dark", themeId);
- }
- };
-
- const handleSetMode = (newMode: ThemeMode) => {
- setMode(newMode);
- localStorage.setItem(storageKey + "-mode", newMode);
- };
-
- const addCustomTheme = (
- themeData: Omit,
- ) => {
- const newTheme: ThemeDefinition = {
- ...themeData,
- id: `custom-${Date.now()}`,
- isCustom: true,
- };
-
- const updatedThemes = [...themes, newTheme];
- setThemes(updatedThemes);
-
- // Save only custom themes to localStorage
- const customThemes = updatedThemes.filter((t) => t.isCustom);
- localStorage.setItem(storageKey + "-themes", JSON.stringify(customThemes));
- };
-
- const removeCustomTheme = (themeId: string) => {
- const updatedThemes = themes.filter((t) => t.id !== themeId);
- setThemes(updatedThemes);
-
- // If removing current theme, switch to default
- if (currentLightThemeId === themeId) {
- const defaultLight = updatedThemes.find(
- (t) => t.mode === "light" && !t.isCustom,
- );
- if (defaultLight) {
- setCurrentLightThemeId(defaultLight.id);
- localStorage.setItem(storageKey + "-light", defaultLight.id);
- }
- }
-
- if (currentDarkThemeId === themeId) {
- const defaultDark = updatedThemes.find(
- (t) => t.mode === "dark" && !t.isCustom,
- );
- if (defaultDark) {
- setCurrentDarkThemeId(defaultDark.id);
- localStorage.setItem(storageKey + "-dark", defaultDark.id);
- }
- }
-
- // Save only custom themes to localStorage
- const customThemes = updatedThemes.filter((t) => t.isCustom);
- localStorage.setItem(storageKey + "-themes", JSON.stringify(customThemes));
- };
-
- const getThemesForMode = (targetMode: "light" | "dark") => {
- return themes.filter((t) => t.mode === targetMode);
- };
-
- const value = {
- mode,
- currentTheme,
- currentLightTheme,
- currentDarkTheme,
- themes,
- setMode: handleSetMode,
- setTheme,
- addCustomTheme,
- removeCustomTheme,
- getThemesForMode,
- };
-
- return (
-
- {children}
-
- );
-}
-
-export const useTheme = () => {
- const context = useContext(ThemeProviderContext);
-
- if (context === undefined)
- throw new Error("useTheme must be used within a ThemeProvider");
-
- return context;
-};
diff --git a/concord-client/src/components/ui/alert.tsx b/concord-client/src/components/ui/alert.tsx
deleted file mode 100644
index 1421354..0000000
--- a/concord-client/src/components/ui/alert.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as React from "react"
-import { cva, type VariantProps } from "class-variance-authority"
-
-import { cn } from "@/lib/utils"
-
-const alertVariants = cva(
- "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
- {
- variants: {
- variant: {
- default: "bg-card text-card-foreground",
- destructive:
- "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
- },
- },
- defaultVariants: {
- variant: "default",
- },
- }
-)
-
-function Alert({
- className,
- variant,
- ...props
-}: React.ComponentProps<"div"> & VariantProps) {
- return (
-
- )
-}
-
-function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function AlertDescription({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-export { Alert, AlertTitle, AlertDescription }
diff --git a/concord-client/src/components/ui/avatar.tsx b/concord-client/src/components/ui/avatar.tsx
deleted file mode 100644
index b7224f0..0000000
--- a/concord-client/src/components/ui/avatar.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import * as React from "react"
-import * as AvatarPrimitive from "@radix-ui/react-avatar"
-
-import { cn } from "@/lib/utils"
-
-function Avatar({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AvatarImage({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AvatarFallback({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export { Avatar, AvatarImage, AvatarFallback }
diff --git a/concord-client/src/components/ui/badge.tsx b/concord-client/src/components/ui/badge.tsx
deleted file mode 100644
index 0205413..0000000
--- a/concord-client/src/components/ui/badge.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
-
-import { cn } from "@/lib/utils"
-
-const badgeVariants = cva(
- "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
- {
- variants: {
- variant: {
- default:
- "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
- secondary:
- "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
- destructive:
- "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
- outline:
- "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
- },
- },
- defaultVariants: {
- variant: "default",
- },
- }
-)
-
-function Badge({
- className,
- variant,
- asChild = false,
- ...props
-}: React.ComponentProps<"span"> &
- VariantProps & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "span"
-
- return (
-
- )
-}
-
-export { Badge, badgeVariants }
diff --git a/concord-client/src/components/ui/button.tsx b/concord-client/src/components/ui/button.tsx
deleted file mode 100644
index d96719c..0000000
--- a/concord-client/src/components/ui/button.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
-
-import { cn } from "@/lib/utils"
-
-const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
- {
- variants: {
- variant: {
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
- destructive:
- "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
- outline:
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
- secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
- ghost:
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
- link: "text-primary underline-offset-4 hover:underline",
- },
- size: {
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
- icon: "size-9",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- }
-)
-
-function Button({
- className,
- variant,
- size,
- asChild = false,
- ...props
-}: React.ComponentProps<"button"> &
- VariantProps & {
- asChild?: boolean
- }) {
- const Comp = asChild ? Slot : "button"
-
- return (
-
- )
-}
-
-export { Button, buttonVariants }
diff --git a/concord-client/src/components/ui/card.tsx b/concord-client/src/components/ui/card.tsx
deleted file mode 100644
index d05bbc6..0000000
--- a/concord-client/src/components/ui/card.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import * as React from "react"
-
-import { cn } from "@/lib/utils"
-
-function Card({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardAction({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-export {
- Card,
- CardHeader,
- CardFooter,
- CardTitle,
- CardAction,
- CardDescription,
- CardContent,
-}
diff --git a/concord-client/src/components/ui/dialog.tsx b/concord-client/src/components/ui/dialog.tsx
deleted file mode 100644
index 6cb123b..0000000
--- a/concord-client/src/components/ui/dialog.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import * as React from "react"
-import * as DialogPrimitive from "@radix-ui/react-dialog"
-import { XIcon } from "lucide-react"
-
-import { cn } from "@/lib/utils"
-
-function Dialog({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DialogTrigger({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DialogPortal({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DialogClose({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DialogOverlay({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DialogContent({
- className,
- children,
- showCloseButton = true,
- ...props
-}: React.ComponentProps & {
- showCloseButton?: boolean
-}) {
- return (
-
-
-
- {children}
- {showCloseButton && (
-
-
- Close
-
- )}
-
-
- )
-}
-
-function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- )
-}
-
-function DialogTitle({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DialogDescription({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- Dialog,
- DialogClose,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogOverlay,
- DialogPortal,
- DialogTitle,
- DialogTrigger,
-}
diff --git a/concord-client/src/components/ui/dropdown-menu.tsx b/concord-client/src/components/ui/dropdown-menu.tsx
deleted file mode 100644
index eaed9ba..0000000
--- a/concord-client/src/components/ui/dropdown-menu.tsx
+++ /dev/null
@@ -1,255 +0,0 @@
-import * as React from "react"
-import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
-import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
-
-import { cn } from "@/lib/utils"
-
-function DropdownMenu({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DropdownMenuPortal({
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DropdownMenuTrigger({
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DropdownMenuContent({
- className,
- sideOffset = 4,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-function DropdownMenuGroup({
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DropdownMenuItem({
- className,
- inset,
- variant = "default",
- ...props
-}: React.ComponentProps & {
- inset?: boolean
- variant?: "default" | "destructive"
-}) {
- return (
-
- )
-}
-
-function DropdownMenuCheckboxItem({
- className,
- children,
- checked,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- )
-}
-
-function DropdownMenuRadioGroup({
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DropdownMenuRadioItem({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- )
-}
-
-function DropdownMenuLabel({
- className,
- inset,
- ...props
-}: React.ComponentProps & {
- inset?: boolean
-}) {
- return (
-
- )
-}
-
-function DropdownMenuSeparator({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function DropdownMenuShortcut({
- className,
- ...props
-}: React.ComponentProps<"span">) {
- return (
-
- )
-}
-
-function DropdownMenuSub({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function DropdownMenuSubTrigger({
- className,
- inset,
- children,
- ...props
-}: React.ComponentProps & {
- inset?: boolean
-}) {
- return (
-
- {children}
-
-
- )
-}
-
-function DropdownMenuSubContent({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- DropdownMenu,
- DropdownMenuPortal,
- DropdownMenuTrigger,
- DropdownMenuContent,
- DropdownMenuGroup,
- DropdownMenuLabel,
- DropdownMenuItem,
- DropdownMenuCheckboxItem,
- DropdownMenuRadioGroup,
- DropdownMenuRadioItem,
- DropdownMenuSeparator,
- DropdownMenuShortcut,
- DropdownMenuSub,
- DropdownMenuSubTrigger,
- DropdownMenuSubContent,
-}
diff --git a/concord-client/src/components/ui/input.tsx b/concord-client/src/components/ui/input.tsx
deleted file mode 100644
index 8916905..0000000
--- a/concord-client/src/components/ui/input.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as React from "react"
-
-import { cn } from "@/lib/utils"
-
-function Input({ className, type, ...props }: React.ComponentProps<"input">) {
- return (
-
- )
-}
-
-export { Input }
diff --git a/concord-client/src/components/ui/label.tsx b/concord-client/src/components/ui/label.tsx
deleted file mode 100644
index ef7133a..0000000
--- a/concord-client/src/components/ui/label.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-
-import { cn } from "@/lib/utils"
-
-function Label({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export { Label }
diff --git a/concord-client/src/components/ui/scroll-area.tsx b/concord-client/src/components/ui/scroll-area.tsx
deleted file mode 100644
index 9376f59..0000000
--- a/concord-client/src/components/ui/scroll-area.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import * as React from "react"
-import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
-
-import { cn } from "@/lib/utils"
-
-function ScrollArea({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
- {children}
-
-
-
-
- )
-}
-
-function ScrollBar({
- className,
- orientation = "vertical",
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-export { ScrollArea, ScrollBar }
diff --git a/concord-client/src/components/ui/select.tsx b/concord-client/src/components/ui/select.tsx
deleted file mode 100644
index 51f466e..0000000
--- a/concord-client/src/components/ui/select.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-import * as React from "react"
-import * as SelectPrimitive from "@radix-ui/react-select"
-import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
-
-import { cn } from "@/lib/utils"
-
-function Select({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function SelectGroup({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function SelectValue({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function SelectTrigger({
- className,
- size = "default",
- children,
- ...props
-}: React.ComponentProps & {
- size?: "sm" | "default"
-}) {
- return (
-
- {children}
-
-
-
-
- )
-}
-
-function SelectContent({
- className,
- children,
- position = "popper",
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
- {children}
-
-
-
-
- )
-}
-
-function SelectLabel({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function SelectItem({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- )
-}
-
-function SelectSeparator({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function SelectScrollUpButton({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-function SelectScrollDownButton({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-export {
- Select,
- SelectContent,
- SelectGroup,
- SelectItem,
- SelectLabel,
- SelectScrollDownButton,
- SelectScrollUpButton,
- SelectSeparator,
- SelectTrigger,
- SelectValue,
-}
diff --git a/concord-client/src/components/ui/separator.tsx b/concord-client/src/components/ui/separator.tsx
deleted file mode 100644
index 275381c..0000000
--- a/concord-client/src/components/ui/separator.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-"use client"
-
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
-
-import { cn } from "@/lib/utils"
-
-function Separator({
- className,
- orientation = "horizontal",
- decorative = true,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export { Separator }
diff --git a/concord-client/src/components/ui/slider.tsx b/concord-client/src/components/ui/slider.tsx
deleted file mode 100644
index 1bb40c6..0000000
--- a/concord-client/src/components/ui/slider.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import * as React from "react"
-import * as SliderPrimitive from "@radix-ui/react-slider"
-
-import { cn } from "@/lib/utils"
-
-function Slider({
- className,
- defaultValue,
- value,
- min = 0,
- max = 100,
- ...props
-}: React.ComponentProps) {
- const _values = React.useMemo(
- () =>
- Array.isArray(value)
- ? value
- : Array.isArray(defaultValue)
- ? defaultValue
- : [min, max],
- [value, defaultValue, min, max]
- )
-
- return (
-
-
-
-
- {Array.from({ length: _values.length }, (_, index) => (
-
- ))}
-
- )
-}
-
-export { Slider }
diff --git a/concord-client/src/components/ui/sonner.tsx b/concord-client/src/components/ui/sonner.tsx
deleted file mode 100644
index cd62aff..0000000
--- a/concord-client/src/components/ui/sonner.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { useTheme } from "next-themes"
-import { Toaster as Sonner, ToasterProps } from "sonner"
-
-const Toaster = ({ ...props }: ToasterProps) => {
- const { theme = "system" } = useTheme()
-
- return (
-
- )
-}
-
-export { Toaster }
diff --git a/concord-client/src/components/ui/switch.tsx b/concord-client/src/components/ui/switch.tsx
deleted file mode 100644
index b0363e3..0000000
--- a/concord-client/src/components/ui/switch.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as React from "react"
-import * as SwitchPrimitive from "@radix-ui/react-switch"
-
-import { cn } from "@/lib/utils"
-
-function Switch({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-export { Switch }
diff --git a/concord-client/src/components/ui/textarea.tsx b/concord-client/src/components/ui/textarea.tsx
deleted file mode 100644
index 7f21b5e..0000000
--- a/concord-client/src/components/ui/textarea.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import * as React from "react"
-
-import { cn } from "@/lib/utils"
-
-function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
- return (
-
- )
-}
-
-export { Textarea }
diff --git a/concord-client/src/components/ui/tooltip.tsx b/concord-client/src/components/ui/tooltip.tsx
deleted file mode 100644
index 715bf76..0000000
--- a/concord-client/src/components/ui/tooltip.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import * as React from "react"
-import * as TooltipPrimitive from "@radix-ui/react-tooltip"
-
-import { cn } from "@/lib/utils"
-
-function TooltipProvider({
- delayDuration = 0,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function Tooltip({
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- )
-}
-
-function TooltipTrigger({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function TooltipContent({
- className,
- sideOffset = 0,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
- {children}
-
-
-
- )
-}
-
-export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
diff --git a/concord-client/src/components/voice/VoiceConnectionManager.tsx b/concord-client/src/components/voice/VoiceConnectionManager.tsx
deleted file mode 100644
index 450e7b3..0000000
--- a/concord-client/src/components/voice/VoiceConnectionManager.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import React, { useEffect, useRef } from "react";
-import { useVoiceStore } from "@/stores/voiceStore";
-
-interface AudioPlayerProps {
- stream: MediaStream;
- isDeafened: boolean;
-}
-
-const AudioPlayer: React.FC = ({ stream, isDeafened }) => {
- const audioRef = useRef(null);
-
- useEffect(() => {
- if (audioRef.current) {
- audioRef.current.srcObject = stream;
- audioRef.current.volume = isDeafened ? 0 : 1;
- }
- }, [stream, isDeafened]);
-
- return ;
-};
-
-const VoiceConnectionManager: React.FC = () => {
- const remoteStreams = useVoiceStore((state) => state.remoteStreams);
- const isDeafened = useVoiceStore((state) => state.isDeafened);
-
- if (remoteStreams.size === 0) {
- return null;
- }
-
- return (
-
- {Array.from(remoteStreams.entries()).map(([userId, stream]) => (
-
- ))}
-
- );
-};
-
-export default VoiceConnectionManager;
diff --git a/concord-client/src/hooks/useAuth.ts b/concord-client/src/hooks/useAuth.ts
deleted file mode 100644
index 0f1d9d3..0000000
--- a/concord-client/src/hooks/useAuth.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useAuthStore } from "@/stores/authStore";
-import {
- authClient,
- LoginCredentials,
- RegisterData,
- AuthResponse,
-} from "@/lib/auth-client";
-import { BackendUser } from "@/lib/api-client";
-import { Role, UserStatus } from "@/types/database";
-
-// Frontend User type
-interface FrontendUser {
- id: string;
- username: string;
- nickname?: string | null;
- bio?: string | null;
- picture?: string | null;
- banner?: string | null;
- hashPassword: string;
- admin: boolean;
- status: UserStatus;
- createdAt: string;
- updatedAt: string;
- roles: Role[];
-}
-
-// Transform backend user to frontend user format
-function transformBackendUser(backendUser: BackendUser): FrontendUser {
- return {
- id: backendUser.id,
- username: backendUser.userName,
- nickname: backendUser.nickName,
- bio: backendUser.bio,
- picture: backendUser.picture,
- banner: backendUser.banner,
- hashPassword: "", // Don't store password
- admin: backendUser.admin,
- status: transformStatusToFrontend(backendUser.status),
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- roles: backendUser.role.map((r) => ({
- instanceId: r.instanceId || "",
- role: r.role || "member",
- })) as Role[],
- };
-}
-
-// Transform status from backend to frontend format
-function transformStatusToFrontend(
- backendStatus: "online" | "offline" | "dnd" | "idle" | "invis",
-): UserStatus {
- switch (backendStatus) {
- case "dnd":
- return "busy";
- case "idle":
- return "away";
- case "invis":
- return "offline";
- default:
- return "online";
- }
-}
-
-// Transform status from frontend to backend format
-export function transformStatusToBackend(
- frontendStatus: UserStatus,
-): "online" | "offline" | "dnd" | "idle" | "invis" {
- switch (frontendStatus) {
- case "busy":
- return "dnd";
- case "away":
- return "idle";
- case "offline":
- return "invis";
- default:
- return "online";
- }
-}
-
-// Hook for login
-export const useLogin = () => {
- const { setAuth, setLoading } = useAuthStore();
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: async (
- credentials: LoginCredentials,
- ): Promise => {
- setLoading(true);
- return authClient.login(credentials);
- },
- onSuccess: (data: AuthResponse) => {
- const frontendUser = transformBackendUser(data.user);
- setAuth(frontendUser, data.token, data.token); // Use token as refresh token for now
- queryClient.clear();
- },
- onError: (error: Error) => {
- console.error("Login failed:", error);
- setLoading(false);
- },
- onSettled: () => {
- setLoading(false);
- },
- });
-};
-
-// Hook for registration (requires admin)
-export const useRegister = () => {
- const { setAuth, setLoading, user, token } = useAuthStore();
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: async (userData: RegisterData): Promise => {
- setLoading(true);
-
- if (!user || !token || !user.admin) {
- throw new Error("Admin privileges required for user creation");
- }
-
- return authClient.register(userData, { id: user.id, token });
- },
- onSuccess: (data: AuthResponse) => {
- const frontendUser = transformBackendUser(data.user);
- setAuth(frontendUser, data.token, data.token);
- queryClient.clear();
- },
- onError: (error: Error) => {
- console.error("Registration failed:", error);
- setLoading(false);
- },
- onSettled: () => {
- setLoading(false);
- },
- });
-};
-
-// Hook for logout
-export const useLogout = () => {
- const { logout, user } = useAuthStore();
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: async (): Promise => {
- if (user) {
- try {
- await authClient.logout(user.id);
- } catch (error) {
- console.warn("Logout endpoint failed:", error);
- }
- }
- },
- onSuccess: () => {
- logout();
- queryClient.clear();
- },
- onError: (error: Error) => {
- console.error("Logout failed:", error);
- // Still logout locally even if server request fails
- logout();
- queryClient.clear();
- },
- });
-};
-
-// Hook for token validation
-export const useValidateToken = () => {
- const { token, user, setAuth, logout } = useAuthStore();
-
- return useMutation({
- mutationFn: async (): Promise<{ valid: boolean; user?: BackendUser }> => {
- if (!token || !user) {
- throw new Error("No token to validate");
- }
- return authClient.validateToken(token, user.id);
- },
- onSuccess: (data) => {
- if (!data.valid) {
- logout();
- } else if (data.user) {
- const frontendUser = transformBackendUser(data.user);
- setAuth(frontendUser, token!, useAuthStore.getState().refreshToken!);
- }
- },
- onError: (error: Error) => {
- console.error("Token validation failed:", error);
- logout();
- },
- });
-};
-
-// Hook for token refresh
-export const useRefreshToken = () => {
- const { refreshToken, user, setAuth, logout } = useAuthStore();
-
- return useMutation({
- mutationFn: async (): Promise => {
- if (!refreshToken || !user) {
- throw new Error("No refresh token available");
- }
- return authClient.refreshToken(refreshToken, user.id);
- },
- onSuccess: (data: AuthResponse) => {
- const frontendUser = transformBackendUser(data.user);
- setAuth(frontendUser, data.token, data.token);
- },
- onError: (error: Error) => {
- console.error("Token refresh failed:", error);
- logout();
- },
- });
-};
diff --git a/concord-client/src/hooks/useMessages.ts b/concord-client/src/hooks/useMessages.ts
deleted file mode 100644
index 94c8bfd..0000000
--- a/concord-client/src/hooks/useMessages.ts
+++ /dev/null
@@ -1,303 +0,0 @@
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { apiClient, Message } from "@/lib/api-client";
-import { useAuthStore } from "@/stores/authStore";
-
-// Hook for getting messages in a channel with pagination
-export const useChannelMessages = (channelId?: string, limit = 50) => {
- return useQuery({
- queryKey: ["messages", channelId, limit],
- queryFn: async (): Promise => {
- if (!channelId) return [];
-
- try {
- const date = new Date();
- const messages = await apiClient.getMessages({
- date: date.toISOString(),
- channelId: channelId,
- });
-
- return messages || [];
- } catch (error) {
- console.error("Failed to fetch messages:", error);
- return [];
- }
- },
- enabled: !!channelId,
- staleTime: 500 * 1,
- refetchInterval: 500 * 1,
- });
-};
-
-// Hook for getting older messages (pagination)
-export const useChannelMessagesPaginated = (
- channelId?: string,
- beforeDate?: Date,
- limit = 50,
-) => {
- return useQuery({
- queryKey: [
- "messages",
- channelId,
- "paginated",
- beforeDate?.toISOString(),
- limit,
- ],
- queryFn: async (): Promise => {
- if (!channelId || !beforeDate) return [];
-
- try {
- const messages = await apiClient.getMessages({
- date: beforeDate.toISOString(),
- channelId: channelId,
- });
-
- return messages || [];
- } catch (error) {
- console.error("Failed to fetch paginated messages:", error);
- return [];
- }
- },
- enabled: !!channelId && !!beforeDate,
- staleTime: 500 * 1,
- });
-};
-
-// Hook for sending messages
-export const useSendMessage = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: {
- channelId: string;
- content: string;
- repliedMessageId?: string | null;
- }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- const requestData = {
- channelId: data.channelId,
- userId: user.id,
- content: data.content,
- token: token,
- repliedMessageId: data.repliedMessageId,
- };
-
- try {
- const message = await apiClient.sendMessage(requestData);
- return message;
- } catch (error) {
- console.error("Failed to send message:", error);
- throw new Error("Failed to send message");
- }
- },
- onSuccess: (_, variables) => {
- queryClient.invalidateQueries({
- queryKey: ["messages", variables.channelId],
- });
- },
- onError: (error) => {
- console.error("Send message failed:", error);
- },
- });
-};
-
-// Hook for deleting messages
-export const useDeleteMessage = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: { messageId: string; channelId: string }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- // TODO: Replace with actual API call when available
-
- return { success: true, messageId: data.messageId };
- },
- onSuccess: (result, variables) => {
- // Update the cache to mark message as deleted
- queryClient.setQueryData(
- ["messages", variables.channelId],
- (oldData: Message[] | undefined) => {
- if (!oldData) return oldData;
-
- return oldData.map((msg) =>
- msg.id === result.messageId
- ? { ...msg, content: "[Message deleted]", deleted: true }
- : msg,
- );
- },
- );
- },
- onError: (error) => {
- console.error("Delete message failed:", error);
- },
- });
-};
-
-// Hook for editing messages
-export const useEditMessage = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: {
- messageId: string;
- content: string;
- channelId: string;
- }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- // TODO: Replace with actual API call when available
-
- return {
- success: true,
- messageId: data.messageId,
- content: data.content,
- edited: true,
- };
- },
- onSuccess: (result, variables) => {
- // Update the cache with edited message
- queryClient.setQueryData(
- ["messages", variables.channelId],
- (oldData: Message[] | undefined) => {
- if (!oldData) return oldData;
-
- return oldData.map((msg) =>
- msg.id === result.messageId
- ? { ...msg, content: result.content, edited: result.edited }
- : msg,
- );
- },
- );
- },
- onError: (error) => {
- console.error("Edit message failed:", error);
- },
- });
-};
-
-// Hook for pinning/unpinning messages
-export const usePinMessage = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: {
- messageId: string;
- channelId: string;
- pinned: boolean;
- }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- // TODO: Replace with actual API call when available
-
- return {
- success: true,
- messageId: data.messageId,
- pinned: data.pinned,
- };
- },
- onSuccess: (result, variables) => {
- // Update the cache with pinned status
- queryClient.setQueryData(
- ["messages", variables.channelId],
- (oldData: Message[] | undefined) => {
- if (!oldData) return oldData;
-
- return oldData.map((msg) =>
- msg.id === result.messageId
- ? { ...msg, pinned: result.pinned }
- : msg,
- );
- },
- );
-
- // Also invalidate pinned messages query if it exists
- queryClient.invalidateQueries({
- queryKey: ["pinned-messages", variables.channelId],
- });
- },
- onError: (error) => {
- console.error("Pin message failed:", error);
- },
- });
-};
-
-// Hook for getting pinned messages
-export const usePinnedMessages = (channelId?: string) => {
- return useQuery({
- queryKey: ["pinned-messages", channelId],
- queryFn: async (): Promise => {
- if (!channelId) return [];
-
- try {
- // TODO: Replace with actual API call when available
- // For now, return empty array
- return [];
- } catch (error) {
- console.error("Failed to fetch pinned messages:", error);
- return [];
- }
- },
- enabled: !!channelId,
- staleTime: 500 * 1,
- });
-};
-
-// Hook for loading more messages (infinite scroll)
-export const useLoadMoreMessages = (channelId?: string) => {
- const queryClient = useQueryClient();
-
- return useMutation({
- mutationFn: async (data: { beforeDate: Date }) => {
- if (!channelId) return [];
-
- try {
- const messages = await apiClient.getMessages({
- date: data.beforeDate.toISOString(),
- channelId: channelId,
- });
-
- return messages || [];
- } catch (error) {
- console.error("Failed to load more messages:", error);
- return [];
- }
- },
- onSuccess: (newMessages) => {
- if (newMessages.length > 0) {
- // Prepend new messages to existing messages
- queryClient.setQueryData(
- ["messages", channelId],
- (oldData: Message[] | undefined) => {
- if (!oldData) return newMessages;
-
- // Remove duplicates and sort by creation date
- const combined = [...newMessages, ...oldData];
- const unique = combined.filter(
- (msg, index, arr) =>
- arr.findIndex((m) => m.id === msg.id) === index,
- );
-
- return unique.sort(
- (a, b) =>
- new Date(a.createdAt).getTime() -
- new Date(b.createdAt).getTime(),
- );
- },
- );
- }
- },
- });
-};
diff --git a/concord-client/src/hooks/usePermissions.ts b/concord-client/src/hooks/usePermissions.ts
deleted file mode 100644
index 6415f3d..0000000
--- a/concord-client/src/hooks/usePermissions.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-import { useAuthStore } from "@/stores/authStore";
-import { Role } from "@/types/database";
-import { useMemo } from "react";
-import { useParams } from "react-router";
-
-type PermissionsRole = "admin" | "member" | "mod";
-
-const getUserRoleForInstance = (
- roles: Role[],
- instanceId: string,
-): PermissionsRole => {
- if (!instanceId) return "member";
- const roleEntry = roles.find((r) => r.instanceId === instanceId);
- return roleEntry?.role || "member";
-};
-
-const getRoleInfo = (role: PermissionsRole) => {
- const lowerRole = role.toLowerCase();
- switch (lowerRole) {
- case "admin":
- return { color: "#ff6b6b", priority: 3, name: "Admin" };
- case "mod":
- return { color: "#4ecdc4", priority: 2, name: "Moderator" };
- case "member":
- return { color: null, priority: 1, name: "Member" };
- default:
- return {
- color: null,
- priority: 0,
- name: role.charAt(0).toUpperCase() + role.slice(1),
- };
- }
-};
-
-interface InstancePermissions {
- currentUserRole: PermissionsRole;
- currentUserRolePriority: number;
- canManageMembers: boolean; // Can kick/ban/promote/demote members
- canViewAdminPanel: boolean;
-}
-
-export const useInstancePermissions = (): InstancePermissions => {
- const { instanceId } = useParams<{ instanceId: string }>();
- const { user: currentUser } = useAuthStore();
-
- const permissions = useMemo(() => {
- let currentUserRole: PermissionsRole = "member";
- let currentUserRolePriority = 1;
- let canManageMembers = false;
- let canViewAdminPanel = false;
-
- if (!currentUser || !instanceId) {
- // If no user or instance, user has no permissions within an instance
- return {
- currentUserRole,
- currentUserRolePriority,
- canManageMembers,
- canViewAdminPanel,
- };
- }
-
- // If they are a global admin
- if (currentUser.admin) {
- currentUserRole = "admin";
- currentUserRolePriority = 3;
- canManageMembers = true;
- canViewAdminPanel = true;
- return {
- currentUserRole: "admin",
- currentUserRolePriority: 3,
- canManageMembers: true,
- canManageRoles: true,
- canViewAdminPanel: true,
- };
- }
-
- // Instance-Specific Role Check
- const instanceRole = getUserRoleForInstance(currentUser.roles, instanceId);
- const roleInfo = getRoleInfo(instanceRole as PermissionsRole);
-
- currentUserRole = instanceRole;
- currentUserRolePriority = roleInfo.priority;
-
- // Define permissions based on role priority
- if (roleInfo.priority >= 3) {
- // Admin
- canManageMembers = true;
- canViewAdminPanel = true;
- } else if (roleInfo.priority === 2) {
- // Moderator
- canManageMembers = true;
- canViewAdminPanel = false;
- } else {
- // Member (priority 1 or 0)
- canManageMembers = false;
- canViewAdminPanel = false;
- }
-
- return {
- currentUserRole,
- currentUserRolePriority,
- canManageMembers,
- canViewAdminPanel,
- };
- }, [currentUser, instanceId]);
-
- return permissions as InstancePermissions;
-};
diff --git a/concord-client/src/hooks/useServers.ts b/concord-client/src/hooks/useServers.ts
deleted file mode 100644
index e9b446b..0000000
--- a/concord-client/src/hooks/useServers.ts
+++ /dev/null
@@ -1,269 +0,0 @@
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import {
- apiClient,
- Instance,
- Category,
- Channel,
- BackendUser,
-} from "@/lib/api-client";
-import { useAuthStore } from "@/stores/authStore";
-
-// Extended types with relations for frontend use
-export interface CategoryWithChannels extends Category {
- channels: Channel[];
-}
-
-export interface InstanceWithDetails extends Instance {
- categories: CategoryWithChannels[];
-}
-
-// Transform backend user to frontend user format for compatibility
-function transformBackendUserToFrontend(backendUser: BackendUser) {
- return {
- id: backendUser.id,
- username: backendUser.userName,
- nickname: backendUser.nickName,
- bio: backendUser.bio,
- picture: backendUser.picture,
- banner: backendUser.banner,
- hashPassword: "",
- admin: backendUser.admin,
- status:
- backendUser.status === "dnd"
- ? "busy"
- : backendUser.status === "idle"
- ? "away"
- : backendUser.status === "invis"
- ? "offline"
- : backendUser.status,
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- roles: backendUser.role.map((r) => ({
- instanceId: r.instanceId || "",
- role: r.role || "member",
- })),
- };
-}
-
-// Hook for getting all servers/instances
-export const useServers = () => {
- return useQuery({
- queryKey: ["servers"],
- queryFn: async (): Promise => {
- try {
- const instances = await apiClient.getInstances();
- return instances;
- } catch (error) {
- console.error("Failed to fetch servers:", error);
- throw new Error("Failed to fetch servers");
- }
- },
- staleTime: 500 * 1,
- });
-};
-
-// Hook for getting detailed instance info with categories and channels
-export const useInstanceDetails = (instanceId?: string) => {
- return useQuery({
- queryKey: ["instance", instanceId],
- queryFn: async (): Promise => {
- if (!instanceId) return null;
-
- try {
- // Get instance basic info
- const instances = await apiClient.getInstances();
- const instance = instances.find((s) => s.id === instanceId);
- if (!instance) return null;
-
- // Get categories for this instance
- const categories = await apiClient.getCategoriesByInstance(instanceId);
-
- // For each category, get its channels
- const categoriesWithChannels: CategoryWithChannels[] =
- await Promise.all(
- categories.map(async (category): Promise => {
- try {
- const channels = await apiClient.getChannelsByCategory(
- category.id,
- );
- return {
- ...category,
- channels: channels || [],
- };
- } catch (error) {
- console.warn(
- `Failed to fetch channels for category ${category.id}:`,
- error,
- );
- return {
- ...category,
- channels: [],
- };
- }
- }),
- );
-
- return {
- ...instance,
- categories: categoriesWithChannels,
- };
- } catch (error) {
- console.error("Failed to fetch instance details:", error);
- throw new Error("Failed to fetch instance details");
- }
- },
- enabled: !!instanceId,
- staleTime: 500 * 1,
- });
-};
-
-// Hook for getting all users from an instance with their roles
-export const useInstanceMembers = (instanceId?: string) => {
- return useQuery({
- queryKey: ["instance", instanceId, "members"],
- queryFn: async () => {
- if (!instanceId) return [];
-
- try {
- const backendUsers = await apiClient.getUsersByInstance(instanceId);
- // Transform backend users to frontend format for compatibility
- return backendUsers.map(transformBackendUserToFrontend);
- } catch (error) {
- console.error("Failed to fetch instance members:", error);
- throw new Error("Failed to fetch instance members");
- }
- },
- enabled: !!instanceId,
- staleTime: 500 * 1,
- });
-};
-
-// Hook for creating a new server/instance
-export const useCreateInstance = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: { name: string; icon?: string }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- const requestData = {
- ...data,
- requestingUserId: user.id,
- requestingUserToken: token,
- };
-
- try {
- const instance = await apiClient.createInstance(requestData);
- return instance;
- } catch (error) {
- console.error("Failed to create instance:", error);
- throw new Error("Failed to create instance");
- }
- },
- onSuccess: () => {
- // Invalidate servers list to refetch
- queryClient.invalidateQueries({ queryKey: ["servers"] });
- },
- });
-};
-
-// Hook for creating a new category
-export const useCreateCategory = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: {
- name: string;
- instanceId?: string;
- position: number;
- }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- const requestData = {
- ...data,
- admin: user.admin,
- requestingUserId: user.id,
- requestingUserToken: token,
- };
-
- try {
- const category = await apiClient.createCategory(requestData);
- return category;
- } catch (error) {
- console.error("Failed to create category:", error);
- throw new Error("Failed to create category");
- }
- },
- onSuccess: (_, variables) => {
- // Invalidate instance details to refetch categories
- if (variables.instanceId) {
- queryClient.invalidateQueries({
- queryKey: ["instance", variables.instanceId],
- });
- }
- },
- });
-};
-
-// Hook for creating a new channel
-export const useCreateChannel = () => {
- const queryClient = useQueryClient();
- const { user, token } = useAuthStore();
-
- return useMutation({
- mutationFn: async (data: {
- type: "text" | "voice";
- name: string;
- description: string;
- categoryId?: string;
- }) => {
- if (!user || !token) {
- throw new Error("Authentication required");
- }
-
- const requestData = {
- ...data,
- admin: user.admin,
- requestingUserId: user.id,
- requestingUserToken: token,
- };
-
- try {
- const channel = await apiClient.createChannel(requestData);
- return channel;
- } catch (error) {
- console.error("Failed to create channel:", error);
- throw new Error("Failed to create channel");
- }
- },
- onSuccess: (_, variables) => {
- // Invalidate related queries
- if (variables.categoryId) {
- // Find the instance this category belongs to and invalidate it
- queryClient.invalidateQueries({
- queryKey: ["instance"],
- });
- }
- },
- });
-};
-
-// Placeholder hook for channels by instance (for backward compatibility)
-export const useChannels = (instanceId?: string) => {
- const { data: instance } = useInstanceDetails(instanceId);
-
- return useQuery({
- queryKey: ["channels", instanceId],
- queryFn: async (): Promise => {
- return instance?.categories || [];
- },
- enabled: !!instanceId && !!instance,
- staleTime: 500 * 1,
- });
-};
diff --git a/concord-client/src/index.css b/concord-client/src/index.css
deleted file mode 100644
index 15771f4..0000000
--- a/concord-client/src/index.css
+++ /dev/null
@@ -1,307 +0,0 @@
-@import "tailwindcss";
-@import "tw-animate-css";
-
-@custom-variant dark (&:is(.dark *));
-
-@theme inline {
- --radius-sm: calc(var(--radius) - 4px);
- --radius-md: calc(var(--radius) - 2px);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) + 4px);
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --color-card: var(--card);
- --color-card-foreground: var(--card-foreground);
- --color-popover: var(--popover);
- --color-popover-foreground: var(--popover-foreground);
- --color-primary: var(--primary);
- --color-primary-foreground: var(--primary-foreground);
- --color-secondary: var(--secondary);
- --color-secondary-foreground: var(--secondary-foreground);
- --color-muted: var(--muted);
- --color-muted-foreground: var(--muted-foreground);
- --color-accent: var(--accent);
- --color-accent-foreground: var(--accent-foreground);
- --color-destructive: var(--destructive);
- --color-border: var(--border);
- --color-input: var(--input);
- --color-ring: var(--ring);
- --color-chart-1: var(--chart-1);
- --color-chart-2: var(--chart-2);
- --color-chart-3: var(--chart-3);
- --color-chart-4: var(--chart-4);
- --color-chart-5: var(--chart-5);
- --color-sidebar: var(--sidebar);
- --color-sidebar-foreground: var(--sidebar-foreground);
- --color-sidebar-primary: var(--sidebar-primary);
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
- --color-sidebar-accent: var(--sidebar-accent);
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
- --color-sidebar-border: var(--sidebar-border);
- --color-sidebar-ring: var(--sidebar-ring);
-
- /* concord-specific custom properties */
- --color-text-primary: var(--foreground);
- --color-text-secondary: var(--muted-foreground);
- --color-text-muted: var(--muted-foreground);
- --color-interactive-normal: var(--muted-foreground);
- --color-interactive-hover: var(--foreground);
- --color-interactive-active: var(--primary);
- --color-background-primary: var(--background);
- --color-background-secondary: var(--card);
- --color-background-tertiary: var(--muted);
-
- /* Status colors - these remain consistent across themes */
- --color-status-online: oklch(0.6 0.15 140);
- --color-status-away: oklch(0.75 0.15 85);
- --color-status-busy: oklch(0.65 0.2 25);
- --color-status-offline: var(--muted-foreground);
-}
-
-:root {
- --radius: 0.625rem;
- --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.205 0 0);
- --primary-foreground: oklch(0.985 0 0);
- --secondary: oklch(0.97 0 0);
- --secondary-foreground: oklch(0.205 0 0);
- --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.646 0.222 41.116);
- --chart-2: oklch(0.6 0.118 184.704);
- --chart-3: oklch(0.398 0.07 227.392);
- --chart-4: oklch(0.828 0.189 84.429);
- --chart-5: oklch(0.769 0.188 70.08);
- --sidebar: oklch(0.985 0 0);
- --sidebar-foreground: oklch(0.145 0 0);
- --sidebar-primary: oklch(0.205 0 0);
- --sidebar-primary-foreground: oklch(0.985 0 0);
- --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.922 0 0);
- --primary-foreground: oklch(0.205 0 0);
- --secondary: oklch(0.269 0 0);
- --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.488 0.243 264.376);
- --chart-2: oklch(0.696 0.17 162.48);
- --chart-3: oklch(0.769 0.188 70.08);
- --chart-4: oklch(0.627 0.265 303.9);
- --chart-5: oklch(0.645 0.246 16.439);
- --sidebar: oklch(0.205 0 0);
- --sidebar-foreground: oklch(0.985 0 0);
- --sidebar-primary: oklch(0.488 0.243 264.376);
- --sidebar-primary-foreground: oklch(0.985 0 0);
- --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);
-}
-
-@layer base {
- * {
- border-color: var(--border);
- outline-color: var(--ring, oklch(0.708 0 0)) / 50%;
- }
- body {
- background-color: var(--background);
- color: var(--foreground);
- }
-}
-
-/* Background utilities */
-@utility bg-concord-primary {
- background-color: var(--color-background-primary);
-}
-@utility bg-concord-secondary {
- background-color: var(--color-background-secondary);
-}
-@utility bg-concord-tertiary {
- background-color: var(--color-background-tertiary);
-}
-
-/* Text utilities */
-@utility text-concord-primary {
- color: var(--color-text-primary);
-}
-@utility text-concord-secondary {
- color: var(--color-text-secondary);
-}
-@utility text-concord-muted {
- color: var(--color-text-muted);
-}
-
-/* Interactive utilities */
-@utility text-interactive-normal {
- color: var(--color-interactive-normal);
-}
-@utility text-interactive-hover {
- color: var(--color-interactive-hover);
-}
-@utility text-interactive-active {
- color: var(--color-interactive-active);
-}
-
-/* Status utilities */
-@utility text-status-online {
- color: var(--color-status-online);
-}
-@utility text-status-away {
- color: var(--color-status-away);
-}
-@utility text-status-busy {
- color: var(--color-status-busy);
-}
-@utility text-status-offline {
- color: var(--color-status-offline);
-}
-
-@utility bg-status-online {
- background-color: var(--color-status-online);
-}
-@utility bg-status-away {
- background-color: var(--color-status-away);
-}
-@utility bg-status-busy {
- background-color: var(--color-status-busy);
-}
-@utility bg-status-offline {
- background-color: var(--color-status-offline);
-}
-
-/* Border utilities */
-@utility border-concord {
- border-color: var(--color-border);
-}
-@utility border-sidebar {
- border-color: var(--color-sidebar-border);
-}
-
-@utility interactive-hover {
- transition-property: color;
- transition-duration: 200ms;
- transition-timing-function: ease-in-out;
- color: var(--color-interactive-normal);
- &:hover {
- color: var(--color-interactive-hover);
- }
-}
-
-@utility spacing-xs {
- padding: var(--tw-spacing-1, 0.25rem);
- gap: var(--tw-spacing-1, 0.25rem);
-}
-@utility spacing-sm {
- padding: var(--tw-spacing-2, 0.5rem);
- gap: var(--tw-spacing-2, 0.5rem);
-}
-@utility spacing-md {
- padding: var(--tw-spacing-4, 1rem);
- gap: var(--tw-spacing-4, 1rem);
-}
-@utility spacing-lg {
- padding: var(--tw-spacing-6, 1.5rem);
- gap: var(--tw-spacing-6, 1.5rem);
-}
-@utility spacing-xl {
- padding: var(--tw-spacing-8, 2rem);
- gap: var(--tw-spacing-8, 2rem);
-}
-
-@utility spacing-x-xs {
- padding-left: var(--tw-spacing-1, 0.25rem);
- padding-right: var(--tw-spacing-1, 0.25rem);
-}
-@utility spacing-x-sm {
- padding-left: var(--tw-spacing-2, 0.5rem);
- padding-right: var(--tw-spacing-2, 0.5rem);
-}
-@utility spacing-x-md {
- padding-left: var(--tw-spacing-4, 1rem);
- padding-right: var(--tw-spacing-4, 1rem);
-}
-@utility spacing-x-lg {
- padding-left: var(--tw-spacing-6, 1.5rem);
- padding-right: var(--tw-spacing-6, 1.5rem);
-}
-@utility spacing-x-xl {
- padding-left: var(--tw-spacing-8, 2rem);
- padding-right: var(--tw-spacing-8, 2rem);
-}
-
-@utility spacing-y-xs {
- padding-top: var(--tw-spacing-1, 0.25rem);
- padding-bottom: var(--tw-spacing-1, 0.25rem);
-}
-@utility spacing-y-sm {
- padding-top: var(--tw-spacing-2, 0.5rem);
- padding-bottom: var(--tw-spacing-2, 0.5rem);
-}
-@utility spacing-y-md {
- padding-top: var(--tw-spacing-4, 1rem);
- padding-bottom: var(--tw-spacing-4, 1rem);
-}
-@utility spacing-y-lg {
- padding-top: var(--tw-spacing-6, 1.5rem);
- padding-bottom: var(--tw-spacing-6, 1.5rem);
-}
-@utility spacing-y-xl {
- padding-top: var(--tw-spacing-8, 2rem);
- padding-bottom: var(--tw-spacing-8, 2rem);
-}
-
-@layer components {
- /* Sidebar styling */
- .sidebar-primary {
- background-color: var(--color-sidebar);
- border-right-width: 1px;
- border-color: var(--color-sidebar-border);
- }
-
- .sidebar-secondary {
- background-color: var(--color-background-secondary);
- border-right-width: 1px;
- border-color: var(--color-border);
- }
-
- .panel-button {
- display: flex;
- width: full;
- flex-grow: 1;
- border-radius: 12px;
- margin: 4px 8px;
- padding: 8px;
- &:hover {
- background-color: var(--color-background-tertiary);
- }
- }
-}
diff --git a/concord-client/src/lib/api-client.ts b/concord-client/src/lib/api-client.ts
deleted file mode 100644
index e53acd7..0000000
--- a/concord-client/src/lib/api-client.ts
+++ /dev/null
@@ -1,359 +0,0 @@
-import { QueryClient } from "@tanstack/react-query";
-
-// Base API configuration
-export const API_BASE_URL =
- import.meta.env.VITE_API_URL || "http://localhost:3000";
-
-// Enhanced QueryClient with error handling
-export const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- staleTime: 500 * 1, // 1 minute
- refetchOnWindowFocus: true,
- retry: (failureCount, error: any) => {
- // Don't retry on auth errors
- if (error?.status === 401 || error?.status === 403) return false;
- return failureCount < 3;
- },
- },
- mutations: {
- retry: (failureCount, error: any) => {
- if (error?.status === 401 || error?.status === 403) return false;
- return failureCount < 2;
- },
- },
- },
-});
-
-// API Response types based on your backend
-export interface ApiResponse {
- success?: boolean;
- data?: T;
- error?: string;
-}
-
-// Specific response types for your backend
-export interface Instance {
- id: string;
- name: string;
- icon?: string | null;
- description?: string;
- createdAt: string;
- updatedAt: string;
-}
-
-export interface Category {
- id: string;
- name: string;
- instanceId: string;
- position: number;
- createdAt: string;
- updatedAt: string;
-}
-
-export interface Channel {
- id: string;
- name: string;
- type: "text" | "voice";
- categoryId: string;
- instanceId: string;
- position: number;
- description?: string;
- createdAt: string;
- updatedAt: string;
-}
-
-export interface BackendUser {
- id: string;
- userName: string;
- nickName: string | null;
- bio: string | null;
- picture: string | null;
- banner: string | null;
- admin: boolean;
- status: "online" | "offline" | "dnd" | "idle" | "invis";
- role: Array<{
- userId: string;
- instanceId: string;
- role?: string;
- }>;
-}
-
-export interface Message {
- id: string;
- text: string;
- channelId: string;
- userId: string;
- edited: boolean;
- createdAt: string;
- deleted: boolean;
- updatedAt: string;
- replies: MessageReply;
- user?: BackendUser;
-}
-
-export interface MessageReply {
- id: string;
- repliesToId: string;
- repliesToText: string;
-}
-
-// Enhanced fetch wrapper with auth and error handling
-export class ApiClient {
- private baseUrl: string;
-
- constructor(baseUrl: string = API_BASE_URL) {
- this.baseUrl = baseUrl;
- }
-
- private async getAuthHeaders(): Promise> {
- const headers: Record = {
- "Content-Type": "application/json",
- };
- return headers;
- }
-
- private async request(
- endpoint: string,
- options: RequestInit = {},
- ): Promise {
- const url = `${this.baseUrl}${endpoint}`;
- const headers = await this.getAuthHeaders();
-
- const config: RequestInit = {
- ...options,
- headers: {
- ...headers,
- ...options.headers,
- },
- };
-
- try {
- const response = await fetch(url, config);
-
- if (!response.ok) {
- if (response.status === 401) {
- // Handle auth error - logout user
- const authStore = await import("@/stores/authStore");
- authStore.useAuthStore.getState().logout();
- throw new Error("Authentication required");
- }
-
- const errorData = await response
- .json()
- .catch(() => ({ error: "Unknown error" }));
- throw new Error(errorData.error || `HTTP ${response.status}`);
- }
-
- const data = await response.json();
- return data as T;
- } catch (error) {
- console.error(`API request failed: ${endpoint}`, error);
- throw error;
- }
- }
-
- // Instance/Server methods
- async getInstances(): Promise {
- const response = await this.request<
- { success: boolean; data: Instance[] } | Instance[]
- >("/api/instance");
-
- // Handle both wrapped and direct responses
- if (Array.isArray(response)) {
- return response;
- }
-
- if ("data" in response && Array.isArray(response.data)) {
- return response.data;
- }
-
- return [];
- }
-
- async createInstance(data: {
- name: string;
- icon?: string;
- requestingUserId: string;
- requestingUserToken: string;
- }): Promise {
- return this.request("/api/instance", {
- method: "POST",
- body: JSON.stringify(data),
- });
- }
-
- // Categories methods
- async getCategoriesByInstance(instanceId: string): Promise {
- try {
- const response = await this.request(
- `/api/category/instance/${instanceId}`,
- );
-
- if (Array.isArray(response)) {
- return response;
- }
-
- if ("data" in response && Array.isArray(response.data)) {
- return response.data;
- }
-
- return [];
- } catch (error) {
- console.warn(
- `Categories endpoint not available for instance ${instanceId}`,
- error,
- );
- return [];
- }
- }
-
- async createCategory(data: {
- name: string;
- position: number;
- instanceId?: string;
- admin: boolean;
- requestingUserId: string;
- requestingUserToken: string;
- }): Promise {
- return this.request("/api/category", {
- method: "POST",
- body: JSON.stringify(data),
- });
- }
-
- // Channel methods
- async getChannelsByCategory(categoryId: string): Promise {
- try {
- const response = await this.request(
- `/api/channel/category/${categoryId}`,
- );
-
- if (Array.isArray(response)) {
- return response;
- }
-
- if ("data" in response && Array.isArray(response.data)) {
- return response.data;
- }
-
- return [];
- } catch (error) {
- console.warn(
- `Channels endpoint not available for category ${categoryId}`,
- error,
- );
- return [];
- }
- }
-
- async createChannel(data: {
- type: "text" | "voice";
- name: string;
- description: string;
- categoryId?: string;
- admin: boolean;
- requestingUserId: string;
- requestingUserToken: string;
- }): Promise {
- console.log(data);
-
- return this.request("/api/channel", {
- method: "POST",
- body: JSON.stringify(data),
- });
- }
-
- // Message methods
- async getMessages(params: {
- date: string;
- channelId: string;
- }): Promise {
- const query = new URLSearchParams(params);
- const response = await this.request(
- `/api/message?${query}`,
- );
-
- if (Array.isArray(response)) {
- return response;
- }
-
- if ("data" in response && Array.isArray(response.data)) {
- return response.data;
- }
-
- return [];
- }
-
- async sendMessage(data: {
- channelId: string;
- userId: string;
- content: string;
- token: string;
- repliedMessageId?: string | null;
- }): Promise {
- return this.request("/api/message", {
- method: "POST",
- body: JSON.stringify(data),
- });
- }
-
- // User methods
- async getUsersByInstance(instanceId: string): Promise {
- const query = new URLSearchParams({ instanceId });
- const response = await this.request<
- BackendUser[] | { data: BackendUser[] }
- >(`/api/user?${query}`);
-
- if (Array.isArray(response)) {
- return response;
- }
-
- if ("data" in response && Array.isArray(response.data)) {
- return response.data;
- }
-
- return [];
- }
-
- async getUser(id: string): Promise {
- const response = await this.request(
- `/api/user/${id}`,
- );
-
- if ("data" in response) {
- return response.data;
- }
-
- return response as BackendUser;
- }
-
- async createUser(data: {
- username: string;
- nickname?: string;
- bio?: string;
- picture?: string;
- banner?: string;
- status?: "online" | "offline" | "dnd" | "idle" | "invis";
- admin?: boolean;
- requestingUserId: string;
- requestingUserToken: string;
- passwordhash: string;
- }): Promise<{ success: boolean; data?: BackendUser; error?: string }> {
- try {
- const response = await this.request("/api/user", {
- method: "POST",
- body: JSON.stringify(data),
- });
- return { success: true, data: response };
- } catch (error) {
- return {
- success: false,
- error: error instanceof Error ? error.message : "Unknown error",
- };
- }
- }
-}
-
-// Create singleton instance
-export const apiClient = new ApiClient();
diff --git a/concord-client/src/lib/auth-client.ts b/concord-client/src/lib/auth-client.ts
deleted file mode 100644
index 87e787e..0000000
--- a/concord-client/src/lib/auth-client.ts
+++ /dev/null
@@ -1,175 +0,0 @@
-import { apiClient, BackendUser } from "./api-client";
-
-export interface LoginCredentials {
- username: string;
- password: string;
-}
-
-export interface RegisterData {
- username: string;
- password: string;
- nickname?: string;
- bio?: string;
- picture?: string;
- banner?: string;
-}
-
-export interface AuthResponse {
- user: BackendUser;
- token: string;
-}
-
-class AuthClient {
- private baseUrl: string;
-
- constructor(
- baseUrl: string = import.meta.env.VITE_API_URL || "http://localhost:3000",
- ) {
- this.baseUrl = baseUrl;
- }
-
- async login(credentials: LoginCredentials): Promise {
- try {
- const response = await fetch(`${this.baseUrl}/api/auth/login`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- username: credentials.username,
- password: credentials.password,
- }),
- });
-
- if (!response.ok) {
- const errorData = await response
- .json()
- .catch(() => ({ error: "Login failed" }));
- throw new Error(errorData.error || "Login failed");
- }
-
- const data: AuthResponse = await response.json();
- return data;
- } catch (error) {
- console.error("Login failed:", error);
- throw error instanceof Error ? error : new Error("Login failed");
- }
- }
-
- async register(
- data: RegisterData,
- adminUser: { id: string; token: string },
- ): Promise {
- try {
- const createUserData = {
- username: data.username,
- nickname: data.nickname,
- bio: data.bio,
- picture: data.picture,
- banner: data.banner,
- status: "online" as const,
- admin: false,
- requestingUserId: adminUser.id,
- requestingUserToken: adminUser.token,
- passwordhash: data.password,
- };
-
- const response = await apiClient.createUser(createUserData);
-
- if (!response.success || !response.data) {
- throw new Error(response.error || "Registration failed");
- }
- try {
- const loginResponse = await this.login({
- username: data.username,
- password: data.password,
- });
- return loginResponse;
- } catch (loginError) {
- throw new Error(
- "Registration successful, but auto-login failed. Please login manually.",
- );
- }
- } catch (error) {
- console.error("Registration failed:", error);
- throw error instanceof Error ? error : new Error("Registration failed");
- }
- }
-
- async validateToken(
- token: string,
- userId: string,
- ): Promise<{ valid: boolean; user?: BackendUser }> {
- try {
- const response = await fetch(`${this.baseUrl}/api/auth/validate`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ token, userId }),
- });
-
- if (!response.ok) {
- return { valid: false };
- }
-
- const data: { valid: boolean; user?: BackendUser } =
- await response.json();
- return data;
- } catch (error) {
- console.error("Token validation failed:", error);
- return { valid: false };
- }
- }
-
- async refreshToken(oldToken: string, userId: string): Promise {
- try {
- const response = await fetch(`${this.baseUrl}/api/auth/refresh`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ userId, oldToken }),
- });
-
- if (!response.ok) {
- const errorData = await response
- .json()
- .catch(() => ({ error: "Token refresh failed" }));
- throw new Error(errorData.error || "Token refresh failed");
- }
-
- const data: AuthResponse = await response.json();
- return data;
- } catch (error) {
- console.error("Token refresh failed:", error);
- throw error instanceof Error ? error : new Error("Token refresh failed");
- }
- }
-
- async logout(userId: string): Promise<{ success: boolean }> {
- try {
- const response = await fetch(`${this.baseUrl}/api/auth/logout`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ userId }),
- });
-
- if (!response.ok) {
- console.warn(
- "Logout endpoint failed, but continuing with local logout",
- );
- }
-
- const data = await response.json().catch(() => ({ success: true }));
- return data;
- } catch (error) {
- console.warn("Logout request failed:", error);
- return { success: true }; // Always succeed locally
- }
- }
-}
-
-export const authClient = new AuthClient();
diff --git a/concord-client/src/lib/utils.ts b/concord-client/src/lib/utils.ts
deleted file mode 100644
index bd0c391..0000000
--- a/concord-client/src/lib/utils.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { clsx, type ClassValue } from "clsx"
-import { twMerge } from "tailwind-merge"
-
-export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
-}
diff --git a/concord-client/src/main.tsx b/concord-client/src/main.tsx
deleted file mode 100644
index 338cfb3..0000000
--- a/concord-client/src/main.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from "react";
-import ReactDOM from "react-dom/client";
-import App from "./App.tsx";
-import { io } from "socket.io-client";
-import "./index.css";
-
-const socket = io("http://localhost:3000");
-
-ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
- ,
-);
diff --git a/concord-client/src/pages/ChatPage.tsx b/concord-client/src/pages/ChatPage.tsx
deleted file mode 100644
index 5326d56..0000000
--- a/concord-client/src/pages/ChatPage.tsx
+++ /dev/null
@@ -1,372 +0,0 @@
-import React, { useState, useEffect, useRef } from "react";
-import { useNavigate, useParams } from "react-router";
-import { Hash, Volume2, Users } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { ScrollArea } from "@/components/ui/scroll-area";
-import { MessageComponent } from "@/components/message/MessageComponent";
-import { useInstanceDetails, useInstanceMembers } from "@/hooks/useServers";
-import { useChannelMessages, useLoadMoreMessages } from "@/hooks/useMessages";
-import { useUiStore } from "@/stores/uiStore";
-import { useAuthStore } from "@/stores/authStore";
-import { Message } from "@/lib/api-client";
-import { MessageInput } from "@/components/message/MessageInput";
-
-const ChatPage: React.FC = () => {
- const { instanceId, channelId } = useParams();
- const navigate = useNavigate();
-
- const {
- data: instance,
- isLoading: instanceLoading,
- error: instanceError,
- } = useInstanceDetails(instanceId);
- const {
- data: channelMessages,
- isLoading: messagesLoading,
- error: messagesError,
- } = useChannelMessages(channelId);
- const { data: users, isLoading: usersLoading } =
- useInstanceMembers(instanceId);
-
- // UI state hooks - called unconditionally
- const { toggleMemberList, showMemberList } = useUiStore();
- const { user: currentUser } = useAuthStore();
-
- // Local state hooks - called unconditionally
- const [replyingTo, setReplyingTo] = useState(null);
- const [isLoadingMore, setIsLoadingMore] = useState(false);
-
- const messagesEndRef = useRef(null);
- const messagesStartRef = useRef(null);
- const scrollAreaRef = useRef(null); // Ref for the ScrollArea content wrapper
-
- // API mutation hooks - called unconditionally
- const loadMoreMessagesMutation = useLoadMoreMessages(channelId);
-
- // Memoized values - called unconditionally
- const categories = instance?.categories;
-
- const currentChannel = React.useMemo(() => {
- return categories
- ?.flatMap((cat) => cat.channels)
- ?.find((ch) => ch.id === channelId);
- }, [categories, channelId]);
-
- const userHasAccess = React.useMemo(() => {
- if (!currentUser || !instanceId) return false;
- if (currentUser.admin) return true;
- return currentUser.roles.some((role) => role.instanceId === instanceId);
- }, [currentUser, instanceId]);
-
- const sortedMessages = React.useMemo(() => {
- if (!channelMessages) return [];
-
- // Sort messages by createdAt timestamp (oldest first, newest last)
- return [...channelMessages].sort((a, b) => {
- const dateA = new Date(a.createdAt).getTime();
- const dateB = new Date(b.createdAt).getTime();
- return dateA - dateB; // ascending order (oldest to newest)
- });
- }, [channelMessages]);
-
- // Effects - called unconditionally
- useEffect(() => {
- // Scroll to bottom when messages load or update
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
- }, [channelMessages]);
-
- // Auto-focus on channel change or initial load (using DOM query)
- useEffect(() => {
- if (!currentUser) return; // Skip if input isn't rendered
-
- let retryCount = 0;
- const maxRetries = 10;
- const retryInterval = 100; // ms
-
- const focusInput = () => {
- retryCount++;
- const textarea = document.getElementById(
- "message-input-textarea",
- ) as HTMLTextAreaElement | null;
- if (textarea) {
- textarea.focus();
- } else if (retryCount < maxRetries) {
- setTimeout(focusInput, retryInterval);
- }
- };
-
- focusInput();
- }, [channelId, currentUser]);
-
- useEffect(() => {
- if (!replyingTo) return; // Skip if no reply
-
- const focusInput = () => {
- const textarea = document.getElementById(
- "message-input-textarea",
- ) as HTMLTextAreaElement | null;
- if (textarea) {
- textarea.focus();
- }
- };
-
- focusInput();
- }, [replyingTo]);
-
- // Event handlers
- const handleLoadMore = React.useCallback(async () => {
- if (!channelMessages || channelMessages.length === 0 || isLoadingMore)
- return;
-
- setIsLoadingMore(true);
- try {
- const oldestMessage = channelMessages[0];
- await loadMoreMessagesMutation.mutateAsync({
- beforeDate: new Date(oldestMessage.createdAt),
- });
- } catch (error) {
- console.error("Failed to load more messages:", error);
- } finally {
- setIsLoadingMore(false);
- }
- }, [channelMessages, isLoadingMore, loadMoreMessagesMutation]);
-
- const handleReply = React.useCallback(
- (messageId: string) => {
- const message = channelMessages?.find((m) => m.id === messageId);
- if (message) {
- setReplyingTo(message);
- }
- },
- [channelMessages],
- );
-
- // Effect for scroll to top and load more
- useEffect(() => {
- const scrollAreaElement = scrollAreaRef.current;
-
- const handleScroll = () => {
- if (
- scrollAreaElement &&
- scrollAreaElement.scrollTop === 0 &&
- channelMessages &&
- channelMessages.length > 0 &&
- !isLoadingMore
- ) {
- handleLoadMore();
- }
- };
-
- if (scrollAreaElement) {
- scrollAreaElement.addEventListener("scroll", handleScroll);
- }
-
- return () => {
- if (scrollAreaElement) {
- scrollAreaElement.removeEventListener("scroll", handleScroll);
- }
- };
- }, [channelMessages, isLoadingMore, handleLoadMore]);
-
- // Handle loading states
- if (instanceLoading || messagesLoading || usersLoading) {
- return (
-
- );
- }
-
- // Handle errors and permissions
- if (!userHasAccess) {
- return (
-
-
-
- Access Denied
-
-
You don't have permission to view this server.
-
-
-
- );
- }
-
- if (instanceError || messagesError) {
- return (
-
-
-
- Error Loading Chat
-
-
- {instanceError?.message ||
- messagesError?.message ||
- "Something went wrong"}
-
-
-
-
- );
- }
-
- // Require both instanceId and channelId for chat
- if (!instanceId) {
- return (
-
-
-
- No Server Selected
-
-
Select a server from the sidebar to start chatting.
-
-
- );
- } else if (!channelId || !currentChannel) {
- const existingChannelId = categories?.flatMap((cat) => cat.channels)?.[0]
- ?.id; // Get the first channel from the flattened list
-
- if (existingChannelId) {
- navigate(`/channels/${instanceId}/${existingChannelId}`);
- return null;
- } else {
- return (
-
-
-
- No channels exist yet!
-
-
Ask an admin to create a channel
-
-
- );
- }
- }
-
- const ChannelIcon = currentChannel?.type === "voice" ? Volume2 : Hash;
-
- return (
-
- {/* Channel Header */}
-
-
-
-
- {currentChannel?.name}
-
- {currentChannel?.description && (
- <>
-
-
- {currentChannel.description}
-
- >
- )}
-
-
-
-
-
- {/* Chat Content */}
-
- {/* Messages Area */}
-
- {/* Attach ref to the actual scrollable content */}
-
-
-
- {/* Welcome Message */}
-
-
-
-
-
-
-
- Welcome to #{currentChannel?.name}!
-
-
-
-
-
-
- {/* Messages */}
- {sortedMessages && sortedMessages.length > 0 ? (
-
- {sortedMessages.map((message) => {
- const user = users?.find((u) => u.id === message.userId);
- const replyToMessage = channelMessages?.find(
- (m) => m.id === message.replies?.repliesToId,
- );
- const replyToUser = replyToMessage
- ? users?.find((u) => u.id === replyToMessage.userId)
- : undefined;
-
- if (!user) return null;
-
- return (
-
- );
- })}
-
- ) : (
-
-
-
No messages yet. Start the conversation!
-
-
- )}
-
-
-
-
-
-
- {/* Message Input */}
- {currentUser && (
-
- setReplyingTo(null)}
- replyingToUser={
- replyingTo
- ? users?.find((u) => u.id === replyingTo.userId) || null
- : null
- }
- />
-
- )}
-
-
- );
-};
-
-export default ChatPage;
diff --git a/concord-client/src/pages/LoginPage.tsx b/concord-client/src/pages/LoginPage.tsx
deleted file mode 100644
index cfcd3da..0000000
--- a/concord-client/src/pages/LoginPage.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import React, { useState } from "react";
-import { Navigate } from "react-router";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
-} from "@/components/ui/card";
-import { Alert, AlertDescription } from "@/components/ui/alert";
-import { useAuthStore } from "@/stores/authStore";
-import { useLogin } from "@/hooks/useAuth";
-
-const LoginPage: React.FC = () => {
- const { isAuthenticated } = useAuthStore();
- const [username, setUsername] = useState("");
- const [password, setPassword] = useState("");
-
- // Use the real login hook
- const { mutate: login, isPending, error } = useLogin();
-
- // Redirect if already authenticated
- if (isAuthenticated) {
- return ;
- }
-
- const handleLogin = async (e: React.FormEvent) => {
- e.preventDefault();
-
- if (!username.trim() || !password.trim()) {
- return;
- }
-
- login({ username: username.trim(), password });
- };
-
- return (
-
- );
-};
-
-export default LoginPage;
diff --git a/concord-client/src/pages/NotFoundPage.tsx b/concord-client/src/pages/NotFoundPage.tsx
deleted file mode 100644
index e5e1d0a..0000000
--- a/concord-client/src/pages/NotFoundPage.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Button } from "@/components/ui/button";
-
-const NotFoundPage: React.FC = () => {
- return (
-
-
-
404
-
Page not found
-
-
-
- );
-};
-
-export default NotFoundPage;
diff --git a/concord-client/src/pages/SettingsPage.tsx b/concord-client/src/pages/SettingsPage.tsx
deleted file mode 100644
index a1c5013..0000000
--- a/concord-client/src/pages/SettingsPage.tsx
+++ /dev/null
@@ -1,596 +0,0 @@
-import React, { useState } from "react";
-import { useNavigate, useParams } from "react-router";
-import {
- Palette,
- User,
- Mic,
- Settings,
- ChevronRight,
- Moon,
- Sun,
- Monitor,
-} from "lucide-react";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Separator } from "@/components/ui/separator";
-import { ScrollArea } from "@/components/ui/scroll-area";
-import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
-} from "@/components/ui/card";
-import { Alert, AlertDescription } from "@/components/ui/alert";
-import { useTheme } from "@/components/theme-provider";
-import { useAuthStore } from "@/stores/authStore";
-import { Slider } from "@/components/ui/slider";
-
-type SettingsSection = {
- id: string;
- title: string;
- icon: React.ComponentType<{ className?: string }>;
- description?: string;
-};
-
-const SETTINGS_SECTIONS: SettingsSection[] = [
- {
- id: "account",
- title: "My Account",
- icon: User,
- description: "Profile, privacy, and account settings",
- },
- {
- id: "appearance",
- title: "Appearance",
- icon: Palette,
- description: "Themes, display, and accessibility",
- },
- {
- id: "voice",
- title: "Voice & Video",
- icon: Mic,
- description: "Audio and video settings",
- },
-];
-
-const AccountSettings: React.FC = () => {
- const { user } = useAuthStore();
- const [username, setUsername] = useState(user?.username || "");
- const [nickname, setNickname] = useState(user?.nickname || "");
- const [bio, setBio] = useState(user?.bio || "");
- const [isChanged, setIsChanged] = useState(false);
- const [isSaving, setIsSaving] = useState(false);
- const [saveError, setSaveError] = useState("");
- const [saveSuccess, setSaveSuccess] = useState("");
-
- const handleSave = async () => {
- setSaveError("");
- setSaveSuccess("");
- setIsSaving(true);
-
- try {
- // TODO: Implement actual profile update API call
-
- // Update local state
- // updateUser({
- // username: username.trim(),
- // nickname: nickname.trim() || null,
- // bio: bio.trim() || null,
- // });
-
- setSaveSuccess("Profile updated successfully");
- setIsChanged(false);
- } catch (error) {
- setSaveError("Failed to update profile. Please try again.");
- } finally {
- setIsSaving(false);
- }
- };
-
- const handleChange = () => {
- setIsChanged(true);
- setSaveError("");
- setSaveSuccess("");
- };
-
- return (
-
-
-
-
-
- Profile
-
-
- Update your profile information and display settings.
-
-
-
- {saveError && (
-
- {saveError}
-
- )}
-
- {saveSuccess && (
-
- {saveSuccess}
-
- )}
-
-
-
-
-
- {isChanged && (
-
- )}
-
-
-
-
- );
-};
-
-const AppearanceSettings: React.FC = () => {
- const {
- currentLightTheme,
- currentDarkTheme,
- getThemesForMode,
- mode,
- setMode,
- setTheme,
- } = useTheme();
- const lightThemes = getThemesForMode("light");
- const darkThemes = getThemesForMode("dark");
-
- const getModeIcon = (themeMode: "light" | "dark" | "system") => {
- switch (themeMode) {
- case "light":
- return ;
- case "dark":
- return ;
- default:
- return ;
- }
- };
-
- return (
-
- {/* Theme Mode Selection */}
-
-
-
- {getModeIcon(mode)}
- Theme Mode
-
-
- Choose between light, dark, or system preference.
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Theme Selection */}
-
-
-
-
- Theme Selection
-
-
- Choose themes for light and dark mode. You can also create custom
- themes.
-
-
-
- {/* Current Theme Display */}
-
-
-
-
-
-
-
{currentLightTheme.name}
- {currentLightTheme.description && (
-
- {currentLightTheme.description}
-
- )}
-
-
-
-
-
-
-
-
-
{currentDarkTheme.name}
- {currentDarkTheme.description && (
-
- {currentDarkTheme.description}
-
- )}
-
-
-
-
- {/* Theme Grid */}
-
-
-
- {/* Light Themes */}
- {lightThemes.map((theme) => (
-
- ))}
-
- {/* Dark Themes */}
- {darkThemes.map((theme) => (
-
- ))}
-
-
-
- {/* Theme Stats */}
-
-
-
{lightThemes.length}
-
Light Themes
-
-
-
{darkThemes.length}
-
Dark Themes
-
-
-
-
-
- );
-};
-
-const VoiceSettings: React.FC = () => {
- const [inputVolume, setInputVolume] = useState(75);
- const [outputVolume, setOutputVolume] = useState(100);
-
- return (
-
-
-
-
-
- Voice Settings
-
-
- Configure your microphone and audio settings.
-
-
-
-
-
- {
- setInputVolume(v[0]);
- }}
- />
-
-
-
-
- {
- setOutputVolume(v[0]);
- }}
- />
-
-
-
-
-
-
- );
-};
-
-const SettingsPage: React.FC = () => {
- const { section } = useParams();
- const currentSection = section || "account";
- const navigate = useNavigate();
-
- const renderSettingsContent = () => {
- switch (currentSection) {
- case "account":
- return ;
- case "appearance":
- return ;
- case "voice":
- return ;
- default:
- return ;
- }
- };
-
- return (
-
- {/* Sidebar */}
-
-
-
- Settings
-
-
-
-
-
- {SETTINGS_SECTIONS.map((settingsSection) => {
- const Icon = settingsSection.icon;
- const isActive = currentSection === settingsSection.id;
-
- return (
-
- );
- })}
-
-
-
-
- {/* Main Content */}
-
- {/* Header */}
-
-
- {(() => {
- const section = SETTINGS_SECTIONS.find(
- (s) => s.id === currentSection,
- );
- const Icon = section?.icon || Settings;
- return ;
- })()}
-
- {SETTINGS_SECTIONS.find((s) => s.id === currentSection)?.title ||
- "Settings"}
-
-
-
-
- {/* Content */}
-
- {renderSettingsContent()}
-
-
-
- );
-};
-
-export default SettingsPage;
diff --git a/concord-client/src/stores/authStore.ts b/concord-client/src/stores/authStore.ts
deleted file mode 100644
index a65a82f..0000000
--- a/concord-client/src/stores/authStore.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { create } from "zustand";
-import { persist } from "zustand/middleware";
-import { User } from "@/types/database";
-
-interface AuthState {
- user: User | null;
- token: string | null;
- refreshToken: string | null;
- isAuthenticated: boolean;
- isLoading: boolean;
-
- // Actions
- setAuth: (user: User, token: string, refreshToken: string) => void;
- updateUser: (user: Partial) => void;
- logout: () => void;
- setLoading: (loading: boolean) => void;
-}
-
-export const useAuthStore = create()(
- persist(
- (set) => ({
- user: null,
- token: null,
- refreshToken: null,
- isAuthenticated: false,
- isLoading: false,
-
- setAuth: (user, token, refreshToken) =>
- set({
- user,
- token,
- refreshToken,
- isAuthenticated: true,
- isLoading: false,
- }),
-
- updateUser: (userData) =>
- set((state) => ({
- user: state.user ? { ...state.user, ...userData } : null,
- })),
-
- logout: () =>
- set({
- user: null,
- token: null,
- refreshToken: null,
- isAuthenticated: false,
- isLoading: false,
- }),
-
- setLoading: (isLoading) => set({ isLoading }),
- }),
- {
- name: "concord-auth-store",
- // Persist auth data
- partialize: (state) => ({
- user: state.user,
- token: state.token,
- refreshToken: state.refreshToken,
- isAuthenticated: state.isAuthenticated,
- }),
- },
- ),
-);
-
-export const useCurrentUser = () => useAuthStore((state) => state.user);
-export const useIsAuthenticated = () =>
- useAuthStore((state) => state.isAuthenticated);
-export const useAuthToken = () => useAuthStore((state) => state.token);
diff --git a/concord-client/src/stores/uiStore.ts b/concord-client/src/stores/uiStore.ts
deleted file mode 100644
index 22e08ab..0000000
--- a/concord-client/src/stores/uiStore.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import { create } from "zustand";
-import { persist } from "zustand/middleware";
-
-interface UiState {
- // Sidebar states
- showMemberList: boolean;
- sidebarCollapsed: boolean;
-
- // Modal states
- showUserSettings: boolean;
- showServerSettings: boolean;
- showCreateChannel: boolean;
- showCreateServer: boolean;
- showInviteModal: boolean;
-
- // Navigation
- activeChannelId: string | null;
- activeInstanceId: string | null;
-
- // Computed: Should show channel sidebar
- shouldShowChannelSidebar: boolean;
-
- // Actions
- toggleMemberList: () => void;
- toggleSidebar: () => void;
-
- // Modal actions
- openUserSettings: () => void;
- closeUserSettings: () => void;
- openServerSettings: () => void;
- closeServerSettings: () => void;
- openCreateChannel: () => void;
- closeCreateChannel: () => void;
- openCreateServer: () => void;
- closeCreateServer: () => void;
- openInviteModal: () => void;
- closeInviteModal: () => void;
-
- // Navigation actions
- setActiveChannel: (channelId: string | null) => void;
- setActiveInstance: (instanceId: string | null) => void;
- selectedChannelsByInstance: Record;
- setSelectedChannelForInstance: (
- instanceId: string,
- channelId: string,
- ) => void;
- getSelectedChannelForInstance: (instanceId: string) => string | null;
- updateSidebarVisibility: (pathname: string) => void;
-}
-
-// Helper function to determine if channel sidebar should be shown
-const shouldShowChannelSidebar = (pathname: string): boolean => {
- // Show channel sidebar for server pages (not settings, home, etc.)
- const pathParts = pathname.split("/");
- const isChannelsRoute = pathParts[1] === "channels";
- const isSettingsRoute = pathname.includes("/settings");
-
- return isChannelsRoute && !isSettingsRoute;
-};
-
-export const useUiStore = create()(
- persist(
- (set, get) => ({
- // Initial state
- showMemberList: true,
- sidebarCollapsed: false,
- screenWidth: typeof window !== "undefined" ? window.innerWidth : 1024,
- showUserSettings: false,
- showServerSettings: false,
- showCreateChannel: false,
- showCreateServer: false,
- showInviteModal: false,
- activeChannelId: null,
- activeInstanceId: null,
- shouldShowChannelSidebar: false,
- selectedChannelsByInstance: {},
-
- // Sidebar actions
- toggleMemberList: () =>
- set((state) => ({ showMemberList: !state.showMemberList })),
- toggleSidebar: () =>
- set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),
-
- // Modal actions
- openUserSettings: () => set({ showUserSettings: true }),
- closeUserSettings: () => set({ showUserSettings: false }),
- openServerSettings: () => set({ showServerSettings: true }),
- closeServerSettings: () => set({ showServerSettings: false }),
- openCreateChannel: () => set({ showCreateChannel: true }),
- closeCreateChannel: () => set({ showCreateChannel: false }),
- openCreateServer: () => set({ showCreateServer: true }),
- closeCreateServer: () => set({ showCreateServer: false }),
- openInviteModal: () => set({ showInviteModal: true }),
- closeInviteModal: () => set({ showInviteModal: false }),
-
- // Navigation actions
- setActiveChannel: (channelId) => set({ activeChannelId: channelId }),
- setActiveInstance: (instanceId) => set({ activeInstanceId: instanceId }),
-
- setSelectedChannelForInstance: (instanceId, channelId) =>
- set((state) => ({
- selectedChannelsByInstance: {
- ...state.selectedChannelsByInstance,
- [instanceId]: channelId,
- },
- })),
-
- getSelectedChannelForInstance: (instanceId) => {
- const state = get();
- return state.selectedChannelsByInstance[instanceId] || null;
- },
- updateSidebarVisibility: (pathname) => {
- const showChannelSidebar = shouldShowChannelSidebar(pathname);
- const pathParts = pathname.split("/");
- const instanceId = pathParts[2] || null;
- const channelId = pathParts[3] || null;
-
- set({
- shouldShowChannelSidebar: showChannelSidebar,
- activeInstanceId: instanceId,
- activeChannelId: channelId,
- });
-
- // Store the selected channel for this instance if we have both
- if (instanceId && channelId) {
- get().setSelectedChannelForInstance(instanceId, channelId);
- }
- },
- }),
- {
- name: "concord-ui-store",
- // Only persist UI preferences, not temporary states
- partialize: (state) => ({
- showMemberList: state.showMemberList,
- sidebarCollapsed: state.sidebarCollapsed,
-
- selectedChannelsByInstance: state.selectedChannelsByInstance,
- }),
- },
- ),
-);
diff --git a/concord-client/src/stores/voiceStore.ts b/concord-client/src/stores/voiceStore.ts
deleted file mode 100644
index 72f78de..0000000
--- a/concord-client/src/stores/voiceStore.ts
+++ /dev/null
@@ -1,328 +0,0 @@
-import { create } from "zustand";
-import { Socket } from "socket.io-client";
-
-// --- TYPE DEFINITIONS ---
-
-interface IceServerConfig {
- urls: string | string[];
- username?: string;
- credential?: string;
-}
-
-// The state managed by the store
-interface VoiceState {
- socket: Socket | null;
- localStream: MediaStream | null;
- remoteStreams: Map;
- peerConnections: Map;
- iceServers: IceServerConfig[];
- isConnected: boolean;
- isConnecting: boolean;
- activeVoiceChannelId: string | null;
- isDeafened: boolean;
- isMuted: boolean;
-}
-
-// Actions that can be performed on the store
-interface VoiceActions {
- init: (socket: Socket) => void;
- joinChannel: (
- channelId: string,
- userId: string,
- token: string,
- ) => Promise;
- leaveChannel: () => void;
- cleanup: () => void;
- toggleMute: () => void;
- toggleDeafen: () => void;
-}
-
-// --- ZUSTAND STORE IMPLEMENTATION ---
-
-export const useVoiceStore = create((set, get) => {
- // --- INTERNAL HELPERS (not exposed in the store's public interface) ---
-
- /**
- * Safely closes and removes a single peer connection.
- * @param userId The ID of the user whose connection to clean up.
- */
- const cleanupPeerConnection = (userId: string) => {
- const { peerConnections } = get();
- const peerConnection = peerConnections.get(userId);
-
- if (peerConnection) {
- peerConnection.close();
- peerConnections.delete(userId);
- }
-
- set((state) => {
- const newStreams = new Map(state.remoteStreams);
- newStreams.delete(userId);
- return {
- remoteStreams: newStreams,
- peerConnections: new Map(peerConnections),
- };
- });
- };
-
- /**
- * Creates a new RTCPeerConnection for a target user and configures it.
- * @param targetUserId The user to connect to.
- * @returns The configured RTCPeerConnection instance.
- */
- const createPeerConnection = (targetUserId: string): RTCPeerConnection => {
- const { iceServers, localStream, socket, peerConnections } = get();
-
- const peerConnection = new RTCPeerConnection({ iceServers });
-
- // Add local stream tracks to the new connection
- if (localStream) {
- localStream
- .getTracks()
- .forEach((track) => peerConnection.addTrack(track, localStream));
- }
-
- // Handle ICE candidates
- peerConnection.onicecandidate = (event) => {
- if (event.candidate && socket) {
- socket.emit("webrtc-ice-candidate", {
- targetUserId,
- candidate: event.candidate,
- });
- }
- };
-
- // Handle incoming remote tracks
- peerConnection.ontrack = (event) => {
- set((state) => {
- const newStreams = new Map(state.remoteStreams);
- newStreams.set(targetUserId, event.streams[0]);
- return { remoteStreams: newStreams };
- });
- };
-
- // For debugging connection state
- peerConnection.onconnectionstatechange = () => {
- if (
- peerConnection.connectionState === "disconnected" ||
- peerConnection.connectionState === "failed"
- ) {
- cleanupPeerConnection(targetUserId);
- }
- };
-
- peerConnections.set(targetUserId, peerConnection);
- set({ peerConnections: new Map(peerConnections) });
- return peerConnection;
- };
-
- // --- SOCKET EVENT HANDLERS ---
- // These are defined once and can be reused by the join/leave actions.
-
- const onJoinedVoiceChannel = async (data: {
- connectedUserIds: string[];
- iceServers: IceServerConfig[];
- }) => {
- set({
- iceServers: data.iceServers,
- isConnecting: false,
- isConnected: true,
- });
-
- for (const userId of data.connectedUserIds) {
- const peerConnection = createPeerConnection(userId);
- const offer = await peerConnection.createOffer();
- await peerConnection.setLocalDescription(offer);
- get().socket?.emit("webrtc-offer", {
- targetUserId: userId,
- sdp: peerConnection.localDescription,
- });
- }
- };
-
- const onUserLeft = (data: { userId: string }) => {
- cleanupPeerConnection(data.userId);
- };
-
- const onWebRTCOffer = async (data: {
- senderUserId: string;
- sdp: RTCSessionDescriptionInit;
- }) => {
- const peerConnection = createPeerConnection(data.senderUserId);
- await peerConnection.setRemoteDescription(
- new RTCSessionDescription(data.sdp),
- );
- const answer = await peerConnection.createAnswer();
- await peerConnection.setLocalDescription(answer);
- get().socket?.emit("webrtc-answer", {
- targetUserId: data.senderUserId,
- sdp: peerConnection.localDescription,
- });
- };
-
- const onWebRTCAnswer = async (data: {
- senderUserId: string;
- sdp: RTCSessionDescriptionInit;
- }) => {
- const peerConnection = get().peerConnections.get(data.senderUserId);
- if (peerConnection) {
- await peerConnection.setRemoteDescription(
- new RTCSessionDescription(data.sdp),
- );
- }
- };
-
- const onICECandidate = async (data: {
- senderUserId: string;
- candidate: RTCIceCandidateInit;
- }) => {
- const peerConnection = get().peerConnections.get(data.senderUserId);
- if (peerConnection && data.candidate) {
- try {
- await peerConnection.addIceCandidate(
- new RTCIceCandidate(data.candidate),
- );
- } catch (e) {
- console.error("Error adding received ICE candidate", e);
- }
- }
- };
-
- const onError = (error: { message: string }) => {
- console.error("Voice channel error:", error.message);
- get().leaveChannel(); // Disconnect on error
- };
-
- // --- STORE DEFINITION (STATE & ACTIONS) ---
- return {
- // Initial State
- socket: null,
- localStream: null,
- remoteStreams: new Map(),
- peerConnections: new Map(),
- iceServers: [],
- isConnected: false,
- isConnecting: false,
- activeVoiceChannelId: null,
- isMuted: false,
- isDeafened: false,
-
- // Actions
- init: (socketInstance) => {
- set({ socket: socketInstance });
- },
-
- joinChannel: async (channelId: string, userId: string, token: string) => {
- const { socket, activeVoiceChannelId, leaveChannel, isConnecting } =
- get();
- if (!socket || isConnecting || activeVoiceChannelId === channelId) return;
- if (!userId || !token) {
- console.error("Join channel requires user and token.");
- return;
- }
-
- if (activeVoiceChannelId) {
- leaveChannel();
- }
-
- set({ isConnecting: true, activeVoiceChannelId: channelId });
-
- try {
- const stream = await navigator.mediaDevices.getUserMedia({
- audio: true,
- video: false,
- });
- set({ localStream: stream });
- } catch (error) {
- console.error("Could not get user media:", error);
- set({ isConnecting: false, activeVoiceChannelId: null });
- return;
- }
-
- // Attach all necessary listeners for a voice session
- socket.on("joined-voicechannel", onJoinedVoiceChannel);
- socket.on("user-left-voicechannel", onUserLeft);
- socket.on("webrtc-offer", onWebRTCOffer);
- socket.on("webrtc-answer", onWebRTCAnswer);
- socket.on("webrtc-ice-candidate", onICECandidate);
- socket.on("error-voicechannel", onError);
-
- // *** THE FIX: Send user credentials with the join request ***
- socket.emit("join-voicechannel", {
- userId: userId,
- userToken: token,
- voiceChannelId: channelId,
- });
- },
- leaveChannel: () => {
- const { socket, peerConnections, localStream, activeVoiceChannelId } =
- get();
- if (!socket || !activeVoiceChannelId) return;
-
- socket.emit("leave-voicechannel", { channelId: activeVoiceChannelId });
-
- // Clean up all event listeners
- socket.off("joined-voicechannel");
- socket.off("user-left-voicechannel");
- socket.off("webrtc-offer");
- socket.off("webrtc-answer");
- socket.off("webrtc-ice-candidate");
- socket.off("error-voicechannel");
-
- // Close all peer connections
- peerConnections.forEach((pc) => pc.close());
-
- // Stop local media tracks
- localStream?.getTracks().forEach((track) => track.stop());
-
- // Reset state to initial values
- set({
- localStream: null,
- remoteStreams: new Map(),
- peerConnections: new Map(),
- isConnected: false,
- isConnecting: false,
- activeVoiceChannelId: null,
- iceServers: [],
- });
- },
-
- toggleMute: () => {
- set((state) => {
- const newMutedState = !state.isMuted;
- if (state.localStream) {
- state.localStream.getAudioTracks().forEach((track) => {
- track.enabled = !newMutedState;
- });
- }
- // Cannot be deafened and unmuted
- if (state.isDeafened && !newMutedState) {
- return { isMuted: newMutedState, isDeafened: false };
- }
- return { isMuted: newMutedState };
- });
- },
-
- toggleDeafen: () => {
- set((state) => {
- const newDeafenedState = !state.isDeafened;
- // When deafening, you are also muted
- if (newDeafenedState && !state.isMuted) {
- // Manually mute logic without toggling deafen state again
- if (state.localStream) {
- state.localStream.getAudioTracks().forEach((track) => {
- track.enabled = false;
- });
- }
- return { isDeafened: newDeafenedState, isMuted: true };
- }
- return { isDeafened: newDeafenedState };
- });
- },
-
- cleanup: () => {
- get().leaveChannel();
- set({ socket: null });
- },
- };
-});
diff --git a/concord-client/src/types/api.ts b/concord-client/src/types/api.ts
deleted file mode 100644
index e632fb6..0000000
--- a/concord-client/src/types/api.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import { Instance, Category, Channel, User, Message } from "./database";
-
-// API Response wrappers
-export interface ApiResponse {
- data: T;
- success: boolean;
- message?: string;
-}
-
-export interface PaginatedResponse {
- data: T[];
- pagination: {
- page: number;
- limit: number;
- total: number;
- totalPages: number;
- hasNext: boolean;
- hasPrev: boolean;
- };
-}
-
-// Extended types with relations for frontend use
-export interface ChannelWithCategory extends Channel {
- category: Category;
-}
-
-export interface CategoryWithChannels extends Category {
- channels: Channel[];
-}
-
-export interface InstanceWithDetails extends Instance {
- categories: CategoryWithChannels[];
-}
-
-export interface MessageWithUser extends Message {
- user: User;
-}
-
-// Request types
-export interface CreateInstanceRequest {
- name: string;
- description?: string;
- icon?: string;
-}
-
-export interface CreateCategoryRequest {
- name: string;
- instanceId: string;
- position?: number;
-}
-
-export interface CreateChannelRequest {
- name: string;
- type: "text" | "voice";
- categoryId: string;
- topic?: string;
- position?: number;
-}
-
-export interface SendMessageRequest {
- content: string;
- channelId: string;
- user: User;
-}
-
-export interface UpdateMessageRequest {
- content: string;
-}
-
-export interface LoginRequest {
- username: string;
- password: string;
-}
-
-export interface RegisterRequest {
- username: string;
- password: string;
- email?: string;
-}
-
-export interface AuthResponse {
- user: User;
- token: string;
- refreshToken: string;
-}
diff --git a/concord-client/src/types/database.ts b/concord-client/src/types/database.ts
deleted file mode 100644
index 8c6302b..0000000
--- a/concord-client/src/types/database.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-export interface Instance {
- id: string;
- name: string;
- icon?: string | null;
- description?: string;
- createdAt: string;
- updatedAt: string;
-}
-
-export interface Category {
- id: string;
- name: string;
- instanceId: string;
- position: number;
- createdAt: string;
- updatedAt: string;
-}
-
-export interface Channel {
- id: string;
- name: string;
- type: "text" | "voice";
- categoryId: string;
- instanceId: string;
- position: number;
- description?: string;
- createdAt: string;
- updatedAt: string;
-}
-
-export type UserStatus = "online" | "away" | "busy" | "offline";
-export interface User {
- id: string;
- username: string;
- nickname?: string | null;
- bio?: string | null;
- picture?: string | null;
- banner?: string | null;
- hashPassword: string;
- admin: boolean;
- status: "online" | "away" | "busy" | "offline";
- createdAt: string;
- updatedAt: string;
- roles: Role[];
-}
-
-export interface Role {
- instanceId: string;
- role: "admin" | "mod" | "member";
-}
-
-export interface Message {
- id: string;
- content: string;
- channelId: string;
- userId: string;
- edited: boolean;
- createdAt: string;
- updatedAt: string;
- isGrouped?: boolean | null;
- replyTo?: Message | null;
- // Relations
- user?: User;
- channel?: Channel;
-
- replyToId?: string | null;
-}
-
-// Direct messages
-// export interface DirectMessage {
-// id: string;
-// content: string;
-// senderId: string;
-// receiverId: string;
-// edited: boolean;
-// createdAt: string;
-// updatedAt: string;
-// // Relations
-// sender?: User;
-// receiver?: User;
-// }
-
-export interface UserRole {
- userId: string;
- roleId: string;
- instanceId: string;
-}
-
-export interface UserInstance {
- userId: string;
- instanceId: string;
- joinedAt: string;
-}
diff --git a/concord-client/src/types/index.ts b/concord-client/src/types/index.ts
deleted file mode 100644
index 180b027..0000000
--- a/concord-client/src/types/index.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-// API types
-export type {
- ApiResponse,
- Instance,
- Category,
- Channel,
- BackendUser,
- Message,
-} from "@/lib/api-client";
-
-// Auth types
-export type {
- LoginCredentials,
- RegisterData,
- AuthResponse,
-} from "@/lib/auth-client";
-
-// Hook types
-export type { CategoryWithChannels, InstanceWithDetails } from "@/types/api";
-
-// Frontend User type (for compatibility with existing components)
-export interface User {
- id: string;
- username: string;
- nickname?: string | null;
- bio?: string | null;
- picture?: string | null;
- banner?: string | null;
- hashPassword: string;
- admin: boolean;
- status: string;
- createdAt: string;
- updatedAt: string;
- roles: Array<{
- instanceId: string;
- role: string;
- }>;
-}
diff --git a/concord-client/src/utils/permissions.ts b/concord-client/src/utils/permissions.ts
deleted file mode 100644
index e4e229d..0000000
--- a/concord-client/src/utils/permissions.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-import { User } from "@/types/database";
-
-export type UserPermission =
- | "view_instance"
- | "create_channel"
- | "delete_channel"
- | "create_category"
- | "delete_category"
- | "manage_instance"
- | "delete_messages"
- | "pin_messages"
- | "manage_users"
- | "create_instance"
- | "manage_roles";
-
-export type UserRole = "admin" | "mod" | "member";
-
-// Check if user has a specific role in an instance
-export function hasInstanceRole(
- user: User | null,
- instanceId: string,
- role: UserRole,
-): boolean {
- if (!user) return false;
-
- // Global admins have all permissions
- if (user.admin) return true;
-
- const userRole = user.roles.find((r) => r.instanceId === instanceId);
- if (!userRole) return false;
-
- switch (role) {
- case "admin":
- return userRole.role === "admin";
- case "mod":
- return userRole.role === "admin" || userRole.role === "mod";
- case "member":
- return (
- userRole.role === "admin" ||
- userRole.role === "mod" ||
- userRole.role === "member"
- );
- default:
- return false;
- }
-}
-
-// Check if user has access to view an instance
-export function canViewInstance(
- user: User | null,
- instanceId: string,
-): boolean {
- if (!user) return false;
-
- // Global admins can view all instances
- if (user.admin) return true;
-
- // Check if user has any role in this instance
- return user.roles.some((role) => role.instanceId === instanceId);
-}
-
-// Check if user has a specific permission in an instance
-export function hasPermission(
- user: User | null,
- instanceId: string,
- permission: UserPermission,
-): boolean {
- if (!user) return false;
-
- // Global admins have all permissions everywhere
- if (user.admin) return true;
-
- const userRole = user.roles.find((r) => r.instanceId === instanceId);
- if (!userRole) return false;
-
- switch (permission) {
- case "view_instance":
- return hasInstanceRole(user, instanceId, "member");
-
- case "create_channel":
- case "delete_channel":
- case "create_category":
- case "delete_category":
- case "manage_instance":
- case "manage_users":
- case "manage_roles":
- return hasInstanceRole(user, instanceId, "admin");
-
- case "delete_messages":
- case "pin_messages":
- return hasInstanceRole(user, instanceId, "mod");
-
- case "create_instance":
- return user.admin; // Only global admins can create instances
-
- default:
- return false;
- }
-}
-
-// Get user's role in a specific instance
-export function getUserRole(
- user: User | null,
- instanceId: string,
-): UserRole | null {
- if (!user) return null;
-
- // Global admins are always admins
- if (user.admin) return "admin";
-
- const userRole = user.roles.find((r) => r.instanceId === instanceId);
- return userRole ? (userRole.role as UserRole) : null;
-}
-
-// Filter instances that user can access
-export function getAccessibleInstances(
- user: User | null,
- instances: any[],
-): any[] {
- if (!user) return [];
-
- // Global admins can see all instances
- if (user.admin) return instances;
-
- // Filter instances where user has a role
- const userInstanceIds = new Set(user.roles.map((role) => role.instanceId));
- return instances.filter((instance) => userInstanceIds.has(instance.id));
-}
-
-// Check if user can delete a specific message
-export function canDeleteMessage(
- user: User | null,
- instanceId: string,
- messageUserId: string,
-): boolean {
- if (!user) return false;
-
- // Users can always delete their own messages
- if (user.id === messageUserId) return true;
-
- // Mods and admins can delete any message
- return hasPermission(user, instanceId, "delete_messages");
-}
-
-// Check if user can edit a specific message
-export function canEditMessage(
- user: User | null,
- messageUserId: string,
-): boolean {
- if (!user) return false;
-
- // Users can only edit their own messages
- return user.id === messageUserId;
-}
-
-// Check if user can pin messages
-export function canPinMessage(user: User | null, instanceId: string): boolean {
- return hasPermission(user, instanceId, "pin_messages");
-}
-
-// Check if user is global admin
-export function isGlobalAdmin(user: User | null): boolean {
- return user?.admin === true;
-}
-
-// Helper to get role display info
-export function getRoleDisplayInfo(role: UserRole) {
- switch (role) {
- case "admin":
- return {
- name: "Admin",
- color: "#ff6b6b",
- priority: 3,
- description: "Full server permissions",
- };
- case "mod":
- return {
- name: "Moderator",
- color: "#4ecdc4",
- priority: 2,
- description: "Can moderate messages and users",
- };
- case "member":
- return {
- name: "Member",
- color: null,
- priority: 1,
- description: "Basic server access",
- };
- default:
- return {
- name: "Unknown",
- color: null,
- priority: 0,
- description: "Unknown role",
- };
- }
-}
diff --git a/concord-client/src/vite-env.d.ts b/concord-client/src/vite-env.d.ts
deleted file mode 100644
index 7d0ff9e..0000000
--- a/concord-client/src/vite-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/concord-client/tsconfig.json b/concord-client/tsconfig.json
deleted file mode 100644
index 017ff67..0000000
--- a/concord-client/tsconfig.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
- "baseUrl": ".",
- "paths": {
- "@/*": ["./src/*"],
- },
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "react-jsx",
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
- },
- "include": ["src", "electron"],
- "references": [{ "path": "./tsconfig.node.json" }],
-}
diff --git a/concord-client/tsconfig.node.json b/concord-client/tsconfig.node.json
deleted file mode 100644
index efd3582..0000000
--- a/concord-client/tsconfig.node.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
- "module": "ESNext",
- "moduleResolution": "bundler",
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "baseUrl": ".",
- "paths": {
- "@/*": ["./src/*"]
- }
- },
- "include": ["vite.config.ts"]
-}
diff --git a/concord-client/vite.config.ts b/concord-client/vite.config.ts
deleted file mode 100644
index 0982af6..0000000
--- a/concord-client/vite.config.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { defineConfig } from "vite";
-import path from "path";
-import electron from "vite-plugin-electron/simple";
-import react from "@vitejs/plugin-react";
-import tailwindcss from "@tailwindcss/vite";
-
-// https://vitejs.dev/config/
-export default defineConfig(({ mode }) => {
- // Check if VITE_APP_MODE is set to 'web'
- const isWebApp = process.env.VITE_APP_MODE === "web";
-
- return {
- plugins: [
- react(),
- // Only include the electron plugin if not in 'web' app mode
- !isWebApp &&
- electron({
- main: {
- // Shortcut of `build.lib.entry`.
- entry: "electron/main.ts",
- },
- preload: {
- // Shortcut of `build.rollupOptions.input`.
- // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`.
- input: path.join(__dirname, "electron/preload.ts"),
- },
- // Ployfill the Electron and Node.js API for Renderer process.
- // If you want use Node.js in Renderer process, the `nodeIntegration` needs to be enabled in the Main process.
- // See 👉 https://github.com/electron-vite/vite-plugin-electron-renderer
- renderer:
- process.env.NODE_ENV === "test"
- ? // https://github.com/electron-vite/vite-plugin-electron-renderer/issues/78#issuecomment-2053600808
- undefined
- : {},
- }),
- tailwindcss(),
- ].filter(Boolean), // Filter out 'false' values if electron plugin is not included
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "./src"),
- },
- },
- };
-});
diff --git a/concord-server/.editorconfig b/concord-server/.editorconfig
deleted file mode 100644
index 1e09672..0000000
--- a/concord-server/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-# EditorConfig helps maintain consistent coding styles
-root = true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
diff --git a/concord-server/.gitignore b/concord-server/.gitignore
deleted file mode 100644
index 9371620..0000000
--- a/concord-server/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# deps
-node_modules/
-generated/
\ No newline at end of file
diff --git a/concord-server/README.md b/concord-server/README.md
deleted file mode 100644
index d950ba6..0000000
--- a/concord-server/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-To install dependencies:
-
-```sh
-bun install
-```
-
-To run:
-
-```sh
-bun run dev
-```
-
-open http://localhost:3000
diff --git a/concord-server/bun.lock b/concord-server/bun.lock
deleted file mode 100644
index d3d7309..0000000
--- a/concord-server/bun.lock
+++ /dev/null
@@ -1,243 +0,0 @@
-{
- "lockfileVersion": 1,
- "workspaces": {
- "": {
- "name": "concord-server",
- "dependencies": {
- "@hono/standard-validator": "^0.1.5",
- "@hono/zod-validator": "^0.7.3",
- "@prisma/client": "^6.16.2",
- "@scalar/hono-api-reference": "^0.9.19",
- "@socket.io/bun-engine": "^0.0.3",
- "hono": "^4.9.9",
- "hono-openapi": "^1.1.0",
- "prisma": "^6.16.2",
- "socket.io": "^4.8.1",
- "zod": "^4.1.11",
- },
- "devDependencies": {
- "@types/bun": "latest",
- "prisma-zod-generator": "^1.22.1",
- },
- },
- },
- "packages": {
- "@hono/standard-validator": ["@hono/standard-validator@0.1.5", "", { "peerDependencies": { "@standard-schema/spec": "1.0.0", "hono": ">=3.9.0" } }, "sha512-EIyZPPwkyLn6XKwFj5NBEWHXhXbgmnVh2ceIFo5GO7gKI9WmzTjPDKnppQB0KrqKeAkq3kpoW4SIbu5X1dgx3w=="],
-
- "@hono/zod-validator": ["@hono/zod-validator@0.7.3", "", { "peerDependencies": { "hono": ">=3.9.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-uYGdgVib3RlGD698WR5dVM0zB3UuPY5vHKXffGUbUh7r4xY+mFIhF3/v4AcQVLrU5CQdBso8BJr4wuVoCrjTuQ=="],
-
- "@prisma/client": ["@prisma/client@6.16.2", "", { "peerDependencies": { "prisma": "*", "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"] }, "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw=="],
-
- "@prisma/config": ["@prisma/config@6.16.2", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.16.12", "empathic": "2.0.0" } }, ""],
-
- "@prisma/debug": ["@prisma/debug@6.16.2", "", {}, ""],
-
- "@prisma/dmmf": ["@prisma/dmmf@6.16.2", "", {}, "sha512-o9ztgdbj2KZXl6DL+oP56TTC0poTLPns9/MeU761b49E1IQ/fd0jwdov1bidlNOiwio8Nsou23xNrYE/db10aA=="],
-
- "@prisma/driver-adapter-utils": ["@prisma/driver-adapter-utils@6.16.2", "", { "dependencies": { "@prisma/debug": "6.16.2" } }, "sha512-DMgfafnG0zPd+QoAQOC0Trn1xlb0fVAfQi2MpkpzSf641KiVkVPkJRXDSbcTbxGxO2HRdd0vI9U6LlesWad4XA=="],
-
- "@prisma/engines": ["@prisma/engines@6.16.2", "", { "dependencies": { "@prisma/debug": "6.16.2", "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "@prisma/fetch-engine": "6.16.2", "@prisma/get-platform": "6.16.2" } }, ""],
-
- "@prisma/engines-version": ["@prisma/engines-version@6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "", {}, ""],
-
- "@prisma/fetch-engine": ["@prisma/fetch-engine@6.16.2", "", { "dependencies": { "@prisma/debug": "6.16.2", "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "@prisma/get-platform": "6.16.2" } }, ""],
-
- "@prisma/generator": ["@prisma/generator@6.16.2", "", {}, "sha512-7bwRmtMIgfe1rUynh1p9VlmYvEiidbRO6aBphPBS6YGEGSvNe8+QExbRpsqFlFBvIX76BhZCxuEj7ZwALMYRKQ=="],
-
- "@prisma/generator-helper": ["@prisma/generator-helper@6.16.2", "", { "dependencies": { "@prisma/debug": "6.16.2", "@prisma/dmmf": "6.16.2", "@prisma/generator": "6.16.2" } }, "sha512-8tVnWM8ETJNrvI5CT9eKCW23+aPLNkidC+g9NJn7ghXm60Q7GGlLX5tmvn5dE8tXvs/FSX3MN7KNmNJpOr89Hw=="],
-
- "@prisma/get-platform": ["@prisma/get-platform@6.16.2", "", { "dependencies": { "@prisma/debug": "6.16.2" } }, ""],
-
- "@prisma/internals": ["@prisma/internals@6.16.2", "", { "dependencies": { "@prisma/config": "6.16.2", "@prisma/debug": "6.16.2", "@prisma/dmmf": "6.16.2", "@prisma/driver-adapter-utils": "6.16.2", "@prisma/engines": "6.16.2", "@prisma/fetch-engine": "6.16.2", "@prisma/generator": "6.16.2", "@prisma/generator-helper": "6.16.2", "@prisma/get-platform": "6.16.2", "@prisma/prisma-schema-wasm": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "@prisma/schema-engine-wasm": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "@prisma/schema-files-loader": "6.16.2", "arg": "5.0.2", "prompts": "2.4.2" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"] }, "sha512-gwmWl7H8iTbi+58RXua5Lsus5LDbIZGO2wQ4RoSX9YtEbKWHwRP8TUzTVLwRNeJ2DHwfnzhTLrUnybwotqiACg=="],
-
- "@prisma/prisma-schema-wasm": ["@prisma/prisma-schema-wasm@6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "", {}, "sha512-DvYi0zKqzPd49Z5japS3FawyMylscaoUmlXNhnRAXb8HZryG4Q7TM1FLX8OIAfCgLmoWS1c/Zf4UZznBXkvWSg=="],
-
- "@prisma/schema-engine-wasm": ["@prisma/schema-engine-wasm@6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "", {}, "sha512-HDgFE0um5OHkk2pkQbAgARR284i2VpoM+7GYRAT0zxoTagsdaZ6yquJF2LEZuAKfibib0Ct7JZxRCB8eN/Ru6g=="],
-
- "@prisma/schema-files-loader": ["@prisma/schema-files-loader@6.16.2", "", { "dependencies": { "@prisma/prisma-schema-wasm": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", "fs-extra": "11.3.0" } }, "sha512-TN77DUFgOxT/WL6wuxVhn7qVDvwVRl0TEzhFfRh5vKQsuZ5itLzA7Ki4TgOs4Pk18wwZnti6ZKdzR3Y7cu2KsA=="],
-
- "@scalar/core": ["@scalar/core@0.3.17", "", { "dependencies": { "@scalar/types": "0.2.16" } }, "sha512-G6tP+2oorFA90szI8DGiEQ23SmobiuhN93GfTJNpFMhz/kdEtC4lcYawAxL1tWkZhlK/QYRcaCZcVzmpTUgBCA=="],
-
- "@scalar/hono-api-reference": ["@scalar/hono-api-reference@0.9.19", "", { "dependencies": { "@scalar/core": "0.3.17" }, "peerDependencies": { "hono": "^4.0.0" } }, "sha512-MeBdIwuAAhwvsUt1f9174wASu0C8b4WrXuVdC/6FjrsTxLHSbJVx+XFzZAKF5ex+1kaXjvYrm3fiovRFHLyfJA=="],
-
- "@scalar/openapi-types": ["@scalar/openapi-types@0.3.7", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-QHSvHBVDze3+dUwAhIGq6l1iOev4jdoqdBK7QpfeN1Q4h+6qpVEw3EEqBiH0AXUSh/iWwObBv4uMgfIx0aNZ5g=="],
-
- "@scalar/types": ["@scalar/types@0.2.16", "", { "dependencies": { "@scalar/openapi-types": "0.3.7", "nanoid": "5.1.5", "zod": "3.24.1" } }, "sha512-XWff9jWfYaj6q3ww94x66S6Q58u/3kA1sDOUhLAwb9va7r58bzk3NRwLOkEEdJmyEns1MEJAM53mY8KRWX6elA=="],
-
- "@socket.io/bun-engine": ["@socket.io/bun-engine@0.0.3", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-OK2ZObq9hKsxyAcV7xDTcWGubBmfEY3Lt4nb04K+HlYl9G5PDgrY9hxJm9uV+B0xo3MhKFrgdg9VQsVZ3pbT/g=="],
-
- "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="],
-
- "@standard-community/standard-json": ["@standard-community/standard-json@0.3.5", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "sury": "^10.0.0", "typebox": "^1.0.17", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-to-json-schema"] }, "sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA=="],
-
- "@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.8", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-80ap74p5oy/SU4al5HkPwO5+NbN2wH/FBr6kwaE5ROq7AvcDFaxzUfTazewroNaCotbvdGcvzXb9oEoOIyfC/Q=="],
-
- "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, ""],
-
- "@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="],
-
- "@types/cors": ["@types/cors@2.8.19", "", { "dependencies": { "@types/node": "*" } }, "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg=="],
-
- "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
-
- "@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "~7.12.0" } }, ""],
-
- "@types/react": ["@types/react@19.1.14", "", { "dependencies": { "csstype": "^3.0.2" } }, ""],
-
- "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="],
-
- "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
-
- "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
-
- "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="],
-
- "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="],
-
- "bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, ""],
-
- "c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, ""],
-
- "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, ""],
-
- "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, ""],
-
- "confbox": ["confbox@0.2.2", "", {}, ""],
-
- "consola": ["consola@3.4.2", "", {}, ""],
-
- "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
-
- "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
-
- "csstype": ["csstype@3.1.3", "", {}, ""],
-
- "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
-
- "debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
-
- "deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, ""],
-
- "defu": ["defu@6.1.4", "", {}, ""],
-
- "destr": ["destr@2.0.5", "", {}, ""],
-
- "dotenv": ["dotenv@16.6.1", "", {}, ""],
-
- "effect": ["effect@3.16.12", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, ""],
-
- "empathic": ["empathic@2.0.0", "", {}, ""],
-
- "engine.io": ["engine.io@6.6.4", "", { "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1" } }, "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g=="],
-
- "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="],
-
- "exsolve": ["exsolve@1.0.7", "", {}, ""],
-
- "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, ""],
-
- "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
-
- "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
-
- "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
-
- "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
-
- "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="],
-
- "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": "dist/cli.mjs" }, ""],
-
- "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
-
- "hono": ["hono@4.9.9", "", {}, ""],
-
- "hono-openapi": ["hono-openapi@1.1.0", "", { "peerDependencies": { "@hono/standard-validator": "^0.1.2", "@standard-community/standard-json": "^0.3.5", "@standard-community/standard-openapi": "^0.2.8", "@types/json-schema": "^7.0.15", "hono": "^4.8.3", "openapi-types": "^12.1.3" }, "optionalPeers": ["@hono/standard-validator", "hono"] }, "sha512-eA5hN8D2O30EkPPUxWFilcZcThAe81TShbH38Y183ZZp8WkgMh4BrPEDeZ/EFN2tyDi3cmTgKTa3+oStyJX0UA=="],
-
- "jiti": ["jiti@2.6.0", "", { "bin": "lib/jiti-cli.mjs" }, ""],
-
- "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
-
- "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
-
- "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
-
- "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
-
- "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
-
- "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
-
- "nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="],
-
- "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
-
- "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
-
- "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
-
- "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, ""],
-
- "nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": "dist/cli.mjs" }, ""],
-
- "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
-
- "ohash": ["ohash@2.0.11", "", {}, ""],
-
- "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
-
- "pathe": ["pathe@2.0.3", "", {}, ""],
-
- "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, ""],
-
- "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, ""],
-
- "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
-
- "prisma": ["prisma@6.16.2", "", { "dependencies": { "@prisma/config": "6.16.2", "@prisma/engines": "6.16.2" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"], "bin": "build/index.js" }, ""],
-
- "prisma-zod-generator": ["prisma-zod-generator@1.22.1", "", { "dependencies": { "@prisma/client": "^6.16.2", "@prisma/generator-helper": "^6.16.2", "@prisma/internals": "^6.16.2", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "node-fetch": "^3.3.2", "prettier": "^3.6.2", "tslib": "^2.8.1" }, "peerDependencies": { "zod": ">=3.25.0 <5" }, "bin": { "prisma-zod-generator": "lib/generator.js" } }, "sha512-nBr00sfR8onGCD5eIDLHoFrpeJTSuZxSeaO61Zg6CAEyXPR51gpkO1ev9huG7+tsV+mm8me8VNl8hMcVtWl8FA=="],
-
- "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
-
- "pure-rand": ["pure-rand@6.1.0", "", {}, ""],
-
- "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="],
-
- "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, ""],
-
- "readdirp": ["readdirp@4.1.2", "", {}, ""],
-
- "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
-
- "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
-
- "socket.io": ["socket.io@4.8.1", "", { "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" } }, "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg=="],
-
- "socket.io-adapter": ["socket.io-adapter@2.5.5", "", { "dependencies": { "debug": "~4.3.4", "ws": "~8.17.1" } }, "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg=="],
-
- "socket.io-parser": ["socket.io-parser@4.2.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" } }, "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew=="],
-
- "tinyexec": ["tinyexec@1.0.1", "", {}, ""],
-
- "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
-
- "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
-
- "undici-types": ["undici-types@7.12.0", "", {}, ""],
-
- "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
-
- "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
-
- "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
-
- "ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
-
- "zod": ["zod@4.1.11", "", {}, "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg=="],
-
- "@scalar/openapi-types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
-
- "@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
- }
-}
diff --git a/concord-server/migrations/20250927190915_init2finalfinal/migration.sql b/concord-server/migrations/20250927190915_init2finalfinal/migration.sql
deleted file mode 100644
index 6defc25..0000000
--- a/concord-server/migrations/20250927190915_init2finalfinal/migration.sql
+++ /dev/null
@@ -1,131 +0,0 @@
--- CreateTable
-CREATE TABLE "public"."Instance" (
- "id" TEXT NOT NULL,
- "name" TEXT NOT NULL,
- "icon" TEXT,
-
- CONSTRAINT "Instance_pkey" PRIMARY KEY ("id")
-);
-
--- CreateTable
-CREATE TABLE "public"."User" (
- "id" TEXT NOT NULL,
- "username" TEXT NOT NULL,
- "nickname" TEXT,
- "bio" TEXT,
- "picture" TEXT,
- "banner" TEXT,
- "admin" BOOLEAN NOT NULL,
- "status" TEXT NOT NULL,
-
- CONSTRAINT "User_pkey" PRIMARY KEY ("id")
-);
-
--- CreateTable
-CREATE TABLE "public"."Role" (
- "userId" TEXT NOT NULL,
- "instanceId" TEXT NOT NULL,
- "type" TEXT NOT NULL
-);
-
--- CreateTable
-CREATE TABLE "public"."UserAuth" (
- "userId" TEXT NOT NULL,
- "password" TEXT NOT NULL,
- "token" TEXT
-);
-
--- CreateTable
-CREATE TABLE "public"."Category" (
- "id" TEXT NOT NULL,
- "instanceId" TEXT,
- "name" TEXT NOT NULL,
- "position" INTEGER NOT NULL,
-
- CONSTRAINT "Category_pkey" PRIMARY KEY ("id")
-);
-
--- CreateTable
-CREATE TABLE "public"."Channel" (
- "id" TEXT NOT NULL,
- "type" TEXT NOT NULL,
- "categoryId" TEXT,
- "name" TEXT NOT NULL,
- "description" TEXT NOT NULL,
-
- CONSTRAINT "Channel_pkey" PRIMARY KEY ("id")
-);
-
--- CreateTable
-CREATE TABLE "public"."Message" (
- "id" TEXT NOT NULL,
- "channelId" TEXT NOT NULL,
- "userId" TEXT NOT NULL,
- "deleted" BOOLEAN NOT NULL,
- "text" TEXT NOT NULL,
-
- CONSTRAINT "Message_pkey" PRIMARY KEY ("id")
-);
-
--- CreateTable
-CREATE TABLE "public"."Reply" (
- "messageId" TEXT NOT NULL,
- "repliesToId" TEXT NOT NULL
-);
-
--- CreateTable
-CREATE TABLE "public"."MessagePing" (
- "messageId" TEXT NOT NULL,
- "pingsUserId" TEXT NOT NULL
-);
-
--- CreateIndex
-CREATE UNIQUE INDEX "Role_userId_instanceId_key" ON "public"."Role"("userId", "instanceId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "UserAuth_userId_key" ON "public"."UserAuth"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "Reply_messageId_key" ON "public"."Reply"("messageId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "Reply_repliesToId_key" ON "public"."Reply"("repliesToId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "Reply_messageId_repliesToId_key" ON "public"."Reply"("messageId", "repliesToId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "MessagePing_messageId_pingsUserId_key" ON "public"."MessagePing"("messageId", "pingsUserId");
-
--- AddForeignKey
-ALTER TABLE "public"."Role" ADD CONSTRAINT "Role_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Role" ADD CONSTRAINT "Role_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "public"."Instance"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."UserAuth" ADD CONSTRAINT "UserAuth_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Category" ADD CONSTRAINT "Category_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "public"."Instance"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Channel" ADD CONSTRAINT "Channel_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "public"."Category"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Message" ADD CONSTRAINT "Message_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "public"."Channel"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Message" ADD CONSTRAINT "Message_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Reply" ADD CONSTRAINT "Reply_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "public"."Message"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."Reply" ADD CONSTRAINT "Reply_repliesToId_fkey" FOREIGN KEY ("repliesToId") REFERENCES "public"."Message"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."MessagePing" ADD CONSTRAINT "MessagePing_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "public"."Message"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."MessagePing" ADD CONSTRAINT "MessagePing_pingsUserId_fkey" FOREIGN KEY ("pingsUserId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/concord-server/migrations/20250927230554_timestampify/migration.sql b/concord-server/migrations/20250927230554_timestampify/migration.sql
deleted file mode 100644
index 7285123..0000000
--- a/concord-server/migrations/20250927230554_timestampify/migration.sql
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- Warnings:
-
- - Added the required column `updatedAt` to the `Category` table without a default value. This is not possible if the table is not empty.
- - Added the required column `pinnedId` to the `Channel` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `Channel` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `Instance` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `Message` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `Reply` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `Role` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `User` table without a default value. This is not possible if the table is not empty.
- - Added the required column `updatedAt` to the `UserAuth` table without a default value. This is not possible if the table is not empty.
-
-*/
--- AlterTable
-ALTER TABLE "public"."Category" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."Channel" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "pinnedId" TEXT,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."Instance" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."Message" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."MessagePing" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."Reply" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."Role" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."User" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- AlterTable
-ALTER TABLE "public"."UserAuth" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
-ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-
--- CreateTable
-CREATE TABLE "public"."ChannelPin" (
- "messageId" TEXT NOT NULL,
- "channelId" TEXT NOT NULL,
- "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
--- CreateIndex
-CREATE UNIQUE INDEX "ChannelPin_messageId_key" ON "public"."ChannelPin"("messageId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "ChannelPin_channelId_key" ON "public"."ChannelPin"("channelId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "ChannelPin_messageId_channelId_key" ON "public"."ChannelPin"("messageId", "channelId");
-
--- AddForeignKey
-ALTER TABLE "public"."ChannelPin" ADD CONSTRAINT "ChannelPin_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "public"."Message"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-
--- AddForeignKey
-ALTER TABLE "public"."ChannelPin" ADD CONSTRAINT "ChannelPin_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "public"."Channel"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/concord-server/migrations/20250927231139_pinnedidnullable/migration.sql b/concord-server/migrations/20250927231139_pinnedidnullable/migration.sql
deleted file mode 100644
index 4614fa0..0000000
--- a/concord-server/migrations/20250927231139_pinnedidnullable/migration.sql
+++ /dev/null
@@ -1,26 +0,0 @@
--- AlterTable
-ALTER TABLE "public"."Category" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."Channel" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."Channel" ALTER COLUMN "pinnedId" DROP NOT NULL;
-
--- AlterTable
-ALTER TABLE "public"."Instance" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."Message" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."Reply" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."Role" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."User" ALTER COLUMN "updatedAt" DROP DEFAULT;
-
--- AlterTable
-ALTER TABLE "public"."UserAuth" ALTER COLUMN "updatedAt" DROP DEFAULT;
diff --git a/concord-server/migrations/20250928083913_maxchar2000/migration.sql b/concord-server/migrations/20250928083913_maxchar2000/migration.sql
deleted file mode 100644
index 096b66b..0000000
--- a/concord-server/migrations/20250928083913_maxchar2000/migration.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- Warnings:
-
- - You are about to alter the column `text` on the `Message` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(2000)`.
-
-*/
--- AlterTable
-ALTER TABLE "public"."Message" ALTER COLUMN "text" SET DATA TYPE VARCHAR(2000);
diff --git a/concord-server/package-lock.json b/concord-server/package-lock.json
deleted file mode 100644
index cef0762..0000000
--- a/concord-server/package-lock.json
+++ /dev/null
@@ -1,390 +0,0 @@
-{
- "name": "concord-server",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "concord-server",
- "dependencies": {
- "@prisma/client": "^6.16.2",
- "hono": "^4.9.9",
- "prisma": "^6.16.2"
- },
- "devDependencies": {
- "@types/bun": "latest"
- }
- },
- "node_modules/@prisma/client": {
- "version": "6.16.2",
- "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.2.tgz",
- "integrity": "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==",
- "hasInstallScript": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18.18"
- },
- "peerDependencies": {
- "prisma": "*",
- "typescript": ">=5.1.0"
- },
- "peerDependenciesMeta": {
- "prisma": {
- "optional": true
- },
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@prisma/config": {
- "version": "6.16.2",
- "license": "Apache-2.0",
- "dependencies": {
- "c12": "3.1.0",
- "deepmerge-ts": "7.1.5",
- "effect": "3.16.12",
- "empathic": "2.0.0"
- }
- },
- "node_modules/@prisma/debug": {
- "version": "6.16.2",
- "license": "Apache-2.0"
- },
- "node_modules/@prisma/engines": {
- "version": "6.16.2",
- "hasInstallScript": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@prisma/debug": "6.16.2",
- "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
- "@prisma/fetch-engine": "6.16.2",
- "@prisma/get-platform": "6.16.2"
- }
- },
- "node_modules/@prisma/engines-version": {
- "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
- "license": "Apache-2.0"
- },
- "node_modules/@prisma/fetch-engine": {
- "version": "6.16.2",
- "license": "Apache-2.0",
- "dependencies": {
- "@prisma/debug": "6.16.2",
- "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
- "@prisma/get-platform": "6.16.2"
- }
- },
- "node_modules/@prisma/get-platform": {
- "version": "6.16.2",
- "license": "Apache-2.0",
- "dependencies": {
- "@prisma/debug": "6.16.2"
- }
- },
- "node_modules/@standard-schema/spec": {
- "version": "1.0.0",
- "license": "MIT"
- },
- "node_modules/@types/bun": {
- "version": "1.2.22",
- "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.2.22.tgz",
- "integrity": "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "bun-types": "1.2.22"
- }
- },
- "node_modules/@types/node": {
- "version": "24.5.2",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "undici-types": "~7.12.0"
- }
- },
- "node_modules/@types/react": {
- "version": "19.1.14",
- "dev": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "csstype": "^3.0.2"
- }
- },
- "node_modules/bun-types": {
- "version": "1.2.22",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- },
- "peerDependencies": {
- "@types/react": "^19"
- }
- },
- "node_modules/c12": {
- "version": "3.1.0",
- "license": "MIT",
- "dependencies": {
- "chokidar": "^4.0.3",
- "confbox": "^0.2.2",
- "defu": "^6.1.4",
- "dotenv": "^16.6.1",
- "exsolve": "^1.0.7",
- "giget": "^2.0.0",
- "jiti": "^2.4.2",
- "ohash": "^2.0.11",
- "pathe": "^2.0.3",
- "perfect-debounce": "^1.0.0",
- "pkg-types": "^2.2.0",
- "rc9": "^2.1.2"
- },
- "peerDependencies": {
- "magicast": "^0.3.5"
- },
- "peerDependenciesMeta": {
- "magicast": {
- "optional": true
- }
- }
- },
- "node_modules/chokidar": {
- "version": "4.0.3",
- "license": "MIT",
- "dependencies": {
- "readdirp": "^4.0.1"
- },
- "engines": {
- "node": ">= 14.16.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/citty": {
- "version": "0.1.6",
- "license": "MIT",
- "dependencies": {
- "consola": "^3.2.3"
- }
- },
- "node_modules/confbox": {
- "version": "0.2.2",
- "license": "MIT"
- },
- "node_modules/consola": {
- "version": "3.4.2",
- "license": "MIT",
- "engines": {
- "node": "^14.18.0 || >=16.10.0"
- }
- },
- "node_modules/csstype": {
- "version": "3.1.3",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/deepmerge-ts": {
- "version": "7.1.5",
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=16.0.0"
- }
- },
- "node_modules/defu": {
- "version": "6.1.4",
- "license": "MIT"
- },
- "node_modules/destr": {
- "version": "2.0.5",
- "license": "MIT"
- },
- "node_modules/dotenv": {
- "version": "16.6.1",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://dotenvx.com"
- }
- },
- "node_modules/effect": {
- "version": "3.16.12",
- "license": "MIT",
- "dependencies": {
- "@standard-schema/spec": "^1.0.0",
- "fast-check": "^3.23.1"
- }
- },
- "node_modules/empathic": {
- "version": "2.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/exsolve": {
- "version": "1.0.7",
- "license": "MIT"
- },
- "node_modules/fast-check": {
- "version": "3.23.2",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/dubzzz"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/fast-check"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "pure-rand": "^6.1.0"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/giget": {
- "version": "2.0.0",
- "license": "MIT",
- "dependencies": {
- "citty": "^0.1.6",
- "consola": "^3.4.0",
- "defu": "^6.1.4",
- "node-fetch-native": "^1.6.6",
- "nypm": "^0.6.0",
- "pathe": "^2.0.3"
- },
- "bin": {
- "giget": "dist/cli.mjs"
- }
- },
- "node_modules/hono": {
- "version": "4.9.9",
- "license": "MIT",
- "engines": {
- "node": ">=16.9.0"
- }
- },
- "node_modules/jiti": {
- "version": "2.6.0",
- "license": "MIT",
- "bin": {
- "jiti": "lib/jiti-cli.mjs"
- }
- },
- "node_modules/node-fetch-native": {
- "version": "1.6.7",
- "license": "MIT"
- },
- "node_modules/nypm": {
- "version": "0.6.2",
- "license": "MIT",
- "dependencies": {
- "citty": "^0.1.6",
- "consola": "^3.4.2",
- "pathe": "^2.0.3",
- "pkg-types": "^2.3.0",
- "tinyexec": "^1.0.1"
- },
- "bin": {
- "nypm": "dist/cli.mjs"
- },
- "engines": {
- "node": "^14.16.0 || >=16.10.0"
- }
- },
- "node_modules/ohash": {
- "version": "2.0.11",
- "license": "MIT"
- },
- "node_modules/pathe": {
- "version": "2.0.3",
- "license": "MIT"
- },
- "node_modules/perfect-debounce": {
- "version": "1.0.0",
- "license": "MIT"
- },
- "node_modules/pkg-types": {
- "version": "2.3.0",
- "license": "MIT",
- "dependencies": {
- "confbox": "^0.2.2",
- "exsolve": "^1.0.7",
- "pathe": "^2.0.3"
- }
- },
- "node_modules/prisma": {
- "version": "6.16.2",
- "hasInstallScript": true,
- "license": "Apache-2.0",
- "peer": true,
- "dependencies": {
- "@prisma/config": "6.16.2",
- "@prisma/engines": "6.16.2"
- },
- "bin": {
- "prisma": "build/index.js"
- },
- "engines": {
- "node": ">=18.18"
- },
- "peerDependencies": {
- "typescript": ">=5.1.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/pure-rand": {
- "version": "6.1.0",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/dubzzz"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/fast-check"
- }
- ],
- "license": "MIT"
- },
- "node_modules/rc9": {
- "version": "2.1.2",
- "license": "MIT",
- "dependencies": {
- "defu": "^6.1.4",
- "destr": "^2.0.3"
- }
- },
- "node_modules/readdirp": {
- "version": "4.1.2",
- "license": "MIT",
- "engines": {
- "node": ">= 14.18.0"
- },
- "funding": {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/tinyexec": {
- "version": "1.0.1",
- "license": "MIT"
- },
- "node_modules/undici-types": {
- "version": "7.12.0",
- "dev": true,
- "license": "MIT"
- }
- }
-}
diff --git a/concord-server/package.json b/concord-server/package.json
deleted file mode 100644
index fe84cc1..0000000
--- a/concord-server/package.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "concord-server",
- "scripts": {
- "dev": "bun run --hot src/index.ts"
- },
- "dependencies": {
- "@hono/standard-validator": "^0.1.5",
- "@hono/zod-validator": "^0.7.3",
- "@prisma/client": "^6.16.2",
- "@scalar/hono-api-reference": "^0.9.19",
- "@socket.io/bun-engine": "^0.0.3",
- "hono": "^4.9.9",
- "hono-openapi": "^1.1.0",
- "prisma": "^6.16.2",
- "socket.io": "^4.8.1",
- "zod": "^4.1.11"
- },
- "devDependencies": {
- "@types/bun": "latest",
- "prisma-zod-generator": "^1.22.1"
- }
-}
diff --git a/concord-server/schema.prisma b/concord-server/schema.prisma
deleted file mode 100644
index bb689df..0000000
--- a/concord-server/schema.prisma
+++ /dev/null
@@ -1,135 +0,0 @@
-generator client {
- provider = "prisma-client-js"
-}
-
-generator zod {
- provider = "prisma-zod-generator"
-}
-
-datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
-}
-
-model Instance {
- id String @id @default(uuid(7))
- name String
- icon String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- Role Role[]
- Category Category[]
-}
-
-model User {
- id String @id @default(uuid(7))
- username String
- nickname String?
- bio String?
- picture String?
- banner String?
- admin Boolean
- status String // online/offline/dnd/idle/invis
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- Role Role[]
- UserAuth UserAuth?
- Message Message[]
- MessagePing MessagePing[]
-}
-
-model Role {
- User User @relation(fields: [userId], references: [id])
- userId String
- Instance Instance @relation(fields: [instanceId], references: [id])
- instanceId String
- type String
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- @@unique([userId, instanceId])
-}
-
-model UserAuth {
- User User @relation(fields: [userId], references: [id])
- userId String
- password String // HASHED PASSWORD AS STRING USING SHA-256
- token String? // current user token
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- @@unique([userId])
-}
-
-model Category {
- id String @id @default(uuid(7))
- Instance Instance? @relation(fields: [instanceId], references: [id])
- instanceId String?
- name String
- position Int
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- Channel Channel[]
-}
-
-model Channel {
- id String @id @default(uuid(7))
- type String
- Category Category? @relation(fields: [categoryId], references: [id])
- categoryId String?
- name String
- description String
- pinnedId String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- Message Message[]
- ChannelPin ChannelPin?
-}
-
-model ChannelPin {
- messageId String @unique
- channelId String @unique
-
- Message Message @relation(fields: [messageId], references: [id])
- Channel Channel @relation(fields: [channelId], references: [id])
- createdAt DateTime @default(now())
-
- @@unique([messageId, channelId])
-}
-
-model Message {
- id String @id @default(uuid(7))
- Channel Channel @relation(fields: [channelId], references: [id])
- channelId String
- User User @relation(fields: [userId], references: [id])
- userId String
- deleted Boolean
- text String @db.VarChar(2000)
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- replies Reply? @relation("MessageToReply")
- repliedTo Reply? @relation("ReplyToMessage")
- MessagePing MessagePing[]
- ChannelPin ChannelPin?
-}
-
-model Reply {
- message Message @relation("MessageToReply", fields: [messageId], references: [id]) //message text
- messageId String @unique //message id of the reply
- repliesTo Message @relation("ReplyToMessage", fields: [repliesToId], references: [id]) //message id that this message replies to
- repliesToId String @unique //replies to this message id
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- @@unique([messageId, repliesToId])
-}
-
-model MessagePing {
- Message Message @relation(fields: [messageId], references: [id])
- messageId String
- PingsUser User @relation(fields: [pingsUserId], references: [id])
- pingsUserId String
- createdAt DateTime @default(now())
-
- @@unique([messageId, pingsUserId])
-}
diff --git a/concord-server/src/controller/categoryController.ts b/concord-server/src/controller/categoryController.ts
deleted file mode 100644
index c2b5a1b..0000000
--- a/concord-server/src/controller/categoryController.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import {
- createCategory,
- getCategory,
- getCategoriesByInstance,
- updateCategory,
- deleteCategory,
- deleteAllCategoriesFromInstance,
-} from "../services/channelService";
-import {
- CreateCategoryInput,
- UpdateCategoryInput,
- DeleteCategoryInput,
- DeleteCategoriesByInstanceIdInput,
-} from "../validators/categoryValidator";
-
-export async function createNewCategory(data: CreateCategoryInput) {
- return await createCategory(data);
-}
-
-export async function fetchCategoryData(id: string) {
- return await getCategory(id);
-}
-
-export async function fetchCategoriesByInstance(instanceId: string) {
- return await getCategoriesByInstance(instanceId);
-}
-
-export async function updateExistingCategory(data: UpdateCategoryInput) {
- return await updateCategory(data);
-}
-
-export async function deleteExistingCategory(data: DeleteCategoryInput) {
- return await deleteCategory(data);
-}
-
-export async function deleteAllCategoriesByInstance(
- data: DeleteCategoriesByInstanceIdInput,
-) {
- return await deleteAllCategoriesFromInstance(data);
-}
diff --git a/concord-server/src/controller/channelController.ts b/concord-server/src/controller/channelController.ts
deleted file mode 100644
index 1c09a84..0000000
--- a/concord-server/src/controller/channelController.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import {
- createChannel,
- getChannel,
- getChannelsByCategory,
- updateChannel,
- deleteChannel,
- deleteAllChannelsFromCategory,
-} from "../services/channelService";
-import {
- CreateChannelInput,
- UpdateChannelInput,
- DeleteChannelInput,
- DeleteChannelsByCategoryIdInput,
-} from "../validators/channelValidator";
-
-export async function createNewChannel(data: CreateChannelInput) {
- return await createChannel(data);
-}
-
-export async function fetchChannelData(id: string) {
- return await getChannel(id);
-}
-
-export async function fetchChannelsByCategory(categoryId: string) {
- return await getChannelsByCategory(categoryId);
-}
-
-export async function updateExistingChannel(data: UpdateChannelInput) {
- return await updateChannel(data);
-}
-
-export async function deleteExistingChannel(data: DeleteChannelInput) {
- return await deleteChannel(data);
-}
-
-export async function deleteAllChannelsByCategory(
- data: DeleteChannelsByCategoryIdInput,
-) {
- return await deleteAllChannelsFromCategory(data);
-}
diff --git a/concord-server/src/controller/instanceController.ts b/concord-server/src/controller/instanceController.ts
deleted file mode 100644
index a586e35..0000000
--- a/concord-server/src/controller/instanceController.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createInstance, getAllInstances } from "../services/instanceService";
-import { CreateInstanceRequest } from "../validators/instanceValidator";
-
-export async function createInstanceReq(data: CreateInstanceRequest) {
- return await createInstance(data);
-}
-
-export async function getAllInstancesReq() {
- return await getAllInstances();
-}
diff --git a/concord-server/src/controller/messageController.ts b/concord-server/src/controller/messageController.ts
deleted file mode 100644
index dc9f2da..0000000
--- a/concord-server/src/controller/messageController.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- editMessage,
- getMessageInformation,
- getMessagesBefore,
- sendMessageToChannel,
-} from "../services/messageService";
-import { PutMessage } from "../validators/messageValidator";
-
-export async function fetchMessageData(id: string) {
- return await getMessageInformation(id);
-}
-
-export async function fetchMessagesBefore(date: string, channelId: string) {
- return getMessagesBefore(date, channelId);
-}
-
-export async function sendMessage(
- channelId: string,
- userId: string,
- content: string,
- token: string,
- repliedMessageId: string | null,
-) {
- return await sendMessageToChannel(
- channelId,
- userId,
- content,
- token,
- repliedMessageId,
- );
-}
-
-export async function putMessage(data: PutMessage) {
- return await editMessage(data);
-}
diff --git a/concord-server/src/controller/userController.ts b/concord-server/src/controller/userController.ts
deleted file mode 100644
index 9bf4acc..0000000
--- a/concord-server/src/controller/userController.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import {
- getAllUsersFrom,
- getUserInformation,
- createUser,
- getUserId,
-} from "../services/userService";
-import { CreateUserInput } from "../validators/userValidator";
-
-export async function fetchUserData(id: string) {
- return await getUserInformation(id);
-}
-
-export async function fetchAllUsers(instanceId: string) {
- return await getAllUsersFrom(instanceId);
-}
-
-export async function createNewUser(data: CreateUserInput) {
- return await createUser(data);
-}
-
-export async function fetchUserId(username: string) {
- return await getUserId(username);
-}
diff --git a/concord-server/src/helper/hashing.ts b/concord-server/src/helper/hashing.ts
deleted file mode 100644
index d987684..0000000
--- a/concord-server/src/helper/hashing.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as crypto from "crypto";
-
-export default function shaHash(data: string, salt: string): string {
- return crypto.createHmac("sha256", salt).update(data).digest("hex");
-}
diff --git a/concord-server/src/index.ts b/concord-server/src/index.ts
deleted file mode 100644
index 3412191..0000000
--- a/concord-server/src/index.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import { Hono } from "hono";
-import { cors } from "hono/cors";
-import { Server as Engine } from "@socket.io/bun-engine";
-import { Server } from "socket.io";
-import routes from "./routes/index";
-import { Scalar } from "@scalar/hono-api-reference";
-import { openAPIRouteHandler } from "hono-openapi";
-import { registerSocketHandlers } from "./sockets";
-
-// Routes
-const app = new Hono();
-
-app.use(
- "*",
- cors({
- origin: ["http://localhost:5173", "https://concord.kpuig.net", "http://localhost:3000"],
- allowHeaders: [
- "Content-Type",
- "Authorization",
- "Access-Control-Allow-Origin",
- ],
- allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
- credentials: true,
- }),
-);
-
-app.route("/api", routes);
-
-app.get(
- "/openapi",
- openAPIRouteHandler(app, {
- documentation: {
- info: {
- title: "Hono API",
- version: "1.0.0",
- description: "Greeting API",
- },
- servers: [{ url: "http://localhost:3000", description: "Local Server" }],
- },
- }),
-);
-
-app.get("/scalar", Scalar({ url: "/openapi" }));
-
-// initialize socket.io server
-const io = new Server({
- cors: {
- origin: ["http://localhost:5173", "https://concord.kpuig.net", "http://localhost:3000"],
- credentials: true,
- },
-});
-const engine = new Engine();
-io.bind(engine);
-
-// Register socket.io events
-registerSocketHandlers(io);
-
-const { websocket } = engine.handler();
-
-export default {
- port: 3000,
- idleTimeout: 30, // must be greater than the "pingInterval" option of the engine, which defaults to 25 seconds
-
- async fetch(req: Request, server: Bun.Server) {
- const url = new URL(req.url);
-
- if (url.pathname === "/socket.io/") {
- const response = await engine.handleRequest(req, server);
- // Add CORS headers explicitly
- const origin = req.headers.get("Origin");
- if (
- origin &&
- ["http://localhost:5173", "https://concord.kpuig.net", "http://localhost:3000"].includes(origin)
- ) {
- response.headers.set("Access-Control-Allow-Origin", origin);
- }
- response.headers.set("Access-Control-Allow-Credentials", "true");
- return response;
- } else {
- return app.fetch(req, server);
- }
- },
-
- websocket,
-};
diff --git a/concord-server/src/routes/authRoutes.ts b/concord-server/src/routes/authRoutes.ts
deleted file mode 100644
index e611eba..0000000
--- a/concord-server/src/routes/authRoutes.ts
+++ /dev/null
@@ -1,239 +0,0 @@
-import { Hono } from "hono";
-import { zValidator } from "@hono/zod-validator";
-import { describeRoute, resolver } from "hono-openapi";
-import {
- getUserCredentials,
- getUserId,
- getUserInformation,
-} from "../services/userService";
-import shaHash from "../helper/hashing";
-import { PrismaClient } from "@prisma/client";
-import {
- loginSchema,
- validateTokenSchema,
- refreshTokenSchema,
- logoutSchema,
- authResponseSchema,
- validationResponseSchema,
- errorResponseSchema,
- successResponseSchema,
-} from "../validators/authValidator";
-
-const prisma = new PrismaClient();
-const authRoutes = new Hono();
-
-// Login endpoint
-authRoutes.post(
- "/login",
- describeRoute({
- description: "User login",
- responses: {
- 200: {
- description: "Login successful",
- content: {
- "application/json": { schema: resolver(authResponseSchema) },
- },
- },
- 401: {
- description: "Invalid credentials",
- content: {
- "application/json": { schema: resolver(errorResponseSchema) },
- },
- },
- },
- }),
- zValidator("json", loginSchema),
- async (c) => {
- try {
- const { username, password } = await c.req.json();
- console.log(c.req.json);
-
- // Find user by username
- const user = await prisma.user.findFirst({
- where: { username: username },
- });
-
- if (!user) {
- return c.json({ error: "Invalid username or password" }, 401);
- }
-
- // get userId
- const userIdResult = await getUserId(username);
- if (!userIdResult) {
- return c.json({ error: "Invalid username or password" }, 401);
- }
-
- const userId = userIdResult.userId;
-
- // get user creds
- const userCredentials = await getUserCredentials(userId);
- if (!userCredentials) {
- return c.json({ error: "Invalid username or password" }, 401);
- }
-
- // hash the provided password with user ID as salt
- const hashedPassword = shaHash(password, userId);
-
- // verify password
- if (hashedPassword !== userCredentials.password) {
- return c.json({ error: "Invalid username or password" }, 401);
- }
-
- // generate new token
- const token = crypto.randomUUID();
-
- // Update user's token in database
- await prisma.userAuth.update({
- where: { userId: user.id },
- data: { token: token },
- });
-
- // get full user information
- const userInfo = await getUserInformation(user.id);
- if (!userInfo) {
- return c.json({ error: "Failed to get user information" }, 500);
- }
-
- return c.json({
- user: userInfo,
- token: token,
- });
- } catch (error) {
- console.error("Login error:", error);
- return c.json({ error: "Internal server error" }, 500);
- }
- },
-);
-
-// Token validation endpoint
-authRoutes.post(
- "/validate",
- describeRoute({
- description: "Validate user token",
- responses: {
- 200: {
- description: "Token validation result",
- content: {
- "application/json": { schema: resolver(validationResponseSchema) },
- },
- },
- },
- }),
- zValidator("json", validateTokenSchema),
- async (c) => {
- try {
- const { token, userId } = await c.req.json();
-
- // Get user credentials
- const userCredentials = await getUserCredentials(userId);
- if (!userCredentials || userCredentials.token !== token) {
- return c.json({ valid: false });
- }
-
- // Get user information
- const userInfo = await getUserInformation(userId);
- if (!userInfo) {
- return c.json({ valid: false });
- }
-
- return c.json({
- valid: true,
- user: userInfo,
- });
- } catch (error) {
- return c.json({ valid: false });
- }
- },
-);
-
-// Token refresh endpoint
-authRoutes.post(
- "/refresh",
- describeRoute({
- description: "Refresh user token",
- responses: {
- 200: {
- description: "Token refreshed successfully",
- content: {
- "application/json": { schema: resolver(authResponseSchema) },
- },
- },
- 401: {
- description: "Invalid token",
- content: {
- "application/json": { schema: resolver(errorResponseSchema) },
- },
- },
- },
- }),
- zValidator("json", refreshTokenSchema),
- async (c) => {
- try {
- const { userId, oldToken } = await c.req.json();
-
- // Verify old token
- const userCredentials = await getUserCredentials(userId);
- if (!userCredentials || userCredentials.token !== oldToken) {
- return c.json({ error: "Invalid token" }, 401);
- }
-
- // Generate new token
- const newToken = crypto.randomUUID();
-
- // Update token in database
- await prisma.userAuth.update({
- where: { userId: userId },
- data: { token: newToken },
- });
-
- // Get user information
- const userInfo = await getUserInformation(userId);
- if (!userInfo) {
- return c.json({ error: "Failed to get user information" }, 500);
- }
-
- return c.json({
- user: userInfo,
- token: newToken,
- });
- } catch (error) {
- console.error("Token refresh error:", error);
- return c.json({ error: "Internal server error" }, 500);
- }
- },
-);
-
-// Logout endpoint (invalidate token)
-authRoutes.post(
- "/logout",
- describeRoute({
- description: "User logout",
- responses: {
- 200: {
- description: "Logout successful",
- content: {
- "application/json": { schema: resolver(successResponseSchema) },
- },
- },
- },
- }),
- zValidator("json", logoutSchema),
- async (c) => {
- try {
- const { userId } = await c.req.json();
-
- // Clear token in database
- await prisma.userAuth.update({
- where: { userId: userId },
- data: { token: null },
- });
-
- return c.json({ success: true });
- } catch (error) {
- console.error("Logout error:", error);
- return c.json({ error: "Internal server error" }, 500);
- }
- },
-);
-
-export default authRoutes;
diff --git a/concord-server/src/routes/categoryRoutes.ts b/concord-server/src/routes/categoryRoutes.ts
deleted file mode 100644
index 9b48532..0000000
--- a/concord-server/src/routes/categoryRoutes.ts
+++ /dev/null
@@ -1,315 +0,0 @@
-import {
- createNewCategory,
- fetchCategoryData,
- fetchCategoriesByInstance,
- updateExistingCategory,
- deleteExistingCategory,
- deleteAllCategoriesByInstance,
-} from "../controller/categoryController";
-
-import {
- createCategorySchema,
- getCategorySchema,
- getCategoriesByInstanceIdSchema,
- updateCategorySchema,
- deleteCategorySchema,
- deleteCategoriesByInstanceIdSchema,
- CreateCategoryInput,
- GetCategoryInput,
- GetCategoriesByInstanceIdInput,
- UpdateCategoryInput,
- DeleteCategoryInput,
- DeleteCategoriesByInstanceIdInput,
-} from "../validators/categoryValidator";
-import { zValidator } from "@hono/zod-validator";
-import { Hono } from "hono";
-import { describeRoute, resolver } from "hono-openapi";
-const categoryRoutes = new Hono();
-
-// Create a new category
-categoryRoutes.post(
- "/",
- describeRoute({
- description: "Create a new category",
- responses: {
- 200: {
- description: "Success creating category",
- content: {
- "application/json": { schema: resolver(createCategorySchema) },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": { schema: resolver(createCategorySchema) },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": { schema: resolver(createCategorySchema) },
- },
- },
- 404: {
- description: "User Id not found",
- content: {
- "application/json": { schema: resolver(createCategorySchema) },
- },
- },
- },
- }),
- zValidator("json", createCategorySchema),
- async (c) => {
- const data = c.req.valid("json") as CreateCategoryInput;
- const categoryData = await createNewCategory(data);
- if (categoryData) {
- return c.json(categoryData);
- } else {
- return c.json({ error: "Failed to create category" }, 400);
- }
- },
-);
-
-// Get a category by ID
-categoryRoutes.get(
- "/:id",
- describeRoute({
- description: "Get category by id",
- responses: {
- 200: {
- description: "Success getting category",
- content: {
- "application/json": { schema: resolver(getCategorySchema) },
- },
- },
- 404: {
- description: "Category id not found",
- content: {
- "application/json": { schema: resolver(getCategorySchema) },
- },
- },
- },
- }),
- async (c) => {
- const id = c.req.param("id");
- const categoryData = await fetchCategoryData(id);
- if (categoryData) {
- return c.json(categoryData);
- } else {
- return c.json({ error: "Category not found" }, 404);
- }
- },
-);
-
-// Get all categories by instance ID
-categoryRoutes.get(
- "/instance/:instanceId",
- describeRoute({
- description: "Get all categories by instance id",
- responses: {
- 200: {
- description: "Success getting all categories in instance",
- content: {
- "application/json": {
- schema: resolver(getCategoriesByInstanceIdSchema),
- },
- },
- },
- 400: {
- description: "Bad Request - Missing instance ID",
- content: {
- "application/json": {
- schema: resolver(getCategoriesByInstanceIdSchema),
- },
- },
- },
- },
- }),
- async (c) => {
- const instanceId = c.req.param("instanceId");
- if (!instanceId) {
- return c.json({ error: "No instance id provided" }, 400);
- }
-
- const categoryData = await fetchCategoriesByInstance(instanceId);
- if (categoryData) {
- return c.json(categoryData);
- } else {
- return c.json(
- { error: "Error getting all categories from instance" },
- 500,
- );
- }
- },
-);
-
-// Update a category
-categoryRoutes.put(
- "/:id",
- describeRoute({
- description: "Update an existing category",
- responses: {
- 200: {
- description: "Success updating category",
- content: {
- "application/json": { schema: resolver(updateCategorySchema) },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": { schema: resolver(updateCategorySchema) },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": { schema: resolver(updateCategorySchema) },
- },
- },
- 404: {
- description: "Category id or User Id not found",
- content: {
- "application/json": { schema: resolver(updateCategorySchema) },
- },
- },
- },
- }),
- zValidator("json", updateCategorySchema),
- async (c) => {
- const id = c.req.param("id");
- const data = c.req.valid("json") as UpdateCategoryInput;
-
- // Ensure the ID in the path matches the one in the body
- if (data.id && data.id !== id) {
- return c.json({ error: "ID in path does not match ID in body" }, 400);
- }
-
- // Set ID from path if not in body
- if (!data.id) {
- data.id = id;
- }
-
- const categoryData = await updateExistingCategory(data);
- if (categoryData) {
- return c.json(categoryData);
- } else {
- return c.json({ error: "Failed to update category" }, 400);
- }
- },
-);
-
-// Delete a specific category
-categoryRoutes.delete(
- "/:id",
- describeRoute({
- description: "Delete an existing category",
- responses: {
- 200: {
- description: "Success deleting category",
- content: {
- "application/json": { schema: resolver(deleteCategorySchema) },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": { schema: resolver(deleteCategorySchema) },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": { schema: resolver(deleteCategorySchema) },
- },
- },
- 404: {
- description: "Category id or User Id not found",
- content: {
- "application/json": { schema: resolver(deleteCategorySchema) },
- },
- },
- },
- }),
- zValidator("json", deleteCategorySchema),
- async (c) => {
- const id = c.req.param("id");
- const data = c.req.valid("json") as DeleteCategoryInput;
-
- // Ensure the ID in the path matches the one in the body
- if (data.id !== id) {
- return c.json({ error: "ID in path does not match ID in body" }, 400);
- }
-
- const categoryData = await deleteExistingCategory(data);
- if (categoryData) {
- return c.json(categoryData);
- } else {
- return c.json({ error: "Failed to delete category" }, 400);
- }
- },
-);
-
-// Delete all categories by instance ID
-categoryRoutes.delete(
- "/instance/:instanceId",
- describeRoute({
- description: "Delete all categories by instance id",
- responses: {
- 200: {
- description: "Success deleting all categories in instance",
- content: {
- "application/json": {
- schema: resolver(deleteCategoriesByInstanceIdSchema),
- },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": {
- schema: resolver(deleteCategoriesByInstanceIdSchema),
- },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": {
- schema: resolver(deleteCategoriesByInstanceIdSchema),
- },
- },
- },
- 404: {
- description: "Instance id or User Id not found",
- content: {
- "application/json": {
- schema: resolver(deleteCategoriesByInstanceIdSchema),
- },
- },
- },
- },
- }),
- zValidator("json", deleteCategoriesByInstanceIdSchema),
- async (c) => {
- const instanceId = c.req.param("instanceId");
- const data = c.req.valid("json") as DeleteCategoriesByInstanceIdInput;
-
- // Ensure the instanceId in the path matches the one in the body
- if (data.instanceId !== instanceId) {
- return c.json(
- { error: "Instance ID in path does not match Instance ID in body" },
- 400,
- );
- }
-
- const categoryData = await deleteAllCategoriesByInstance(data);
- if (categoryData) {
- return c.json(categoryData);
- } else {
- return c.json({ error: "Failed to delete categories" }, 400);
- }
- },
-);
-
-export { categoryRoutes };
diff --git a/concord-server/src/routes/channelRoutes.ts b/concord-server/src/routes/channelRoutes.ts
deleted file mode 100644
index 43f38ad..0000000
--- a/concord-server/src/routes/channelRoutes.ts
+++ /dev/null
@@ -1,313 +0,0 @@
-import {
- createNewChannel,
- fetchChannelData,
- fetchChannelsByCategory,
- updateExistingChannel,
- deleteExistingChannel,
- deleteAllChannelsByCategory,
-} from "../controller/channelController";
-
-import {
- createChannelSchema,
- getChannelSchema,
- getChannelsByCategoryIdSchema,
- updateChannelSchema,
- deleteChannelSchema,
- deleteChannelsByCategoryIdSchema,
- CreateChannelInput,
- GetChannelInput,
- GetChannelsByCategoryIdInput,
- UpdateChannelInput,
- DeleteChannelInput,
- DeleteChannelsByCategoryIdInput,
-} from "../validators/channelValidator";
-import { zValidator } from "@hono/zod-validator";
-import { Hono } from "hono";
-import { describeRoute, resolver } from "hono-openapi";
-
-const channelRoutes = new Hono();
-
-// Create a new channel
-channelRoutes.post(
- "/",
- describeRoute({
- description: "Create a new channel",
- responses: {
- 200: {
- description: "Success creating channel",
- content: {
- "application/json": { schema: resolver(createChannelSchema) },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": { schema: resolver(createChannelSchema) },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": { schema: resolver(createChannelSchema) },
- },
- },
- 404: {
- description: "User Id not found",
- content: {
- "application/json": { schema: resolver(createChannelSchema) },
- },
- },
- },
- }),
- zValidator("json", createChannelSchema),
- async (c) => {
- const data = c.req.valid("json") as CreateChannelInput;
- const channelData = await createNewChannel(data);
- if (channelData) {
- return c.json(channelData);
- } else {
- return c.json({ error: "Failed to create channel" }, 400);
- }
- },
-);
-
-// Get a channel by ID
-channelRoutes.get(
- "/:id",
- describeRoute({
- description: "Get channel by id",
- responses: {
- 200: {
- description: "Success getting channel",
- content: {
- "application/json": { schema: resolver(getChannelSchema) },
- },
- },
- 404: {
- description: "Channel id not found",
- content: {
- "application/json": { schema: resolver(getChannelSchema) },
- },
- },
- },
- }),
- async (c) => {
- const id = c.req.param("id");
- const channelData = await fetchChannelData(id);
- if (channelData) {
- return c.json(channelData);
- } else {
- return c.json({ error: "Channel not found" }, 404);
- }
- },
-);
-
-// Get all channels by category ID
-channelRoutes.get(
- "/category/:categoryId",
- describeRoute({
- description: "Get all channels by category id",
- responses: {
- 200: {
- description: "Success getting all channels in category",
- content: {
- "application/json": {
- schema: resolver(getChannelsByCategoryIdSchema),
- },
- },
- },
- 400: {
- description: "Bad Request - Missing category ID",
- content: {
- "application/json": {
- schema: resolver(getChannelsByCategoryIdSchema),
- },
- },
- },
- },
- }),
- async (c) => {
- const categoryId = c.req.param("categoryId");
- if (!categoryId) {
- return c.json({ error: "No category id provided" }, 400);
- }
-
- const channels = await fetchChannelsByCategory(categoryId);
- if (channels) {
- return c.json(channels);
- } else {
- return c.json({ error: "Error getting channels from category" }, 500);
- }
- },
-);
-
-// Update a channel
-channelRoutes.put(
- "/:id",
- describeRoute({
- description: "Update an existing channel",
- responses: {
- 200: {
- description: "Success updating channel",
- content: {
- "application/json": { schema: resolver(updateChannelSchema) },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": { schema: resolver(updateChannelSchema) },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": { schema: resolver(updateChannelSchema) },
- },
- },
- 404: {
- description: "Channel id or User Id not found",
- content: {
- "application/json": { schema: resolver(updateChannelSchema) },
- },
- },
- },
- }),
- zValidator("json", updateChannelSchema),
- async (c) => {
- const id = c.req.param("id");
- const data = c.req.valid("json") as UpdateChannelInput;
-
- // Ensure the ID in the path matches the one in the body
- if (data.id && data.id !== id) {
- return c.json({ error: "ID in path does not match ID in body" }, 400);
- }
-
- // Set ID from path if not in body
- if (!data.id) {
- data.id = id;
- }
-
- const result = await updateExistingChannel(data);
- if (result) {
- return c.json(result);
- } else {
- return c.json({ error: "Failed to update channel" }, 400);
- }
- },
-);
-
-// Delete a specific channel
-channelRoutes.delete(
- "/:id",
- describeRoute({
- description: "Delete an existing channel",
- responses: {
- 200: {
- description: "Success deleting channel",
- content: {
- "application/json": { schema: resolver(deleteChannelSchema) },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": { schema: resolver(deleteChannelSchema) },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": { schema: resolver(deleteChannelSchema) },
- },
- },
- 404: {
- description: "Channel id or User Id not found",
- content: {
- "application/json": { schema: resolver(deleteChannelSchema) },
- },
- },
- },
- }),
- zValidator("json", deleteChannelSchema),
- async (c) => {
- const id = c.req.param("id");
- const data = c.req.valid("json") as DeleteChannelInput;
-
- // Ensure the ID in the path matches the one in the body
- if (data.id !== id) {
- return c.json({ error: "ID in path does not match ID in body" }, 400);
- }
-
- const result = await deleteExistingChannel(data);
- if (result) {
- return c.json({ success: true });
- } else {
- return c.json({ error: "Failed to delete channel" }, 400);
- }
- },
-);
-
-// Delete all channels by category ID
-channelRoutes.delete(
- "/category/:categoryId",
- describeRoute({
- description: "Delete all channels by category id",
- responses: {
- 200: {
- description: "Success deleting all channels in category",
- content: {
- "application/json": {
- schema: resolver(deleteChannelsByCategoryIdSchema),
- },
- },
- },
- 400: {
- description: "Bad Request - Invalid input data",
- content: {
- "application/json": {
- schema: resolver(deleteChannelsByCategoryIdSchema),
- },
- },
- },
- 401: {
- description: "Unauthorized - Admin access required",
- content: {
- "application/json": {
- schema: resolver(deleteChannelsByCategoryIdSchema),
- },
- },
- },
- 404: {
- description: "Category id or User Id not found",
- content: {
- "application/json": {
- schema: resolver(deleteChannelsByCategoryIdSchema),
- },
- },
- },
- },
- }),
- zValidator("json", deleteChannelsByCategoryIdSchema),
- async (c) => {
- const categoryId = c.req.param("categoryId");
- const data = c.req.valid("json") as DeleteChannelsByCategoryIdInput;
-
- // Ensure the categoryId in the path matches the one in the body
- if (data.categoryId !== categoryId) {
- return c.json(
- { error: "Category ID in path does not match Category ID in body" },
- 400,
- );
- }
-
- const result = await deleteAllChannelsByCategory(data);
- if (result) {
- return c.json({ success: true });
- } else {
- return c.json({ error: "Failed to delete channels" }, 400);
- }
- },
-);
-
-export { channelRoutes };
diff --git a/concord-server/src/routes/index.ts b/concord-server/src/routes/index.ts
deleted file mode 100644
index 53b4ddd..0000000
--- a/concord-server/src/routes/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-//place exported routes below this line
-import { Hono } from "hono";
-import userRoutes from "./userRoutes";
-import messageRoutes from "./messageRoutes";
-import { channelRoutes } from "./channelRoutes";
-import instanceRoutes from "./instanceRoutes";
-import { categoryRoutes } from "./categoryRoutes";
-import authRoutes from "./authRoutes";
-
-const routes = new Hono();
-
-routes.route("/user", userRoutes);
-routes.route("/message", messageRoutes);
-routes.route("/channel", channelRoutes);
-routes.route("/instance", instanceRoutes);
-routes.route("/category", categoryRoutes);
-routes.route("/auth", authRoutes);
-
-export default routes;
diff --git a/concord-server/src/routes/instanceRoutes.ts b/concord-server/src/routes/instanceRoutes.ts
deleted file mode 100644
index 4e27d75..0000000
--- a/concord-server/src/routes/instanceRoutes.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { Hono } from "hono";
-import { describeRoute, resolver } from "hono-openapi";
-import {
- createInstanceRequestSchema,
- getAllInstancesResponseSchema,
-} from "../validators/instanceValidator";
-import { zValidator } from "@hono/zod-validator";
-import {
- createInstanceReq,
- getAllInstancesReq,
-} from "../controller/instanceController";
-
-const instanceRoutes = new Hono();
-
-instanceRoutes.post(
- "",
- describeRoute({
- description: "Create instance",
- responses: {
- 200: {
- description: "Instance created",
- content: {
- "application/json": { schema: resolver(createInstanceRequestSchema) },
- },
- },
- 400: {
- description: "Invalid request",
- },
- },
- }),
- zValidator("json", createInstanceRequestSchema),
- async (c) => {
- const data = await c.req.json();
- if (!data) {
- return c.json({ error: "could not parse data" }, 400);
- }
-
- const instance = await createInstanceReq(data);
- return c.json(instance, 201);
- },
-);
-
-instanceRoutes.get(
- "",
- describeRoute({
- description: "Get all instances",
- responses: {
- 200: {
- description: "List of all instances",
- content: {
- "application/json": {
- schema: resolver(getAllInstancesResponseSchema),
- },
- },
- },
- 500: {
- description: "Server error",
- },
- },
- }),
- async (c) => {
- const instances = await getAllInstancesReq();
- if (instances.success) {
- return c.json(instances, 200);
- } else {
- return c.json(
- {
- success: false,
- error: instances.error || "Failed to fetch instances",
- },
- 500,
- );
- }
- },
-);
-
-export default instanceRoutes;
diff --git a/concord-server/src/routes/messageRoutes.ts b/concord-server/src/routes/messageRoutes.ts
deleted file mode 100644
index 15c1765..0000000
--- a/concord-server/src/routes/messageRoutes.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import { Hono } from "hono";
-import { describeResponse, describeRoute, resolver } from "hono-openapi";
-import {
- getMessageByIdSchema,
- getMessagesBeforeDate,
- sendMessageSchema,
-} from "../validators/messageValidator";
-import { zValidator } from "@hono/zod-validator";
-import {
- fetchMessageData,
- fetchMessagesBefore,
- sendMessage,
-} from "../controller/messageController";
-
-const messageRoutes = new Hono();
-
-messageRoutes.get(
- "/:id",
- describeRoute({
- description: "Get message by id",
- responses: {
- 200: {
- description: "Success getting message",
- content: {
- "application/json": { schema: resolver(getMessageByIdSchema) },
- },
- },
- 404: {
- description: "Message id not found",
- content: {
- "application/json": { schema: resolver(getMessageByIdSchema) },
- },
- },
- },
- }),
- zValidator("param", getMessageByIdSchema),
- async (c) => {
- const id = c.req.param("id");
- const messageData = await fetchMessageData(id);
-
- if (messageData) {
- return c.json(messageData, 200);
- } else {
- return c.json({ error: "Message not found" }, 404);
- }
- },
-);
-
-messageRoutes.get(
- "",
- describeRoute({
- description: "Get up to 50 messages prior to given datetime",
- responses: {
- 200: {
- description: "Success getting up to 50 messages",
- content: {
- "application/json": { schema: resolver(getMessagesBeforeDate) },
- },
- },
- },
- }),
- zValidator("query", getMessagesBeforeDate),
- async (c) => {
- const date = c.req.query("date");
- if (!date) {
- return c.json({ error: "date not provided" }, 400);
- }
-
- const channelId = c.req.query("channelId");
- if (!channelId) {
- return c.json({ error: "channelId not provided" }, 400);
- }
-
- const messagesArr = await fetchMessagesBefore(date, channelId);
-
- if (messagesArr) {
- return c.json(messagesArr, 200);
- } else {
- return c.json({ error: "Failed to fetch messages" }, 500);
- }
- },
-);
-
-messageRoutes.put(
- "/:id",
- describeRoute({
- description: "Edit message fields",
- responses: {
- 200: {
- description: "Success"
- },
- 404: {
- description: "Message not found"
- },
- 500: {
- description: "Bad request"
- }
- }
- }),
- zValidator("json", sendMessageSchema),
- async (c) => {
-
- }
-)
-
-messageRoutes.post(
- "",
- describeRoute({
- description: "Send a message to a channel",
- responses: {
- 201: {
- description: "Message sent successfully",
- content: {
- "application/json": { schema: resolver(sendMessageSchema) },
- },
- },
- 401: {
- description: "Unauthorized - invalid token or user credentials",
- content: {
- "application/json": {
- schema: {
- type: "object",
- properties: { error: { type: "string" } },
- },
- },
- },
- },
- 500: {
- description: "Server error",
- content: {
- "application/json": {
- schema: {
- type: "object",
- properties: { error: { type: "string" } },
- },
- },
- },
- },
- },
- }),
- zValidator("json", sendMessageSchema),
- async (c) => {
- const { channelId, userId, content, token, repliedMessageId } =
- await c.req.json();
-
- const result = await sendMessage(
- channelId,
- userId,
- content,
- token,
- repliedMessageId || null,
- );
-
- if (result) {
- return c.json(result, 201);
- } else {
- return c.json(
- {
- error:
- "Failed to send message. Check your credentials and try again.",
- },
- 401,
- );
- }
- },
-);
-
-export default messageRoutes;
diff --git a/concord-server/src/routes/userRoutes.ts b/concord-server/src/routes/userRoutes.ts
deleted file mode 100644
index 9c7ef2f..0000000
--- a/concord-server/src/routes/userRoutes.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import { Hono } from "hono";
-import {
- fetchAllUsers,
- fetchUserData,
- createNewUser,
- fetchUserId,
-} from "../controller/userController";
-import {
- createUserSchema,
- queryAllUsersByInstanceId,
- queryUserByIdSchema,
- queryUserByUsernameSchema,
-} from "../validators/userValidator";
-import { zValidator } from "@hono/zod-validator";
-import { describeRoute, resolver } from "hono-openapi";
-const userRoutes = new Hono();
-
-userRoutes.get(
- "/username/:username",
- describeRoute({
- description: "Get userId by username",
- responses: {
- 200: {
- description: "Success getting userId",
- content: {
- "application/json": { schema: resolver(queryUserByUsernameSchema) },
- },
- },
- 404: {
- description: "userId not found",
- content: {
- "application/json": { schema: resolver(queryUserByUsernameSchema) },
- },
- },
- },
- }),
- zValidator("param", queryUserByUsernameSchema),
- async (c) => {
- const username = c.req.param("username");
- const userId = await fetchUserId(username);
- if (userId) {
- return c.json(userId);
- } else {
- return c.json({ error: "User not found" }, 404);
- }
- },
-);
-
-userRoutes.get(
- "/:id",
- describeRoute({
- description: "Get user by id",
- responses: {
- 200: {
- description: "Success getting user",
- content: {
- "application/json": { schema: resolver(queryUserByIdSchema) },
- },
- },
- 404: {
- description: "User id not found",
- content: {
- "application/json": { schema: resolver(queryUserByIdSchema) },
- },
- },
- },
- }),
- zValidator("param", queryUserByIdSchema),
- async (c) => {
- const id = c.req.param("id");
- const userData = await fetchUserData(id);
- if (userData) {
- return c.json(userData);
- } else {
- return c.json({ error: "User not found" }, 404);
- }
- },
-);
-
-userRoutes.get(
- "",
- describeRoute({
- description: "Get all users by instance id",
- responses: {
- 200: {
- description: "Success getting all users in instance",
- content: {
- "application/json": { schema: resolver(queryAllUsersByInstanceId) },
- },
- },
- },
- }),
- zValidator("query", queryAllUsersByInstanceId),
- async (c) => {
- const instanceId = c.req.query("instanceId");
- if (!instanceId) {
- return c.json({ error: "No instance id provided" }, 400);
- }
-
- const userData = await fetchAllUsers(instanceId);
- if (userData) {
- return c.json(userData);
- } else {
- return c.json({ error: "Error getting all users from instance" }, 500);
- }
- },
-);
-
-userRoutes.post(
- "",
- describeRoute({
- description: "Create a new user",
- responses: {
- 201: {
- description: "Success",
- content: {
- "application/json": { schema: resolver(createUserSchema) },
- },
- },
- 400: {
- description: "Bad request (user exists)",
- content: {
- "application/json": { schema: resolver(createUserSchema) },
- },
- },
- },
- }),
- zValidator("json", createUserSchema),
- async (c) => {
- try {
- const data = await c.req.json();
- const newUser = await createNewUser(data);
- if (!newUser) {
- return c.json({ error: "User already exists" }, 400);
- }
- return c.json(newUser, 201);
- } catch (error) {
- return c.json({ error: "Error creating user" }, 500);
- }
- },
-);
-
-export default userRoutes;
diff --git a/concord-server/src/services/channelService.ts b/concord-server/src/services/channelService.ts
deleted file mode 100644
index 4e12c51..0000000
--- a/concord-server/src/services/channelService.ts
+++ /dev/null
@@ -1,457 +0,0 @@
-import { Channel, Category } from "@prisma/client";
-import { PrismaClient } from "@prisma/client";
-import { getUserInformation, getUserCredentials } from "./userService";
-import {
- CreateChannelInput,
- UpdateChannelInput,
- DeleteChannelInput,
- DeleteChannelsByCategoryIdInput,
-} from "../validators/channelValidator";
-import {
- UpdateCategoryInput,
- DeleteCategoryInput,
- DeleteCategoriesByInstanceIdInput,
- CreateCategoryInput,
-} from "../validators/categoryValidator";
-
-const prisma = new PrismaClient();
-
-export async function createCategory(
- data: CreateCategoryInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const newCategory = await prisma.category.create({
- data: {
- name: data.name,
- position: data.position,
- },
- });
-
- if (!newCategory) {
- throw new Error("could not create category");
- }
-
- let curInstance;
- if (data.instanceId) {
- curInstance = await prisma.instance.findUnique({
- where: {
- id: data.instanceId,
- },
- include: {
- Category: true,
- },
- });
-
- if (!curInstance) {
- throw new Error("could not find instance to add category to");
- }
-
- await prisma.category.update({
- where: {
- id: newCategory.id,
- },
- data: {
- instanceId: curInstance.id,
- },
- });
-
- return newCategory;
- }
-
- return newCategory;
- } catch (err) {
- console.log("services::channelService::createCategory - ", err);
- return null;
- }
-}
-
-export async function getCategory(
- categoryId: string,
-): Promise {
- try {
- const category = await prisma.category.findUnique({
- where: {
- id: categoryId,
- },
- });
-
- if (!category) {
- throw new Error("could not find category");
- }
-
- return category;
- } catch (err) {
- console.log("services::channelService::getCategory - ", err);
- return null;
- }
-}
-
-export async function getCategoriesByInstance(
- instanceId: string,
-): Promise {
- try {
- const categories = await prisma.category.findMany({
- where: {
- instanceId: instanceId,
- },
- include: {
- Channel: true,
- },
- orderBy: {
- position: "asc",
- },
- });
-
- if (!categories) {
- throw new Error("could not find categories for instance");
- }
-
- return categories;
- } catch (err) {
- console.log("services::channelService::getCategoriesByInstance - ", err);
- return null;
- }
-}
-
-export async function updateCategory(
- data: UpdateCategoryInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const updatedCategory = await prisma.category.update({
- where: {
- id: data.id,
- },
- data: {
- name: data.name,
- position: data.position,
- Channel: data.channels ? { set: data.channels } : undefined,
- },
- });
-
- if (!updatedCategory) {
- throw new Error("could not update category");
- }
-
- return updatedCategory;
- } catch (err) {
- console.log("services::channelService::updateCategory - ", err);
- return null;
- }
-}
-
-export async function deleteCategory(
- data: DeleteCategoryInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const deleteAllChannels = await prisma.channel.deleteMany({
- where: {
- categoryId: data.id,
- },
- });
-
- if (deleteAllChannels.count === 0) {
- throw new Error("could not delete channels from category");
- }
-
- const deletedCategory = await prisma.category.delete({
- where: {
- id: data.id,
- },
- });
-
- if (!deletedCategory) {
- throw new Error("could not delete category");
- }
-
- return true;
- } catch (err) {
- console.log("services::channelService::deleteCategory - ", err);
- return false;
- }
-}
-
-export async function deleteAllCategoriesFromInstance(
- data: DeleteCategoriesByInstanceIdInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const deletedCategories = await prisma.category.deleteMany({
- where: {
- instanceId: data.instanceId,
- },
- });
-
- if (deletedCategories.count === 0) {
- throw new Error("could not delete categories from instance");
- }
-
- return true;
- } catch (err) {
- console.log(
- "services::channelService::deleteAllCategoriesFromInstance - ",
- err,
- );
- return false;
- }
-}
-
-export async function createChannel(
- data: CreateChannelInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const newChannel = await prisma.channel.create({
- data: {
- type: data.type,
- name: data.name,
- description: data.description,
- categoryId: data.categoryId ? data.categoryId : null,
- },
- });
-
- if (!newChannel) {
- throw new Error("could not create channel");
- }
-
- return newChannel;
- } catch (err) {
- console.log("services::channelService::createChannel - ", err);
- return null;
- }
-}
-
-export async function getChannel(channelId: string): Promise {
- try {
- const channel = await prisma.channel.findUnique({
- where: {
- id: channelId,
- },
- });
-
- if (!channel) {
- throw new Error("could not find channel");
- }
-
- return channel;
- } catch (err) {
- console.log("services::channelService::getChannel - ", err);
- return null;
- }
-}
-
-export async function getChannelsByCategory(
- categoryId: string,
-): Promise {
- try {
- const channels = await prisma.channel.findMany({
- where: {
- categoryId: categoryId,
- },
- });
-
- if (!channels) {
- throw new Error("could not find channels for category");
- }
- return channels;
- } catch (err) {
- console.log("services::channelService::getChannelsByCategory - ", err);
- return null;
- }
-}
-
-export async function updateChannel(
- data: UpdateChannelInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const updatedChannel = await prisma.channel.update({
- where: {
- id: data.id,
- },
- data: {
- name: data.name,
- description: data.description,
- categoryId: data.categoryId ? data.categoryId : undefined,
- },
- });
-
- if (!updatedChannel) {
- throw new Error("could not update channel");
- }
-
- return updatedChannel;
- } catch (err) {
- console.log("services::channelService::updateChannel - ", err);
- return null;
- }
-}
-
-export async function deleteChannel(
- data: DeleteChannelInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const deletedChannel = await prisma.channel.delete({
- where: {
- id: data.id,
- },
- });
-
- if (!deletedChannel) {
- throw new Error("could not delete channel");
- }
-
- return true;
- } catch (err) {
- console.log("services::channelService::deleteChannel - ", err);
- return false;
- }
-}
-
-export async function deleteAllChannelsFromCategory(
- data: DeleteChannelsByCategoryIdInput,
-): Promise {
- try {
- //Confirm if user exists and is admin
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
-
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- const deletedChannels = await prisma.channel.deleteMany({
- where: {
- categoryId: data.categoryId,
- },
- });
-
- if (deletedChannels.count === 0) {
- throw new Error("could not delete channels from category");
- }
-
- return true;
- } catch (err) {
- console.log(
- "services::channelService::deleteAllChannelsFromCategory - ",
- err,
- );
- return false;
- }
-}
diff --git a/concord-server/src/services/instanceService.ts b/concord-server/src/services/instanceService.ts
deleted file mode 100644
index 7ac6381..0000000
--- a/concord-server/src/services/instanceService.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import { PrismaClient } from "@prisma/client";
-import { CreateInstanceRequest } from "../validators/instanceValidator";
-import { getUserCredentials, getUserInformation } from "./userService";
-
-const prisma = new PrismaClient();
-
-export async function createInstance(data: CreateInstanceRequest) {
- try {
- const creds = await getUserCredentials(data.requestingUserId);
- const user = await getUserInformation(data.requestingUserId);
- if (
- !creds ||
- creds.token != data.requestingUserToken ||
- !user ||
- !user.admin
- ) {
- return null;
- }
-
- const newInstance = await prisma.instance.create({
- data: {
- name: data.name,
- icon: data.icon,
- },
- });
-
- return {
- success: true,
- data: newInstance,
- };
- } catch (error) {
- console.error("Error creating instance:", error);
- return {
- success: false,
- error: "Failed to create instance",
- };
- }
-}
-
-export async function getAllInstances() {
- try {
- const instances = await prisma.instance.findMany({
- orderBy: {
- createdAt: "desc",
- },
- });
-
- return {
- success: true,
- data: instances,
- };
- } catch (error) {
- console.error("Error fetching instances:", error);
- return {
- success: false,
- error: "Failed to fetch instances",
- };
- }
-}
-
-export async function getInstanceByChannelId(id: string) {
- try {
- const instance = await prisma.instance.findFirst({
- where: {
- Category: {
- some: {
- Channel: {
- some: {
- id: id
- }
- }
- }
- }
- },
- });
-
- if (!instance) {
- return null;
- }
-
- return instance;
- } catch (error) {
- console.error("Error fetching instance by channel ID:", error);
- return null;
- }
-}
-
-export async function getInstancesByUserId(id: string) {
- try {
- const user = await getUserInformation(id);
- if (user && user.admin) {
- const adminInstances = await getAllInstances();
- if (adminInstances && adminInstances.success) {
- return adminInstances.data;
- }
- }
-
- const instance = await prisma.instance.findMany({
- where: {
- Role: {
- some: {
- User: {
- id: id
- }
- }
- }
- }
- });
-
- if (!instance) {
- return null;
- }
-
- return instance;
- } catch (error) {
- console.error("Error fetching instance by channel ID:", error);
- return null;
- }
-}
-
diff --git a/concord-server/src/services/messageService.ts b/concord-server/src/services/messageService.ts
deleted file mode 100644
index 23b7590..0000000
--- a/concord-server/src/services/messageService.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-import { PrismaClient } from "@prisma/client";
-import { getUserCredentials } from "./userService";
-import { PutMessage } from "../validators/messageValidator";
-
-const prisma = new PrismaClient();
-
-export async function getMessageInformation(id: string): Promise<{
- id: string;
- channelId: string;
- userId: string;
- text: string;
- deleted: boolean;
- replies: null | {
- messageId: string;
- repliesToId: string;
- repliesToText: string;
- };
-} | null> {
- try {
- if (!id) {
- throw new Error("missing messageId");
- }
-
- const message = await prisma.message.findUnique({
- where: {
- id: id,
- },
- });
-
- if (!message) {
- throw new Error("could not find message");
- }
-
- // Check if this message is a reply to another message
- const replyData = await prisma.reply.findFirst({
- where: {
- messageId: id,
- },
- });
-
- let originalMessage = null;
- if (replyData) {
- originalMessage = await prisma.message.findUnique({
- where: {
- id: replyData.repliesToId,
- },
- });
- }
-
- return {
- id: message.id,
- channelId: message.channelId!,
- userId: message.userId!,
- text: message.text,
- deleted: message.deleted,
- replies: originalMessage
- ? {
- messageId: message.id,
- repliesToId: originalMessage.id,
- repliesToText: originalMessage.text,
- }
- : null,
- };
- } catch (err) {
- const errMessage = err as Error;
-
- if (errMessage.message === "missing messageId") {
- console.log(
- "services::actions::getMessageInformation - missing messageId",
- );
- return null;
- }
-
- if (errMessage.message === "could not find message") {
- console.log(
- "services::actions::getMessageInformation - unable to find message",
- );
- return null;
- }
-
- console.log(
- "services::actions::getMessageInformation - unknown error",
- errMessage,
- );
- return null;
- }
-}
-
-export async function getMessagesBefore(date: string, channelId: string) {
- try {
- if (!date || !channelId) {
- throw new Error("missing date or channelId");
- }
-
- const messages = await prisma.message.findMany({
- where: {
- channelId: channelId,
- createdAt: {
- lt: new Date(date),
- },
- },
- orderBy: {
- createdAt: "desc",
- },
- take: 50,
- });
-
- const messageInformationPromises = messages.map(async (message) => {
- const replyData = await prisma.reply.findFirst({
- where: {
- messageId: message.id,
- },
- });
-
- let originalMessage = null;
- if (replyData) {
- originalMessage = await prisma.message.findUnique({
- where: {
- id: replyData.repliesToId,
- },
- });
- }
-
- return {
- id: message.id,
- channelId: message.channelId!,
- userId: message.userId!,
- text: message.text,
- deleted: message.deleted,
- createdAt: message.createdAt,
- replies: originalMessage
- ? {
- messageId: message.id,
- repliesToId: originalMessage.id,
- repliesToText: originalMessage.text,
- }
- : null,
- };
- });
-
- return Promise.all(messageInformationPromises);
- } catch (err) {
- const errMessage = err as Error;
-
- if (errMessage.message === "missing date or channelId") {
- console.log(
- "services::actions::getMessagesBefore - missing date or channelId",
- );
- return null;
- }
-
- console.log(
- "services::actions::getMessagesBefore - unknown error",
- errMessage,
- );
- return null;
- }
-}
-
-export async function editMessage(data: PutMessage) {
- try {
- const userCreds = await getUserCredentials(data.id);
- if (
- !userCreds ||
- userCreds.token == null ||
- userCreds.token != data.token
- ) {
- return null;
- }
-
- const updatedMessage = await prisma.message.update({
- where: {
- id: data.id,
- },
- data: {
- text: data.content,
- deleted: data.deleted,
- },
- });
-
- if (!updatedMessage) {
- return null;
- }
-
- return updatedMessage;
- } catch (error) {
- console.error("Error editing message:", error);
- return null;
- }
-}
-
-export async function sendMessageToChannel(
- channelId: string,
- userId: string,
- content: string,
- token: string,
- repliedMessageId: string | null,
-): Promise<{
- id: string;
- channelId: string;
- userId: string;
- text: string;
- deleted: boolean;
- replies: null | {
- messageId: string;
- repliesToId: string;
- repliesToText: string;
- };
-} | null> {
- try {
- const userCreds = await getUserCredentials(userId);
- if (!userCreds || userCreds.token != token) {
- return null;
- }
-
- const newMessage = await prisma.message.create({
- data: {
- channelId: channelId,
- userId: userId,
- text: content,
- deleted: false,
- },
- });
-
- if (!newMessage) {
- return null;
- }
-
- let origMessage;
- if (repliedMessageId) {
- origMessage = await prisma.message.findUnique({
- where: {
- id: repliedMessageId,
- },
- });
-
- if (!origMessage) {
- throw new Error("could not find original message to reply to");
- }
-
- await prisma.reply.create({
- data: {
- messageId: newMessage.id,
- repliesToId: origMessage.id,
- },
- });
- }
-
- return {
- ...newMessage,
- channelId: newMessage.channelId!,
- userId: newMessage.userId!,
- replies: origMessage
- ? {
- messageId: newMessage.id,
- repliesToId: origMessage?.id,
- repliesToText: origMessage?.text,
- }
- : null,
- };
- } catch (error) {
- return null;
- }
-}
diff --git a/concord-server/src/services/userService.ts b/concord-server/src/services/userService.ts
deleted file mode 100644
index a66a920..0000000
--- a/concord-server/src/services/userService.ts
+++ /dev/null
@@ -1,330 +0,0 @@
-import {
- Message,
- MessagePing,
- PrismaClient,
- Role,
- UserAuth,
-} from "@prisma/client";
-import { CreateUserInput } from "../validators/userValidator";
-import shaHash from "../helper/hashing";
-
-const prisma = new PrismaClient();
-
-export async function createUser(data: CreateUserInput): Promise<{
- username: string;
- nickname: string | null;
- bio: string | null;
- picture: string | null;
- banner: string | null;
- status: string;
- admin: boolean;
-} | null> {
- const requestingUser = await getUserInformation(data.requestingUserId);
- const requestingUserCredentials = await getUserCredentials(
- data.requestingUserId,
- );
- if (
- !requestingUser ||
- !requestingUserCredentials ||
- !requestingUser.admin ||
- requestingUserCredentials.token == null ||
- data.requestingUserToken != requestingUserCredentials.token
- ) {
- return null;
- }
-
- if ((await prisma.user.count({ where: { username: data.username } })) >= 1) {
- return null;
- }
-
- const userData = await prisma.user.create({
- data: {
- username: data.username,
- nickname: data.nickname,
- bio: data.bio,
- picture: data.picture,
- banner: data.banner,
- status: data.status,
- admin: data.admin,
- },
- });
-
- if (
- !(await prisma.userAuth.create({
- data: {
- userId: userData.id,
- password: shaHash(data.passwordhash, userData.id),
- token: null,
- },
- }))
- ) {
- return null;
- }
-
- return userData;
-}
-
-export async function getUserId(
- username: string,
-): Promise<{ userId: string } | null> {
- try {
- if (!username) throw new Error("missing username");
-
- const user = await prisma.user.findFirst({
- where: {
- username: username,
- },
- });
-
- if (!user) throw new Error("could not find user");
-
- return {
- userId: user.id,
- };
- } catch (err) {
- const errMessage = err as Error;
-
- if (errMessage.message === "missing username") {
- console.log("services::actions::getUserId - no username given");
- return null;
- }
- if (errMessage.message === "could not find user") {
- console.log("services::actions::getUserId - unable to find user");
- return null;
- }
- console.log("services::actions::getUserId - unknown error");
- return null;
- }
-}
-
-export async function getUserCredentials(userId: string): Promise<{
- userId: string;
- password: string;
- token: string | null;
-} | null> {
- try {
- if (!userId) {
- throw new Error("missing userId");
- }
-
- const userAuth = await prisma.userAuth.findUnique({
- where: {
- userId: userId,
- },
- });
-
- if (!userAuth) {
- throw new Error("could not find user credentials");
- }
-
- return {
- userId: userAuth.userId,
- password: userAuth.password,
- token: userAuth.token,
- };
- } catch (err) {
- const errMessage = err as Error;
-
- if (errMessage.message === "missing userId") {
- console.log("services::actions::getUserCredentials - missing userId");
- return null;
- }
-
- if (errMessage.message === "could not find user credentials") {
- console.log(
- "services::actions::getUserCredentials - unable to find user credentials",
- );
- return null;
- }
-
- console.log(
- "services::actions::getUserCredentials - unknown error",
- errMessage,
- );
- return null;
- }
-}
-
-export async function getUserInformation(userId: string): Promise<{
- id: string;
- userName: string;
- nickName: string | null;
- bio: string | null;
- picture: string | null;
- banner: string | null;
- admin: boolean;
- status: "online" | "offline" | "dnd" | "idle" | "invis";
- role: Role[];
-} | null> {
- try {
- if (!userId) {
- throw new Error("missing userId");
- }
-
- const user = await prisma.user.findUnique({
- where: {
- id: userId,
- },
- });
-
- if (!user) {
- throw new Error("could not find user");
- }
-
- const userRoles = await prisma.role.findMany({
- where: {
- userId: userId,
- },
- });
-
- return {
- id: userId,
- userName: user.username,
- nickName: user.nickname,
- bio: user.bio,
- picture: user.picture,
- banner: user.banner,
- admin: user.admin,
- status: (["online", "offline", "dnd", "idle", "invis"] as const).includes(
- user.status as any,
- )
- ? (user.status as "online" | "offline" | "dnd" | "idle" | "invis")
- : "offline",
- role: userRoles,
- };
- } catch (err) {
- const errMessage = err as Error;
-
- if (errMessage.message === "missing userId") {
- console.log("services::actions::getUserInformation - missing userId");
- return null;
- }
-
- if (errMessage.message === "could not find user") {
- console.log(
- "services::actions::getUserInformation - unable to find user",
- );
- return null;
- }
-
- console.log(
- "services::actions::getUserInformation - unknown error",
- errMessage,
- );
- return null;
- }
-}
-
-export async function getAllUsersFrom(instanceId: string): Promise<
- | {
- id: string;
- userName: string;
- nickName: string | null;
- bio: string | null;
- picture: string | null;
- banner: string | null;
- admin: boolean;
- status: "online" | "offline" | "dnd" | "idle" | "invis";
- role: {
- userId: string;
- instanceId: string;
- }[];
- }[]
- | null
-> {
- try {
- const instances = await prisma.instance.count({
- where: {
- id: instanceId,
- },
- });
- if (instances < 1) {
- throw new Error("could not find given instance id");
- }
-
- const users = await prisma.user.findMany({
- where: {
- Role: {
- some: {
- instanceId: instanceId,
- },
- },
- },
- });
- if (!users) {
- throw new Error("could not get all users in instance");
- }
-
- const admins = await prisma.user.findMany({
- where: {
- admin: true,
- },
- });
- if (!admins) {
- throw new Error("could not get all admins");
- }
- const adminData = await Promise.all(
- admins.map(async (u) => {
- const adminRoles = await prisma.role.findMany({
- where: {
- userId: u.id,
- },
- });
-
- if (!adminRoles) {
- throw new Error("could not get admin roles for admin " + u.id);
- }
-
- return {
- id: u.id,
- userName: u.username,
- nickName: u.nickname,
- bio: u.bio,
- picture: u.picture,
- banner: u.banner,
- admin: u.admin,
- status: (
- ["online", "offline", "dnd", "idle", "invis"] as const
- ).includes(u.status as any)
- ? (u.status as "online" | "offline" | "dnd" | "idle" | "invis")
- : "offline",
- role: adminRoles,
- };
- }),
- );
-
- const userData = await Promise.all(
- users.map(async (u) => {
- const userRoles = await prisma.role.findMany({
- where: {
- userId: u.id,
- },
- });
- if (!userRoles) {
- throw new Error("could not get user roles for user " + u.id);
- }
-
- return {
- id: u.id,
- userName: u.username,
- nickName: u.nickname,
- bio: u.bio,
- picture: u.picture,
- banner: u.banner,
- admin: u.admin,
- status: (
- ["online", "offline", "dnd", "idle", "invis"] as const
- ).includes(u.status as any)
- ? (u.status as "online" | "offline" | "dnd" | "idle" | "invis")
- : "offline",
- role: userRoles,
- };
- }),
- );
-
- return userData.concat(adminData);
- } catch (err) {
- console.log(err);
- return null;
- }
-}
diff --git a/concord-server/src/sockets/index.ts b/concord-server/src/sockets/index.ts
deleted file mode 100644
index 816e14d..0000000
--- a/concord-server/src/sockets/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Server } from "socket.io";
-import { registerVoiceHandlers } from "./voiceHandler";
-
-export function registerSocketHandlers(io: Server) {
- // bad practice
- io.on("connection", (socket) => {
- console.log("connected");
- socket.on("ping", (c) => {
- console.log(c);
- socket.emit("pong", c);
- });
- });
-
- // good practice
- registerVoiceHandlers(io);
-}
diff --git a/concord-server/src/sockets/voiceHandler.ts b/concord-server/src/sockets/voiceHandler.ts
deleted file mode 100644
index 50c285f..0000000
--- a/concord-server/src/sockets/voiceHandler.ts
+++ /dev/null
@@ -1,309 +0,0 @@
-import { Server, Socket } from "socket.io";
-import { getUserCredentials, getUserInformation } from "../services/userService";
-import { getAllInstances, getInstanceByChannelId, getInstancesByUserId } from "../services/instanceService";
-import { getCategoriesByInstance, getCategory, getChannel } from "../services/channelService";
-
-// Change to Map of voiceChannelId to Map of userId to socket
-const voiceChannelMembers = new Map>();
-
-// Types for WebRTC messages
-interface WebRTCOffer {
- targetUserId: string;
- sdp: RTCSessionDescriptionInit;
-}
-
-interface WebRTCAnswer {
- targetUserId: string;
- sdp: RTCSessionDescriptionInit;
-}
-
-interface WebRTCIceCandidate {
- targetUserId: string;
- candidate: RTCIceCandidateInit;
-}
-
-// Future ICE server configuration
-// This can be expanded later to include TURN servers
-interface IceServerConfig {
- urls: string | string[];
- username?: string;
- credential?: string;
-}
-
-export function registerVoiceHandlers(io: Server) {
- io.on("connection", (socket: Socket) => {
- // Join voice channel
- socket.on("join-voicechannel", async (data) => {
- const payload = data as {
- userId: string
- userToken: string,
- voiceChannelId: string,
- };
- if (!payload) {
- socket.emit("error-voicechannel", "no payload in voice conn")
- return;
- }
-
- // Initialize map for channel if not present
- if (!voiceChannelMembers.has(payload.voiceChannelId)) {
- voiceChannelMembers.set(payload.voiceChannelId, new Map());
- }
-
- const channelMembers = voiceChannelMembers.get(payload.voiceChannelId)!;
-
- // Remove user if already present in this channel
- if (channelMembers.has(payload.userId)) {
- channelMembers.delete(payload.userId);
- }
-
- // authenticate user
- const userCreds = await getUserCredentials(payload.userId);
- if (!userCreds || !userCreds.token || userCreds.token != payload.userToken) {
- socket.emit("error-voicechannel", "bad user creds in voice conn");
- return;
- }
-
- // determine if channel is voice channel
- const channel = await getChannel(payload.voiceChannelId);
- if (!channel || channel.type !== "voice" || !channel.categoryId) {
- socket.emit("error-voicechannel", "bad channel or channel type in voice conn");
- return;
- }
-
- // authorize user using role
- const user = await getUserInformation(payload.userId);
- const instance = await getInstanceByChannelId(payload.voiceChannelId);
- const instances = await getInstancesByUserId(payload.userId);
- if (!user || !instance || !instances || !instances.find(e => e.id === instance.id)) {
- socket.emit("error-voicechannel", "user not authorized for channel in voice conn");
- return;
- }
-
- // add to map
- channelMembers.set(payload.userId, socket);
-
- socket.join(payload.voiceChannelId);
- socket.emit("joined-voicechannel", {
- voiceChannelId: payload.voiceChannelId,
- connectedUserIds: Array.from(channelMembers.keys()).filter(e => e !== payload.userId),
- iceServers: getIceServers() // Send ICE server config to client
- });
- socket.to(payload.voiceChannelId).emit("user-joined-voicechannel", { userId: payload.userId });
-
- // Store userId in socket.data for easier access later
- socket.data.userId = payload.userId;
- socket.data.currentVoiceChannelId = payload.voiceChannelId;
- });
-
- // Leave voice channel
- socket.on("leave-voicechannel", async (data) => {
- const payload = data as {
- userId: string,
- userToken: string,
- voiceChannelId: string,
- };
- if (!payload) {
- socket.emit("error-voicechannel", "no payload in leave voice request");
- return;
- }
-
- const channelMembers = voiceChannelMembers.get(payload.voiceChannelId);
- if (!channelMembers) {
- socket.emit("error-voicechannel", "voice channel not found");
- return;
- }
-
- // authenticate user
- const userCreds = await getUserCredentials(payload.userId);
- if (!userCreds || !userCreds.token || userCreds.token != payload.userToken) {
- socket.emit("error-voicechannel", "bad user creds in leave voice request");
- return;
- }
-
- // Remove user from channel
- if (channelMembers.has(payload.userId)) {
- channelMembers.delete(payload.userId);
-
- // Leave the socket.io room
- socket.leave(payload.voiceChannelId);
-
- // Notify other users in the channel
- io.to(payload.voiceChannelId).emit("user-left-voicechannel", {
- userId: payload.userId,
- voiceChannelId: payload.voiceChannelId
- });
-
- // Clean up empty channels
- if (channelMembers.size === 0) {
- voiceChannelMembers.delete(payload.voiceChannelId);
- }
-
- // Confirm to the user that they've left
- socket.emit("left-voicechannel", {
- voiceChannelId: payload.voiceChannelId
- });
-
- // Clear socket data
- socket.data.currentVoiceChannelId = undefined;
- } else {
- socket.emit("error-voicechannel", "user not in voice channel");
- }
- });
-
- // Handle disconnection
- socket.on("disconnect", () => {
- // Get the user ID and current voice channel from socket data
- const userId = socket.data.userId;
- const voiceChannelId = socket.data.currentVoiceChannelId;
-
- // If we have the channel ID stored, use it directly
- if (userId && voiceChannelId) {
- const channelMembers = voiceChannelMembers.get(voiceChannelId);
- if (channelMembers && channelMembers.has(userId)) {
- // Remove the user from the channel
- channelMembers.delete(userId);
-
- // Notify other members
- io.to(voiceChannelId).emit("user-left-voicechannel", {
- userId,
- voiceChannelId,
- reason: "disconnected"
- });
-
- // Clean up empty channels
- if (channelMembers.size === 0) {
- voiceChannelMembers.delete(voiceChannelId);
- }
- }
- } else {
- // If we don't have the info stored, search through all channels
- voiceChannelMembers.forEach((members, channelId) => {
- // Use Array.from to convert Map entries to array for iteration
- Array.from(members.entries()).forEach(([memberId, memberSocket]) => {
- if (memberSocket.id === socket.id) {
- // Found the user in this channel
- members.delete(memberId);
-
- // Notify other members
- io.to(channelId).emit("user-left-voicechannel", {
- userId: memberId,
- voiceChannelId: channelId,
- reason: "disconnected"
- });
-
- // Clean up empty channels
- if (members.size === 0) {
- voiceChannelMembers.delete(channelId);
- }
- }
- });
- });
- }
- });
-
- // Handle WebRTC Offer
- socket.on("webrtc-offer", async (data) => {
- const payload = data as { targetUserId: string; sdp: any };
- const senderUserId = socket.data.userId;
- const voiceChannelId = socket.data.currentVoiceChannelId;
-
- if (!payload || !senderUserId || !voiceChannelId) {
- socket.emit("error-voicechannel", "Invalid WebRTC offer payload or sender not in voice channel");
- return;
- }
-
- const channelMembers = voiceChannelMembers.get(voiceChannelId);
- const targetSocket = channelMembers?.get(payload.targetUserId);
-
- if (targetSocket) {
- targetSocket.emit("webrtc-offer", {
- senderUserId: senderUserId,
- sdp: payload.sdp
- });
- } else {
- socket.emit("error-voicechannel", "Target user not found in voice channel");
- }
- });
-
- // Handle WebRTC Answer
- socket.on("webrtc-answer", (data: WebRTCAnswer) => {
- const senderUserId = socket.data.userId;
- const voiceChannelId = socket.data.currentVoiceChannelId;
-
- if (!data || !senderUserId || !voiceChannelId) {
- socket.emit("error-voicechannel", "Invalid WebRTC answer data");
- return;
- }
-
- // Forward the answer to the target user
- const channelMembers = voiceChannelMembers.get(voiceChannelId);
- const targetSocket = channelMembers?.get(data.targetUserId);
-
- if (targetSocket) {
- targetSocket.emit("webrtc-answer", {
- senderUserId: senderUserId,
- sdp: data.sdp
- });
- } else {
- socket.emit("error-voicechannel", "Target user not found in voice channel");
- }
- });
-
- // Handle ICE Candidates
- socket.on("webrtc-ice-candidate", (data: WebRTCIceCandidate) => {
- const senderUserId = socket.data.userId;
- const voiceChannelId = socket.data.currentVoiceChannelId;
-
- if (!data || !senderUserId || !voiceChannelId) {
- socket.emit("error-voicechannel", "Invalid ICE candidate data");
- return;
- }
-
- // Forward the ICE candidate to the target user
- const channelMembers = voiceChannelMembers.get(voiceChannelId);
- const targetSocket = channelMembers?.get(data.targetUserId);
-
- if (targetSocket) {
- targetSocket.emit("webrtc-ice-candidate", {
- senderUserId: senderUserId,
- candidate: data.candidate
- });
- } else {
- socket.emit("error-voicechannel", "Target user not found in voice channel");
- }
- });
- });
-}
-
-/**
- * Get the current ICE server configuration.
- * This function returns STUN servers and includes TURN server credentials
- * if they are available in the environment variables.
- */
-function getIceServers(): IceServerConfig[] {
- const iceServers: IceServerConfig[] = [
- { urls: 'stun:stun.l.google.com:19302' },
- { urls: 'stun:stun1.l.google.com:19302' },
- ];
-
- // Add own STUN server if configured
- const stunServerUrl = process.env.STUN_SERVER_URL;
- if (stunServerUrl) {
- iceServers.push({ urls: stunServerUrl });
- }
-
- // Add TURN server if configured in environment variables
- const turnServerUrl = process.env.TURN_SERVER_URL;
- const turnUsername = process.env.TURN_SERVER_USERNAME;
- const turnCredential = process.env.TURN_SERVER_CREDENTIAL;
-
- if (turnServerUrl && turnUsername && turnCredential) {
- iceServers.push({
- urls: turnServerUrl,
- username: turnUsername,
- credential: turnCredential,
- });
- }
-
- return iceServers;
-}
diff --git a/concord-server/src/validators/authValidator.ts b/concord-server/src/validators/authValidator.ts
deleted file mode 100644
index cb618e1..0000000
--- a/concord-server/src/validators/authValidator.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { z } from "zod";
-
-export const loginSchema = z.object({
- username: z.string().min(3).max(30),
- password: z.string().min(1),
-});
-
-export const validateTokenSchema = z.object({
- token: z.string(),
- userId: z.uuidv7(),
-});
-
-export const refreshTokenSchema = z.object({
- userId: z.uuidv7(),
- oldToken: z.string(),
-});
-
-export const logoutSchema = z.object({
- userId: z.uuidv7(),
-});
-
-// Response schemas for OpenAPI documentation
-export const authResponseSchema = z.object({
- user: z.object({
- id: z.string(),
- userName: z.string(),
- nickName: z.string().nullable(),
- bio: z.string().nullable(),
- picture: z.string().nullable(),
- banner: z.string().nullable(),
- admin: z.boolean(),
- status: z.enum(["online", "offline", "dnd", "idle", "invis"]),
- role: z.array(z.any()),
- }),
- token: z.string(),
-});
-
-export const validationResponseSchema = z.object({
- valid: z.boolean(),
- user: z.any().optional(),
-});
-
-export const errorResponseSchema = z.object({
- error: z.string(),
-});
-
-export const successResponseSchema = z.object({
- success: z.boolean(),
-});
-
-// Type exports
-export type LoginInput = z.infer;
-export type ValidateTokenInput = z.infer;
-export type RefreshTokenInput = z.infer;
-export type LogoutInput = z.infer;
-export type AuthResponse = z.infer;
-export type ValidationResponse = z.infer;
diff --git a/concord-server/src/validators/categoryValidator.ts b/concord-server/src/validators/categoryValidator.ts
deleted file mode 100644
index f8ef491..0000000
--- a/concord-server/src/validators/categoryValidator.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { z } from "zod";
-
-//category validators
-
-export const createCategorySchema = z.object({
- name: z.string().min(1).max(50),
- position: z.number().min(0),
- instanceId: z.uuidv7().optional(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export const getCategorySchema = z.object({
- id: z.uuidv7(),
-});
-
-export const getCategoriesByInstanceIdSchema = z.object({
- instanceId: z.uuidv7(),
-});
-
-export const updateCategorySchema = z.object({
- id: z.uuidv7(),
- name: z.string().min(1).max(50).optional(),
- position: z.number().min(0).optional(),
- channels: z
- .array(
- z.object({
- id: z.string(),
- }),
- )
- .optional(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export const deleteCategorySchema = z.object({
- id: z.uuidv7(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export const deleteCategoriesByInstanceIdSchema = z.object({
- instanceId: z.uuidv7(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export type CreateCategoryInput = z.infer;
-export type GetCategoryInput = z.infer;
-export type GetCategoriesByInstanceIdInput = z.infer<
- typeof getCategoriesByInstanceIdSchema
->;
-export type UpdateCategoryInput = z.infer;
-export type DeleteCategoryInput = z.infer;
-export type DeleteCategoriesByInstanceIdInput = z.infer<
- typeof deleteCategoriesByInstanceIdSchema
->;
diff --git a/concord-server/src/validators/channelValidator.ts b/concord-server/src/validators/channelValidator.ts
deleted file mode 100644
index 23cb918..0000000
--- a/concord-server/src/validators/channelValidator.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { z } from "zod";
-
-//channel validators
-
-export const createChannelSchema = z.object({
- type: z.enum(["text", "voice"]),
- name: z.string().min(1).max(50),
- description: z.string().max(255),
- categoryId: z.uuidv7().optional(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export const getChannelSchema = z.object({
- id: z.uuidv7(),
-});
-
-export const getChannelsByCategoryIdSchema = z.object({
- categoryId: z.uuidv7(),
-});
-
-export const updateChannelSchema = z.object({
- id: z.uuidv7(),
- name: z.string().min(1).max(50).optional(),
- description: z.string().max(255).optional(),
- categoryId: z.uuidv7().optional(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export const deleteChannelSchema = z.object({
- id: z.uuidv7(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export const deleteChannelsByCategoryIdSchema = z.object({
- categoryId: z.uuidv7(),
- admin: z.boolean(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
-});
-
-export type CreateChannelInput = z.infer;
-export type GetChannelInput = z.infer;
-export type GetChannelsByCategoryIdInput = z.infer<
- typeof getChannelsByCategoryIdSchema
->;
-export type UpdateChannelInput = z.infer;
-export type DeleteChannelInput = z.infer;
-export type DeleteChannelsByCategoryIdInput = z.infer<
- typeof deleteChannelsByCategoryIdSchema
->;
diff --git a/concord-server/src/validators/instanceValidator.ts b/concord-server/src/validators/instanceValidator.ts
deleted file mode 100644
index 880f957..0000000
--- a/concord-server/src/validators/instanceValidator.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { z } from "zod";
-
-export const createInstanceRequestSchema = z.object({
- name: z.string().min(1, "Instance name cannot be empty"),
- icon: z.url().optional(),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.string(),
-});
-
-export const getAllInstancesResponseSchema = z.object({
- success: z.boolean(),
- data: z
- .array(
- z.object({
- id: z.string(),
- name: z.string(),
- icon: z.string().nullable(),
- createdAt: z.string().refine((val) => !isNaN(Date.parse(val)), {
- message: "Invalid date string format",
- }),
- updatedAt: z.string().refine((val) => !isNaN(Date.parse(val)), {
- message: "Invalid date string format",
- }),
- }),
- )
- .optional(),
- error: z.string().optional(),
-});
-
-export type CreateInstanceRequest = z.infer;
-export type GetAllInstancesResponse = z.infer<
- typeof getAllInstancesResponseSchema
->;
diff --git a/concord-server/src/validators/messageValidator.ts b/concord-server/src/validators/messageValidator.ts
deleted file mode 100644
index 3833823..0000000
--- a/concord-server/src/validators/messageValidator.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { z } from "zod";
-
-export const getMessageByIdSchema = z.object({
- id: z.uuidv7(),
-});
-
-export const getMessagesBeforeDate = z.object({
- date: z.string().refine((val) => !isNaN(Date.parse(val)), {
- message: "Invalid date string format",
- }),
- channelId: z.uuidv7(),
-});
-
-export const sendMessageSchema = z.object({
- channelId: z.uuidv7(),
- userId: z.uuidv7(),
- content: z.string(),
- token: z.string(),
- repliedMessageId: z.uuidv7().nullable().optional(),
-});
-
-export const putMessageSchema = z.object({
- id: z.uuidv7(),
- content: z.string().optional(),
- deleted: z.boolean().optional(),
- token: z.string(),
-});
-
-export type PutMessage = z.infer;
diff --git a/concord-server/src/validators/realtimeValidator.ts b/concord-server/src/validators/realtimeValidator.ts
deleted file mode 100644
index 859b4e8..0000000
--- a/concord-server/src/validators/realtimeValidator.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { z } from "zod";
-
-export const postMessageToChannelSchema = z.object({
- instanceId: z.uuidv7(),
- categoryId: z.uuidv7(),
- channelId: z.uuidv7(),
- userId: z.uuidv7(),
- content: z.string().min(1).max(2000),
- repliedMessageId: z.uuidv7().optional(),
- token: z.string(),
-});
-
-//TODO: add more realtime related validators as needed
-
-export type PostMessageToChannelInput = z.infer<
- typeof postMessageToChannelSchema
->;
-//TODO: create more input schemas for other realtime actions
diff --git a/concord-server/src/validators/userValidator.ts b/concord-server/src/validators/userValidator.ts
deleted file mode 100644
index 5c9535f..0000000
--- a/concord-server/src/validators/userValidator.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { z } from "zod";
-
-export const queryUserByIdSchema = z.object({
- id: z.uuidv7(),
-});
-
-export const queryUserByUsernameSchema = z.object({
- username: z.string().min(3).max(30),
-});
-
-export const queryAllUsersByInstanceId = z.object({
- instanceId: z.uuidv7(),
-});
-
-export const createUserSchema = z.object({
- username: z.string().min(3).max(30),
- nickname: z.string().min(1).max(30).optional(),
- bio: z.string().max(500).optional(),
- picture: z.url().optional(),
- banner: z.url().optional(),
- status: z
- .enum(["online", "offline", "dnd", "idle", "invis"])
- .default("online"),
- admin: z.boolean().default(false),
- requestingUserId: z.uuidv7(),
- requestingUserToken: z.uuidv4(),
- passwordhash: z.string(),
-});
-
-export type QueryUserByIdInput = z.infer;
-export type QueryAllUsersByInstanceIdInput = z.infer<
- typeof queryAllUsersByInstanceId
->;
-export type CreateUserInput = z.infer;
diff --git a/concord-server/tsconfig.json b/concord-server/tsconfig.json
deleted file mode 100644
index 9136c14..0000000
--- a/concord-server/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "jsx": "react-jsx",
- "jsxImportSource": "hono/jsx"
- }
-}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..fb00d5c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "concord",
+ "private": true,
+ "scripts": {
+ "build": "turbo run build",
+ "dev": "turbo run dev",
+ "lint": "turbo run lint",
+ "format": "prettier --write \"**/*.{ts,tsx,md}\"",
+ "check-types": "turbo run check-types"
+ },
+ "devDependencies": {
+ "prettier": "^3.6.2",
+ "turbo": "^2.5.8",
+ "typescript": "5.9.2"
+ },
+ "packageManager": "pnpm@9.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+}
diff --git a/packages/eslint-config/README.md b/packages/eslint-config/README.md
new file mode 100644
index 0000000..8b42d90
--- /dev/null
+++ b/packages/eslint-config/README.md
@@ -0,0 +1,3 @@
+# `@turbo/eslint-config`
+
+Collection of internal eslint configurations.
diff --git a/packages/eslint-config/base.js b/packages/eslint-config/base.js
new file mode 100644
index 0000000..09d316e
--- /dev/null
+++ b/packages/eslint-config/base.js
@@ -0,0 +1,32 @@
+import js from "@eslint/js";
+import eslintConfigPrettier from "eslint-config-prettier";
+import turboPlugin from "eslint-plugin-turbo";
+import tseslint from "typescript-eslint";
+import onlyWarn from "eslint-plugin-only-warn";
+
+/**
+ * A shared ESLint configuration for the repository.
+ *
+ * @type {import("eslint").Linter.Config[]}
+ * */
+export const config = [
+ js.configs.recommended,
+ eslintConfigPrettier,
+ ...tseslint.configs.recommended,
+ {
+ plugins: {
+ turbo: turboPlugin,
+ },
+ rules: {
+ "turbo/no-undeclared-env-vars": "warn",
+ },
+ },
+ {
+ plugins: {
+ onlyWarn,
+ },
+ },
+ {
+ ignores: ["dist/**"],
+ },
+];
diff --git a/packages/eslint-config/next.js b/packages/eslint-config/next.js
new file mode 100644
index 0000000..6bf01a7
--- /dev/null
+++ b/packages/eslint-config/next.js
@@ -0,0 +1,49 @@
+import js from "@eslint/js";
+import eslintConfigPrettier from "eslint-config-prettier";
+import tseslint from "typescript-eslint";
+import pluginReactHooks from "eslint-plugin-react-hooks";
+import pluginReact from "eslint-plugin-react";
+import globals from "globals";
+import pluginNext from "@next/eslint-plugin-next";
+import { config as baseConfig } from "./base.js";
+
+/**
+ * A custom ESLint configuration for libraries that use Next.js.
+ *
+ * @type {import("eslint").Linter.Config[]}
+ * */
+export const nextJsConfig = [
+ ...baseConfig,
+ js.configs.recommended,
+ eslintConfigPrettier,
+ ...tseslint.configs.recommended,
+ {
+ ...pluginReact.configs.flat.recommended,
+ languageOptions: {
+ ...pluginReact.configs.flat.recommended.languageOptions,
+ globals: {
+ ...globals.serviceworker,
+ },
+ },
+ },
+ {
+ plugins: {
+ "@next/next": pluginNext,
+ },
+ rules: {
+ ...pluginNext.configs.recommended.rules,
+ ...pluginNext.configs["core-web-vitals"].rules,
+ },
+ },
+ {
+ plugins: {
+ "react-hooks": pluginReactHooks,
+ },
+ settings: { react: { version: "detect" } },
+ rules: {
+ ...pluginReactHooks.configs.recommended.rules,
+ // React scope no longer necessary with new JSX transform.
+ "react/react-in-jsx-scope": "off",
+ },
+ },
+];
diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json
new file mode 100644
index 0000000..c18143d
--- /dev/null
+++ b/packages/eslint-config/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@repo/eslint-config",
+ "version": "0.0.0",
+ "type": "module",
+ "private": true,
+ "exports": {
+ "./base": "./base.js",
+ "./next-js": "./next.js",
+ "./react-internal": "./react-internal.js"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.34.0",
+ "@next/eslint-plugin-next": "^15.5.0",
+ "eslint": "^9.34.0",
+ "eslint-config-prettier": "^10.1.1",
+ "eslint-plugin-only-warn": "^1.1.0",
+ "eslint-plugin-react": "^7.37.5",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-turbo": "^2.5.0",
+ "globals": "^16.3.0",
+ "typescript": "^5.9.2",
+ "typescript-eslint": "^8.40.0"
+ }
+}
diff --git a/packages/eslint-config/react-internal.js b/packages/eslint-config/react-internal.js
new file mode 100644
index 0000000..daeccba
--- /dev/null
+++ b/packages/eslint-config/react-internal.js
@@ -0,0 +1,39 @@
+import js from "@eslint/js";
+import eslintConfigPrettier from "eslint-config-prettier";
+import tseslint from "typescript-eslint";
+import pluginReactHooks from "eslint-plugin-react-hooks";
+import pluginReact from "eslint-plugin-react";
+import globals from "globals";
+import { config as baseConfig } from "./base.js";
+
+/**
+ * A custom ESLint configuration for libraries that use React.
+ *
+ * @type {import("eslint").Linter.Config[]} */
+export const config = [
+ ...baseConfig,
+ js.configs.recommended,
+ eslintConfigPrettier,
+ ...tseslint.configs.recommended,
+ pluginReact.configs.flat.recommended,
+ {
+ languageOptions: {
+ ...pluginReact.configs.flat.recommended.languageOptions,
+ globals: {
+ ...globals.serviceworker,
+ ...globals.browser,
+ },
+ },
+ },
+ {
+ plugins: {
+ "react-hooks": pluginReactHooks,
+ },
+ settings: { react: { version: "detect" } },
+ rules: {
+ ...pluginReactHooks.configs.recommended.rules,
+ // React scope no longer necessary with new JSX transform.
+ "react/react-in-jsx-scope": "off",
+ },
+ },
+];
diff --git a/packages/typescript-config/base.json b/packages/typescript-config/base.json
new file mode 100644
index 0000000..5117f2a
--- /dev/null
+++ b/packages/typescript-config/base.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "esModuleInterop": true,
+ "incremental": false,
+ "isolatedModules": true,
+ "lib": ["es2022", "DOM", "DOM.Iterable"],
+ "module": "NodeNext",
+ "moduleDetection": "force",
+ "moduleResolution": "NodeNext",
+ "noUncheckedIndexedAccess": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "ES2022"
+ }
+}
diff --git a/packages/typescript-config/nextjs.json b/packages/typescript-config/nextjs.json
new file mode 100644
index 0000000..e6defa4
--- /dev/null
+++ b/packages/typescript-config/nextjs.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "extends": "./base.json",
+ "compilerOptions": {
+ "plugins": [{ "name": "next" }],
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "allowJs": true,
+ "jsx": "preserve",
+ "noEmit": true
+ }
+}
diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json
new file mode 100644
index 0000000..27c0e60
--- /dev/null
+++ b/packages/typescript-config/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@repo/typescript-config",
+ "version": "0.0.0",
+ "private": true,
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/typescript-config/react-library.json b/packages/typescript-config/react-library.json
new file mode 100644
index 0000000..c3a1b26
--- /dev/null
+++ b/packages/typescript-config/react-library.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "extends": "./base.json",
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ }
+}
diff --git a/packages/ui/eslint.config.mjs b/packages/ui/eslint.config.mjs
new file mode 100644
index 0000000..19170f8
--- /dev/null
+++ b/packages/ui/eslint.config.mjs
@@ -0,0 +1,4 @@
+import { config } from "@repo/eslint-config/react-internal";
+
+/** @type {import("eslint").Linter.Config} */
+export default config;
diff --git a/packages/ui/package.json b/packages/ui/package.json
new file mode 100644
index 0000000..c820347
--- /dev/null
+++ b/packages/ui/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "@repo/ui",
+ "version": "0.0.0",
+ "private": true,
+ "exports": {
+ "./*": "./src/*.tsx"
+ },
+ "scripts": {
+ "lint": "eslint . --max-warnings 0",
+ "generate:component": "turbo gen react-component",
+ "check-types": "tsc --noEmit"
+ },
+ "devDependencies": {
+ "@repo/eslint-config": "workspace:*",
+ "@repo/typescript-config": "workspace:*",
+ "@types/node": "^22.15.3",
+ "@types/react": "19.1.0",
+ "@types/react-dom": "19.1.1",
+ "eslint": "^9.34.0",
+ "typescript": "5.9.2"
+ },
+ "dependencies": {
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0"
+ }
+}
diff --git a/packages/ui/src/button.tsx b/packages/ui/src/button.tsx
new file mode 100644
index 0000000..78e5420
--- /dev/null
+++ b/packages/ui/src/button.tsx
@@ -0,0 +1,20 @@
+"use client";
+
+import { ReactNode } from "react";
+
+interface ButtonProps {
+ children: ReactNode;
+ className?: string;
+ appName: string;
+}
+
+export const Button = ({ children, className, appName }: ButtonProps) => {
+ return (
+
+ );
+};
diff --git a/packages/ui/src/card.tsx b/packages/ui/src/card.tsx
new file mode 100644
index 0000000..7b98893
--- /dev/null
+++ b/packages/ui/src/card.tsx
@@ -0,0 +1,27 @@
+import { type JSX } from "react";
+
+export function Card({
+ className,
+ title,
+ children,
+ href,
+}: {
+ className?: string;
+ title: string;
+ children: React.ReactNode;
+ href: string;
+}): JSX.Element {
+ return (
+
+
+ {title} ->
+
+ {children}
+
+ );
+}
diff --git a/packages/ui/src/code.tsx b/packages/ui/src/code.tsx
new file mode 100644
index 0000000..f7cbd22
--- /dev/null
+++ b/packages/ui/src/code.tsx
@@ -0,0 +1,11 @@
+import { type JSX } from "react";
+
+export function Code({
+ children,
+ className,
+}: {
+ children: React.ReactNode;
+ className?: string;
+}): JSX.Element {
+ return {children};
+}
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json
new file mode 100644
index 0000000..ca86687
--- /dev/null
+++ b/packages/ui/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "@repo/typescript-config/react-library.json",
+ "compilerOptions": {
+ "outDir": "dist"
+ },
+ "include": ["src"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..7365375
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,3009 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ prettier:
+ specifier: ^3.6.2
+ version: 3.6.2
+ turbo:
+ specifier: ^2.5.4
+ version: 2.5.4
+ typescript:
+ specifier: 5.9.2
+ version: 5.9.2
+
+ apps/docs:
+ dependencies:
+ '@repo/ui':
+ specifier: workspace:*
+ version: link:../../packages/ui
+ next:
+ specifier: ^15.5.0
+ version: 15.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
+ devDependencies:
+ '@repo/eslint-config':
+ specifier: workspace:*
+ version: link:../../packages/eslint-config
+ '@repo/typescript-config':
+ specifier: workspace:*
+ version: link:../../packages/typescript-config
+ '@types/node':
+ specifier: ^22.15.3
+ version: 22.15.3
+ '@types/react':
+ specifier: 19.1.0
+ version: 19.1.0
+ '@types/react-dom':
+ specifier: 19.1.1
+ version: 19.1.1(@types/react@19.1.0)
+ eslint:
+ specifier: ^9.34.0
+ version: 9.34.0
+ typescript:
+ specifier: 5.9.2
+ version: 5.9.2
+
+ apps/web:
+ dependencies:
+ '@repo/ui':
+ specifier: workspace:*
+ version: link:../../packages/ui
+ next:
+ specifier: ^15.5.0
+ version: 15.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
+ devDependencies:
+ '@repo/eslint-config':
+ specifier: workspace:*
+ version: link:../../packages/eslint-config
+ '@repo/typescript-config':
+ specifier: workspace:*
+ version: link:../../packages/typescript-config
+ '@types/node':
+ specifier: ^22.15.3
+ version: 22.15.3
+ '@types/react':
+ specifier: 19.1.0
+ version: 19.1.0
+ '@types/react-dom':
+ specifier: 19.1.1
+ version: 19.1.1(@types/react@19.1.0)
+ eslint:
+ specifier: ^9.34.0
+ version: 9.34.0
+ typescript:
+ specifier: 5.9.2
+ version: 5.9.2
+
+ packages/eslint-config:
+ devDependencies:
+ '@eslint/js':
+ specifier: ^9.34.0
+ version: 9.34.0
+ '@next/eslint-plugin-next':
+ specifier: ^15.5.0
+ version: 15.5.0
+ eslint:
+ specifier: ^9.34.0
+ version: 9.34.0
+ eslint-config-prettier:
+ specifier: ^10.1.1
+ version: 10.1.1(eslint@9.34.0)
+ eslint-plugin-only-warn:
+ specifier: ^1.1.0
+ version: 1.1.0
+ eslint-plugin-react:
+ specifier: ^7.37.5
+ version: 7.37.5(eslint@9.34.0)
+ eslint-plugin-react-hooks:
+ specifier: ^5.2.0
+ version: 5.2.0(eslint@9.34.0)
+ eslint-plugin-turbo:
+ specifier: ^2.5.0
+ version: 2.5.0(eslint@9.34.0)(turbo@2.5.4)
+ globals:
+ specifier: ^16.3.0
+ version: 16.3.0
+ typescript:
+ specifier: ^5.9.2
+ version: 5.9.2
+ typescript-eslint:
+ specifier: ^8.40.0
+ version: 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+
+ packages/typescript-config: {}
+
+ packages/ui:
+ dependencies:
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
+ devDependencies:
+ '@repo/eslint-config':
+ specifier: workspace:*
+ version: link:../eslint-config
+ '@repo/typescript-config':
+ specifier: workspace:*
+ version: link:../typescript-config
+ '@types/node':
+ specifier: ^22.15.3
+ version: 22.15.3
+ '@types/react':
+ specifier: 19.1.0
+ version: 19.1.0
+ '@types/react-dom':
+ specifier: 19.1.1
+ version: 19.1.1(@types/react@19.1.0)
+ eslint:
+ specifier: ^9.34.0
+ version: 9.34.0
+ typescript:
+ specifier: 5.9.2
+ version: 5.9.2
+
+packages:
+
+ '@emnapi/runtime@1.4.5':
+ resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==}
+
+ '@eslint-community/eslint-utils@4.7.0':
+ resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.12.1':
+ resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/config-array@0.21.0':
+ resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/config-helpers@0.3.1':
+ resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.15.2':
+ resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.3.1':
+ resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.34.0':
+ resolution: {integrity: sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.6':
+ resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/plugin-kit@0.3.5':
+ resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@humanfs/core@0.19.1':
+ resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanfs/node@0.16.6':
+ resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/retry@0.3.1':
+ resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
+ engines: {node: '>=18.18'}
+
+ '@humanwhocodes/retry@0.4.3':
+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ engines: {node: '>=18.18'}
+
+ '@img/sharp-darwin-arm64@0.34.3':
+ resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-darwin-x64@0.34.3':
+ resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-arm64@1.2.0':
+ resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-x64@1.2.0':
+ resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-linux-arm64@1.2.0':
+ resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-arm@1.2.0':
+ resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-ppc64@1.2.0':
+ resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-s390x@1.2.0':
+ resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-x64@1.2.0':
+ resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.0':
+ resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.0':
+ resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linux-arm64@0.34.3':
+ resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linux-arm@0.34.3':
+ resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-linux-ppc64@0.34.3':
+ resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@img/sharp-linux-s390x@0.34.3':
+ resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-linux-x64@0.34.3':
+ resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-arm64@0.34.3':
+ resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-x64@0.34.3':
+ resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-wasm32@0.34.3':
+ resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [wasm32]
+
+ '@img/sharp-win32-arm64@0.34.3':
+ resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@img/sharp-win32-ia32@0.34.3':
+ resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@img/sharp-win32-x64@0.34.3':
+ resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@next/env@15.5.0':
+ resolution: {integrity: sha512-sDaprBAfzCQiOgo2pO+LhnV0Wt2wBgartjrr+dpcTORYVnnXD0gwhHhiiyIih9hQbq+JnbqH4odgcFWhqCGidw==}
+
+ '@next/eslint-plugin-next@15.5.0':
+ resolution: {integrity: sha512-+k83U/fST66eQBjTltX2T9qUYd43ntAe+NZ5qeZVTQyTiFiHvTLtkpLKug4AnZAtuI/lwz5tl/4QDJymjVkybg==}
+
+ '@next/swc-darwin-arm64@15.5.0':
+ resolution: {integrity: sha512-v7Jj9iqC6enxIRBIScD/o0lH7QKvSxq2LM8UTyqJi+S2w2QzhMYjven4vgu/RzgsdtdbpkyCxBTzHl/gN5rTRg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@next/swc-darwin-x64@15.5.0':
+ resolution: {integrity: sha512-s2Nk6ec+pmYmAb/utawuURy7uvyYKDk+TRE5aqLRsdnj3AhwC9IKUBmhfnLmY/+P+DnwqpeXEFIKe9tlG0p6CA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@next/swc-linux-arm64-gnu@15.5.0':
+ resolution: {integrity: sha512-mGlPJMZReU4yP5fSHjOxiTYvZmwPSWn/eF/dcg21pwfmiUCKS1amFvf1F1RkLHPIMPfocxLViNWFvkvDB14Isg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@next/swc-linux-arm64-musl@15.5.0':
+ resolution: {integrity: sha512-biWqIOE17OW/6S34t1X8K/3vb1+svp5ji5QQT/IKR+VfM3B7GvlCwmz5XtlEan2ukOUf9tj2vJJBffaGH4fGRw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@next/swc-linux-x64-gnu@15.5.0':
+ resolution: {integrity: sha512-zPisT+obYypM/l6EZ0yRkK3LEuoZqHaSoYKj+5jiD9ESHwdr6QhnabnNxYkdy34uCigNlWIaCbjFmQ8FY5AlxA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@next/swc-linux-x64-musl@15.5.0':
+ resolution: {integrity: sha512-+t3+7GoU9IYmk+N+FHKBNFdahaReoAktdOpXHFIPOU1ixxtdge26NgQEEkJkCw2dHT9UwwK5zw4mAsURw4E8jA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@next/swc-win32-arm64-msvc@15.5.0':
+ resolution: {integrity: sha512-d8MrXKh0A+c9DLiy1BUFwtg3Hu90Lucj3k6iKTUdPOv42Ve2UiIG8HYi3UAb8kFVluXxEfdpCoPPCSODk5fDcw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@next/swc-win32-x64-msvc@15.5.0':
+ resolution: {integrity: sha512-Fe1tGHxOWEyQjmygWkkXSwhFcTJuimrNu52JEuwItrKJVV4iRjbWp9I7zZjwqtiNnQmxoEvoisn8wueFLrNpvQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
+ '@swc/helpers@0.5.15':
+ resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/node@22.15.3':
+ resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==}
+
+ '@types/react-dom@19.1.1':
+ resolution: {integrity: sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w==}
+ peerDependencies:
+ '@types/react': ^19.0.0
+
+ '@types/react@19.1.0':
+ resolution: {integrity: sha512-UaicktuQI+9UKyA4njtDOGBD/67t8YEBt2xdfqu8+gP9hqPUPsiXlNPcpS2gVdjmis5GKPG3fCxbQLVgxsQZ8w==}
+
+ '@typescript-eslint/eslint-plugin@8.40.0':
+ resolution: {integrity: sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.40.0
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/parser@8.40.0':
+ resolution: {integrity: sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/project-service@8.40.0':
+ resolution: {integrity: sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/scope-manager@8.40.0':
+ resolution: {integrity: sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/tsconfig-utils@8.40.0':
+ resolution: {integrity: sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/type-utils@8.40.0':
+ resolution: {integrity: sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/types@8.40.0':
+ resolution: {integrity: sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.40.0':
+ resolution: {integrity: sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/utils@8.40.0':
+ resolution: {integrity: sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ '@typescript-eslint/visitor-keys@8.40.0':
+ resolution: {integrity: sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ array-buffer-byte-length@1.0.2:
+ resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
+ engines: {node: '>= 0.4'}
+
+ array-includes@3.1.9:
+ resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.findlast@1.2.5:
+ resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flat@1.3.3:
+ resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flatmap@1.3.3:
+ resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.tosorted@1.1.4:
+ resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==}
+ engines: {node: '>= 0.4'}
+
+ arraybuffer.prototype.slice@1.0.4:
+ resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
+ engines: {node: '>= 0.4'}
+
+ async-function@1.0.0:
+ resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
+ engines: {node: '>= 0.4'}
+
+ available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ brace-expansion@1.1.12:
+ resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
+
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ call-bind@1.0.8:
+ resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
+ engines: {node: '>= 0.4'}
+
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001736:
+ resolution: {integrity: sha512-ImpN5gLEY8gWeqfLUyEF4b7mYWcYoR2Si1VhnrbM4JizRFmfGaAQ12PhNykq6nvI4XvKLrsp8Xde74D5phJOSw==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ client-only@0.0.1:
+ resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+ color@4.2.3:
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+ engines: {node: '>=12.5.0'}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ data-view-buffer@1.0.2:
+ resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-length@1.0.2:
+ resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-offset@1.0.1:
+ resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
+ engines: {node: '>= 0.4'}
+
+ debug@4.4.1:
+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
+ define-properties@1.2.1:
+ resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+ engines: {node: '>= 0.4'}
+
+ detect-libc@2.0.4:
+ resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
+ engines: {node: '>=8'}
+
+ doctrine@2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+
+ dotenv@16.0.3:
+ resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
+ engines: {node: '>=12'}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ es-abstract@1.24.0:
+ resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==}
+ engines: {node: '>= 0.4'}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-iterator-helpers@1.2.1:
+ resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ es-shim-unscopables@1.1.0:
+ resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}
+ engines: {node: '>= 0.4'}
+
+ es-to-primitive@1.3.0:
+ resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
+ engines: {node: '>= 0.4'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-config-prettier@10.1.1:
+ resolution: {integrity: sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==}
+ hasBin: true
+ peerDependencies:
+ eslint: '>=7.0.0'
+
+ eslint-plugin-only-warn@1.1.0:
+ resolution: {integrity: sha512-2tktqUAT+Q3hCAU0iSf4xAN1k9zOpjK5WO8104mB0rT/dGhOa09582HN5HlbxNbPRZ0THV7nLGvzugcNOSjzfA==}
+ engines: {node: '>=6'}
+
+ eslint-plugin-react-hooks@5.2.0:
+ resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react@7.37.5:
+ resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
+
+ eslint-plugin-turbo@2.5.0:
+ resolution: {integrity: sha512-qQk54MrUZv0gnpxV23sccTc+FL3UJ8q7vG7HmXuS2RP8gdjWDwI1CCJTJD8EdRIDjsMxF0xi0AKcMY0CwIlXVg==}
+ peerDependencies:
+ eslint: '>6.6.0'
+ turbo: '>2.0.0'
+
+ eslint-scope@8.4.0:
+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.34.0:
+ resolution: {integrity: sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ espree@10.4.0:
+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-glob@3.3.1:
+ resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.3.3:
+ resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+ for-each@0.3.5:
+ resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
+ engines: {node: '>= 0.4'}
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ function.prototype.name@1.1.8:
+ resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
+ engines: {node: '>= 0.4'}
+
+ functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ get-symbol-description@1.1.0:
+ resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
+ engines: {node: '>= 0.4'}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globals@16.3.0:
+ resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==}
+ engines: {node: '>=18'}
+
+ globalthis@1.0.4:
+ resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
+ engines: {node: '>= 0.4'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+ has-bigints@1.1.0:
+ resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
+ engines: {node: '>= 0.4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-proto@1.2.0:
+ resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ ignore@7.0.5:
+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ engines: {node: '>= 4'}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ internal-slot@1.1.0:
+ resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
+ engines: {node: '>= 0.4'}
+
+ is-array-buffer@3.0.5:
+ resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
+ engines: {node: '>= 0.4'}
+
+ is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+
+ is-async-function@2.1.1:
+ resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
+ engines: {node: '>= 0.4'}
+
+ is-bigint@1.1.0:
+ resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
+ engines: {node: '>= 0.4'}
+
+ is-boolean-object@1.2.2:
+ resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
+ engines: {node: '>= 0.4'}
+
+ is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ is-data-view@1.0.2:
+ resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}
+ engines: {node: '>= 0.4'}
+
+ is-date-object@1.1.0:
+ resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
+ engines: {node: '>= 0.4'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-finalizationregistry@1.1.1:
+ resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}
+ engines: {node: '>= 0.4'}
+
+ is-generator-function@1.1.0:
+ resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}
+ engines: {node: '>= 0.4'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-map@2.0.3:
+ resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+ engines: {node: '>= 0.4'}
+
+ is-negative-zero@2.0.3:
+ resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+ engines: {node: '>= 0.4'}
+
+ is-number-object@1.1.1:
+ resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
+ engines: {node: '>= 0.4'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-regex@1.2.1:
+ resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
+ engines: {node: '>= 0.4'}
+
+ is-set@2.0.3:
+ resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+ engines: {node: '>= 0.4'}
+
+ is-shared-array-buffer@1.0.4:
+ resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
+ engines: {node: '>= 0.4'}
+
+ is-string@1.1.1:
+ resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
+ engines: {node: '>= 0.4'}
+
+ is-symbol@1.1.1:
+ resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
+ engines: {node: '>= 0.4'}
+
+ is-typed-array@1.1.15:
+ resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
+ engines: {node: '>= 0.4'}
+
+ is-weakmap@2.0.2:
+ resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+ engines: {node: '>= 0.4'}
+
+ is-weakref@1.1.1:
+ resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}
+ engines: {node: '>= 0.4'}
+
+ is-weakset@2.0.4:
+ resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
+ engines: {node: '>= 0.4'}
+
+ isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ iterator.prototype@1.1.5:
+ resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
+ engines: {node: '>= 0.4'}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ jsx-ast-utils@3.3.5:
+ resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
+ engines: {node: '>=4.0'}
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ next@15.5.0:
+ resolution: {integrity: sha512-N1lp9Hatw3a9XLt0307lGB4uTKsXDhyOKQo7uYMzX4i0nF/c27grcGXkLdb7VcT8QPYLBa8ouIyEoUQJ2OyeNQ==}
+ engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@opentelemetry/api': ^1.1.0
+ '@playwright/test': ^1.51.1
+ babel-plugin-react-compiler: '*'
+ react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
+ sass: ^1.3.0
+ peerDependenciesMeta:
+ '@opentelemetry/api':
+ optional: true
+ '@playwright/test':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+ sass:
+ optional: true
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
+ object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+
+ object.assign@4.1.7:
+ resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
+ engines: {node: '>= 0.4'}
+
+ object.entries@1.1.9:
+ resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}
+ engines: {node: '>= 0.4'}
+
+ object.fromentries@2.0.8:
+ resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
+ engines: {node: '>= 0.4'}
+
+ object.values@1.2.1:
+ resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
+ engines: {node: '>= 0.4'}
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ own-keys@1.0.1:
+ resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
+ engines: {node: '>= 0.4'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ possible-typed-array-names@1.1.0:
+ resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
+ engines: {node: '>= 0.4'}
+
+ postcss@8.4.31:
+ resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ prettier@3.6.2:
+ resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
+ engines: {node: '>=14'}
+ hasBin: true
+
+ prop-types@15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ react-dom@19.1.0:
+ resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
+ peerDependencies:
+ react: ^19.1.0
+
+ react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ react@19.1.0:
+ resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
+ engines: {node: '>=0.10.0'}
+
+ reflect.getprototypeof@1.0.10:
+ resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
+ engines: {node: '>= 0.4'}
+
+ regexp.prototype.flags@1.5.4:
+ resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
+ engines: {node: '>= 0.4'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ resolve@2.0.0-next.5:
+ resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
+ hasBin: true
+
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+ safe-array-concat@1.1.3:
+ resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
+ engines: {node: '>=0.4'}
+
+ safe-push-apply@1.0.0:
+ resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
+ engines: {node: '>= 0.4'}
+
+ safe-regex-test@1.1.0:
+ resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
+ engines: {node: '>= 0.4'}
+
+ scheduler@0.26.0:
+ resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
+ set-function-name@2.0.2:
+ resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+ engines: {node: '>= 0.4'}
+
+ set-proto@1.0.0:
+ resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
+ engines: {node: '>= 0.4'}
+
+ sharp@0.34.3:
+ resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ stop-iteration-iterator@1.1.0:
+ resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.matchall@4.0.12:
+ resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.repeat@1.0.0:
+ resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==}
+
+ string.prototype.trim@1.2.10:
+ resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimend@1.0.9:
+ resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimstart@1.0.8:
+ resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+ engines: {node: '>= 0.4'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ styled-jsx@5.1.6:
+ resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
+ engines: {node: '>= 12.0.0'}
+ peerDependencies:
+ '@babel/core': '*'
+ babel-plugin-macros: '*'
+ react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ babel-plugin-macros:
+ optional: true
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ ts-api-utils@2.1.0:
+ resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
+ engines: {node: '>=18.12'}
+ peerDependencies:
+ typescript: '>=4.8.4'
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ turbo-darwin-64@2.5.4:
+ resolution: {integrity: sha512-ah6YnH2dErojhFooxEzmvsoZQTMImaruZhFPfMKPBq8sb+hALRdvBNLqfc8NWlZq576FkfRZ/MSi4SHvVFT9PQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ turbo-darwin-arm64@2.5.4:
+ resolution: {integrity: sha512-2+Nx6LAyuXw2MdXb7pxqle3MYignLvS7OwtsP9SgtSBaMlnNlxl9BovzqdYAgkUW3AsYiQMJ/wBRb7d+xemM5A==}
+ cpu: [arm64]
+ os: [darwin]
+
+ turbo-linux-64@2.5.4:
+ resolution: {integrity: sha512-5May2kjWbc8w4XxswGAl74GZ5eM4Gr6IiroqdLhXeXyfvWEdm2mFYCSWOzz0/z5cAgqyGidF1jt1qzUR8hTmOA==}
+ cpu: [x64]
+ os: [linux]
+
+ turbo-linux-arm64@2.5.4:
+ resolution: {integrity: sha512-/2yqFaS3TbfxV3P5yG2JUI79P7OUQKOUvAnx4MV9Bdz6jqHsHwc9WZPpO4QseQm+NvmgY6ICORnoVPODxGUiJg==}
+ cpu: [arm64]
+ os: [linux]
+
+ turbo-windows-64@2.5.4:
+ resolution: {integrity: sha512-EQUO4SmaCDhO6zYohxIjJpOKRN3wlfU7jMAj3CgcyTPvQR/UFLEKAYHqJOnJtymbQmiiM/ihX6c6W6Uq0yC7mA==}
+ cpu: [x64]
+ os: [win32]
+
+ turbo-windows-arm64@2.5.4:
+ resolution: {integrity: sha512-oQ8RrK1VS8lrxkLriotFq+PiF7iiGgkZtfLKF4DDKsmdbPo0O9R2mQxm7jHLuXraRCuIQDWMIw6dpcr7Iykf4A==}
+ cpu: [arm64]
+ os: [win32]
+
+ turbo@2.5.4:
+ resolution: {integrity: sha512-kc8ZibdRcuWUG1pbYSBFWqmIjynlD8Lp7IB6U3vIzvOv9VG+6Sp8bzyeBWE3Oi8XV5KsQrznyRTBPvrf99E4mA==}
+ hasBin: true
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ typed-array-buffer@1.0.3:
+ resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-length@1.0.3:
+ resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-offset@1.0.4:
+ resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-length@1.0.7:
+ resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
+ engines: {node: '>= 0.4'}
+
+ typescript-eslint@8.40.0:
+ resolution: {integrity: sha512-Xvd2l+ZmFDPEt4oj1QEXzA4A2uUK6opvKu3eGN9aGjB8au02lIVcLyi375w94hHyejTOmzIU77L8ol2sRg9n7Q==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <6.0.0'
+
+ typescript@5.9.2:
+ resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ unbox-primitive@1.1.0:
+ resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
+ engines: {node: '>= 0.4'}
+
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ which-boxed-primitive@1.1.1:
+ resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
+ engines: {node: '>= 0.4'}
+
+ which-builtin-type@1.2.1:
+ resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}
+ engines: {node: '>= 0.4'}
+
+ which-collection@1.0.2:
+ resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+ engines: {node: '>= 0.4'}
+
+ which-typed-array@1.1.19:
+ resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
+ engines: {node: '>= 0.4'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+snapshots:
+
+ '@emnapi/runtime@1.4.5':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@eslint-community/eslint-utils@4.7.0(eslint@9.34.0)':
+ dependencies:
+ eslint: 9.34.0
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.1': {}
+
+ '@eslint/config-array@0.21.0':
+ dependencies:
+ '@eslint/object-schema': 2.1.6
+ debug: 4.4.1
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/config-helpers@0.3.1': {}
+
+ '@eslint/core@0.15.2':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/eslintrc@3.3.1':
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.4.1
+ espree: 10.4.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.34.0': {}
+
+ '@eslint/object-schema@2.1.6': {}
+
+ '@eslint/plugin-kit@0.3.5':
+ dependencies:
+ '@eslint/core': 0.15.2
+ levn: 0.4.1
+
+ '@humanfs/core@0.19.1': {}
+
+ '@humanfs/node@0.16.6':
+ dependencies:
+ '@humanfs/core': 0.19.1
+ '@humanwhocodes/retry': 0.3.1
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.3.1': {}
+
+ '@humanwhocodes/retry@0.4.3': {}
+
+ '@img/sharp-darwin-arm64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.2.0
+ optional: true
+
+ '@img/sharp-darwin-x64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.2.0
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-ppc64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-s390x@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linux-x64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.2.0':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-x64@1.2.0':
+ optional: true
+
+ '@img/sharp-linux-arm64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-arm@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-ppc64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-ppc64': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-s390x@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.2.0
+ optional: true
+
+ '@img/sharp-linux-x64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.2.0
+ optional: true
+
+ '@img/sharp-linuxmusl-arm64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.0
+ optional: true
+
+ '@img/sharp-linuxmusl-x64@0.34.3':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.0
+ optional: true
+
+ '@img/sharp-wasm32@0.34.3':
+ dependencies:
+ '@emnapi/runtime': 1.4.5
+ optional: true
+
+ '@img/sharp-win32-arm64@0.34.3':
+ optional: true
+
+ '@img/sharp-win32-ia32@0.34.3':
+ optional: true
+
+ '@img/sharp-win32-x64@0.34.3':
+ optional: true
+
+ '@next/env@15.5.0': {}
+
+ '@next/eslint-plugin-next@15.5.0':
+ dependencies:
+ fast-glob: 3.3.1
+
+ '@next/swc-darwin-arm64@15.5.0':
+ optional: true
+
+ '@next/swc-darwin-x64@15.5.0':
+ optional: true
+
+ '@next/swc-linux-arm64-gnu@15.5.0':
+ optional: true
+
+ '@next/swc-linux-arm64-musl@15.5.0':
+ optional: true
+
+ '@next/swc-linux-x64-gnu@15.5.0':
+ optional: true
+
+ '@next/swc-linux-x64-musl@15.5.0':
+ optional: true
+
+ '@next/swc-win32-arm64-msvc@15.5.0':
+ optional: true
+
+ '@next/swc-win32-x64-msvc@15.5.0':
+ optional: true
+
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.19.1
+
+ '@swc/helpers@0.5.15':
+ dependencies:
+ tslib: 2.8.1
+
+ '@types/estree@1.0.8': {}
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/node@22.15.3':
+ dependencies:
+ undici-types: 6.21.0
+
+ '@types/react-dom@19.1.1(@types/react@19.1.0)':
+ dependencies:
+ '@types/react': 19.1.0
+
+ '@types/react@19.1.0':
+ dependencies:
+ csstype: 3.1.3
+
+ '@typescript-eslint/eslint-plugin@8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+ '@typescript-eslint/scope-manager': 8.40.0
+ '@typescript-eslint/type-utils': 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+ '@typescript-eslint/utils': 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+ '@typescript-eslint/visitor-keys': 8.40.0
+ eslint: 9.34.0
+ graphemer: 1.4.0
+ ignore: 7.0.5
+ natural-compare: 1.4.0
+ ts-api-utils: 2.1.0(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@8.40.0(eslint@9.34.0)(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.40.0
+ '@typescript-eslint/types': 8.40.0
+ '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
+ '@typescript-eslint/visitor-keys': 8.40.0
+ debug: 4.4.1
+ eslint: 9.34.0
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/project-service@8.40.0(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.9.2)
+ '@typescript-eslint/types': 8.40.0
+ debug: 4.4.1
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@8.40.0':
+ dependencies:
+ '@typescript-eslint/types': 8.40.0
+ '@typescript-eslint/visitor-keys': 8.40.0
+
+ '@typescript-eslint/tsconfig-utils@8.40.0(typescript@5.9.2)':
+ dependencies:
+ typescript: 5.9.2
+
+ '@typescript-eslint/type-utils@8.40.0(eslint@9.34.0)(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/types': 8.40.0
+ '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
+ '@typescript-eslint/utils': 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+ debug: 4.4.1
+ eslint: 9.34.0
+ ts-api-utils: 2.1.0(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@8.40.0': {}
+
+ '@typescript-eslint/typescript-estree@8.40.0(typescript@5.9.2)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.40.0(typescript@5.9.2)
+ '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.9.2)
+ '@typescript-eslint/types': 8.40.0
+ '@typescript-eslint/visitor-keys': 8.40.0
+ debug: 4.4.1
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.7.2
+ ts-api-utils: 2.1.0(typescript@5.9.2)
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.40.0(eslint@9.34.0)(typescript@5.9.2)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0)
+ '@typescript-eslint/scope-manager': 8.40.0
+ '@typescript-eslint/types': 8.40.0
+ '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
+ eslint: 9.34.0
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/visitor-keys@8.40.0':
+ dependencies:
+ '@typescript-eslint/types': 8.40.0
+ eslint-visitor-keys: 4.2.1
+
+ acorn-jsx@5.3.2(acorn@8.15.0):
+ dependencies:
+ acorn: 8.15.0
+
+ acorn@8.15.0: {}
+
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ array-buffer-byte-length@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ is-array-buffer: 3.0.5
+
+ array-includes@3.1.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ is-string: 1.1.1
+ math-intrinsics: 1.1.0
+
+ array.prototype.findlast@1.2.5:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.flat@1.3.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.flatmap@1.3.3:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-shim-unscopables: 1.1.0
+
+ array.prototype.tosorted@1.1.4:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-shim-unscopables: 1.1.0
+
+ arraybuffer.prototype.slice@1.0.4:
+ dependencies:
+ array-buffer-byte-length: 1.0.2
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ is-array-buffer: 3.0.5
+
+ async-function@1.0.0: {}
+
+ available-typed-arrays@1.0.7:
+ dependencies:
+ possible-typed-array-names: 1.1.0
+
+ balanced-match@1.0.2: {}
+
+ brace-expansion@1.1.12:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@2.0.2:
+ dependencies:
+ balanced-match: 1.0.2
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ call-bind@1.0.8:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ get-intrinsic: 1.3.0
+ set-function-length: 1.2.2
+
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001736: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ client-only@0.0.1: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+ optional: true
+
+ color@4.2.3:
+ dependencies:
+ color-convert: 2.0.1
+ color-string: 1.9.1
+ optional: true
+
+ concat-map@0.0.1: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ csstype@3.1.3: {}
+
+ data-view-buffer@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ data-view-byte-length@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ data-view-byte-offset@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-data-view: 1.0.2
+
+ debug@4.4.1:
+ dependencies:
+ ms: 2.1.3
+
+ deep-is@0.1.4: {}
+
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ define-properties@1.2.1:
+ dependencies:
+ define-data-property: 1.1.4
+ has-property-descriptors: 1.0.2
+ object-keys: 1.1.1
+
+ detect-libc@2.0.4:
+ optional: true
+
+ doctrine@2.1.0:
+ dependencies:
+ esutils: 2.0.3
+
+ dotenv@16.0.3: {}
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ es-abstract@1.24.0:
+ dependencies:
+ array-buffer-byte-length: 1.0.2
+ arraybuffer.prototype.slice: 1.0.4
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ data-view-buffer: 1.0.2
+ data-view-byte-length: 1.0.2
+ data-view-byte-offset: 1.0.1
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ es-set-tostringtag: 2.1.0
+ es-to-primitive: 1.3.0
+ function.prototype.name: 1.1.8
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ get-symbol-description: 1.1.0
+ globalthis: 1.0.4
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+ has-proto: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ internal-slot: 1.1.0
+ is-array-buffer: 3.0.5
+ is-callable: 1.2.7
+ is-data-view: 1.0.2
+ is-negative-zero: 2.0.3
+ is-regex: 1.2.1
+ is-set: 2.0.3
+ is-shared-array-buffer: 1.0.4
+ is-string: 1.1.1
+ is-typed-array: 1.1.15
+ is-weakref: 1.1.1
+ math-intrinsics: 1.1.0
+ object-inspect: 1.13.4
+ object-keys: 1.1.1
+ object.assign: 4.1.7
+ own-keys: 1.0.1
+ regexp.prototype.flags: 1.5.4
+ safe-array-concat: 1.1.3
+ safe-push-apply: 1.0.0
+ safe-regex-test: 1.1.0
+ set-proto: 1.0.0
+ stop-iteration-iterator: 1.1.0
+ string.prototype.trim: 1.2.10
+ string.prototype.trimend: 1.0.9
+ string.prototype.trimstart: 1.0.8
+ typed-array-buffer: 1.0.3
+ typed-array-byte-length: 1.0.3
+ typed-array-byte-offset: 1.0.4
+ typed-array-length: 1.0.7
+ unbox-primitive: 1.1.0
+ which-typed-array: 1.1.19
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-iterator-helpers@1.2.1:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-set-tostringtag: 2.1.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ globalthis: 1.0.4
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+ has-proto: 1.2.0
+ has-symbols: 1.1.0
+ internal-slot: 1.1.0
+ iterator.prototype: 1.1.5
+ safe-array-concat: 1.1.3
+
+ es-object-atoms@1.1.1:
+ dependencies:
+ es-errors: 1.3.0
+
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ es-shim-unscopables@1.1.0:
+ dependencies:
+ hasown: 2.0.2
+
+ es-to-primitive@1.3.0:
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.1.0
+ is-symbol: 1.1.1
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-config-prettier@10.1.1(eslint@9.34.0):
+ dependencies:
+ eslint: 9.34.0
+
+ eslint-plugin-only-warn@1.1.0: {}
+
+ eslint-plugin-react-hooks@5.2.0(eslint@9.34.0):
+ dependencies:
+ eslint: 9.34.0
+
+ eslint-plugin-react@7.37.5(eslint@9.34.0):
+ dependencies:
+ array-includes: 3.1.9
+ 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
+ eslint: 9.34.0
+ estraverse: 5.3.0
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ 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
+
+ eslint-plugin-turbo@2.5.0(eslint@9.34.0)(turbo@2.5.4):
+ dependencies:
+ dotenv: 16.0.3
+ eslint: 9.34.0
+ turbo: 2.5.4
+
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint@9.34.0:
+ dependencies:
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0)
+ '@eslint-community/regexpp': 4.12.1
+ '@eslint/config-array': 0.21.0
+ '@eslint/config-helpers': 0.3.1
+ '@eslint/core': 0.15.2
+ '@eslint/eslintrc': 3.3.1
+ '@eslint/js': 9.34.0
+ '@eslint/plugin-kit': 0.3.5
+ '@humanfs/node': 0.16.6
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.4.3
+ '@types/estree': 1.0.8
+ '@types/json-schema': 7.0.15
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.1
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
+ esquery: 1.6.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.15.0
+ acorn-jsx: 5.3.2(acorn@8.15.0)
+ eslint-visitor-keys: 4.2.1
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-glob@3.3.1:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fastq@1.19.1:
+ dependencies:
+ reusify: 1.1.0
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.3.3
+ keyv: 4.5.4
+
+ flatted@3.3.3: {}
+
+ for-each@0.3.5:
+ dependencies:
+ is-callable: 1.2.7
+
+ function-bind@1.1.2: {}
+
+ function.prototype.name@1.1.8:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ functions-have-names: 1.2.3
+ hasown: 2.0.2
+ is-callable: 1.2.7
+
+ functions-have-names@1.2.3: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
+
+ get-symbol-description@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@14.0.0: {}
+
+ globals@16.3.0: {}
+
+ globalthis@1.0.4:
+ dependencies:
+ define-properties: 1.2.1
+ gopd: 1.2.0
+
+ gopd@1.2.0: {}
+
+ graphemer@1.4.0: {}
+
+ has-bigints@1.1.0: {}
+
+ has-flag@4.0.0: {}
+
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.1
+
+ has-proto@1.2.0:
+ dependencies:
+ dunder-proto: 1.0.1
+
+ has-symbols@1.1.0: {}
+
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ ignore@5.3.2: {}
+
+ ignore@7.0.5: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ internal-slot@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.1.0
+
+ is-array-buffer@3.0.5:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+
+ is-arrayish@0.3.2:
+ optional: true
+
+ is-async-function@2.1.1:
+ dependencies:
+ async-function: 1.0.0
+ call-bound: 1.0.4
+ get-proto: 1.0.1
+ has-tostringtag: 1.0.2
+ safe-regex-test: 1.1.0
+
+ is-bigint@1.1.0:
+ dependencies:
+ has-bigints: 1.1.0
+
+ is-boolean-object@1.2.2:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-callable@1.2.7: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-data-view@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+ is-typed-array: 1.1.15
+
+ is-date-object@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-extglob@2.1.1: {}
+
+ is-finalizationregistry@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-generator-function@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ get-proto: 1.0.1
+ has-tostringtag: 1.0.2
+ safe-regex-test: 1.1.0
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-map@2.0.3: {}
+
+ is-negative-zero@2.0.3: {}
+
+ is-number-object@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-number@7.0.0: {}
+
+ is-regex@1.2.1:
+ dependencies:
+ call-bound: 1.0.4
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ is-set@2.0.3: {}
+
+ is-shared-array-buffer@1.0.4:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-string@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
+
+ is-symbol@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+ has-symbols: 1.1.0
+ safe-regex-test: 1.1.0
+
+ is-typed-array@1.1.15:
+ dependencies:
+ which-typed-array: 1.1.19
+
+ is-weakmap@2.0.2: {}
+
+ is-weakref@1.1.1:
+ dependencies:
+ call-bound: 1.0.4
+
+ is-weakset@2.0.4:
+ dependencies:
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+
+ isarray@2.0.5: {}
+
+ isexe@2.0.0: {}
+
+ iterator.prototype@1.1.5:
+ dependencies:
+ define-data-property: 1.1.4
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ has-symbols: 1.1.0
+ set-function-name: 2.0.2
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ jsx-ast-utils@3.3.5:
+ dependencies:
+ array-includes: 3.1.9
+ array.prototype.flat: 1.3.3
+ object.assign: 4.1.7
+ object.values: 1.2.1
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.merge@4.6.2: {}
+
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
+ math-intrinsics@1.1.0: {}
+
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.12
+
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.2
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ natural-compare@1.4.0: {}
+
+ next@15.5.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ '@next/env': 15.5.0
+ '@swc/helpers': 0.5.15
+ caniuse-lite: 1.0.30001736
+ postcss: 8.4.31
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ styled-jsx: 5.1.6(react@19.1.0)
+ optionalDependencies:
+ '@next/swc-darwin-arm64': 15.5.0
+ '@next/swc-darwin-x64': 15.5.0
+ '@next/swc-linux-arm64-gnu': 15.5.0
+ '@next/swc-linux-arm64-musl': 15.5.0
+ '@next/swc-linux-x64-gnu': 15.5.0
+ '@next/swc-linux-x64-musl': 15.5.0
+ '@next/swc-win32-arm64-msvc': 15.5.0
+ '@next/swc-win32-x64-msvc': 15.5.0
+ sharp: 0.34.3
+ transitivePeerDependencies:
+ - '@babel/core'
+ - babel-plugin-macros
+
+ object-assign@4.1.1: {}
+
+ object-inspect@1.13.4: {}
+
+ object-keys@1.1.1: {}
+
+ object.assign@4.1.7:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+ has-symbols: 1.1.0
+ object-keys: 1.1.1
+
+ object.entries@1.1.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ object.fromentries@2.0.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-object-atoms: 1.1.1
+
+ object.values@1.2.1:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ own-keys@1.0.1:
+ dependencies:
+ get-intrinsic: 1.3.0
+ object-keys: 1.1.1
+ safe-push-apply: 1.0.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ possible-typed-array-names@1.1.0: {}
+
+ postcss@8.4.31:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prelude-ls@1.2.1: {}
+
+ prettier@3.6.2: {}
+
+ prop-types@15.8.1:
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ punycode@2.3.1: {}
+
+ queue-microtask@1.2.3: {}
+
+ react-dom@19.1.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ scheduler: 0.26.0
+
+ react-is@16.13.1: {}
+
+ react@19.1.0: {}
+
+ reflect.getprototypeof@1.0.10:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ get-proto: 1.0.1
+ which-builtin-type: 1.2.1
+
+ regexp.prototype.flags@1.5.4:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ set-function-name: 2.0.2
+
+ resolve-from@4.0.0: {}
+
+ resolve@2.0.0-next.5:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ reusify@1.1.0: {}
+
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
+ safe-array-concat@1.1.3:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
+ has-symbols: 1.1.0
+ isarray: 2.0.5
+
+ safe-push-apply@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ isarray: 2.0.5
+
+ safe-regex-test@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-regex: 1.2.1
+
+ scheduler@0.26.0: {}
+
+ semver@6.3.1: {}
+
+ semver@7.7.2: {}
+
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
+
+ set-function-name@2.0.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.2
+
+ set-proto@1.0.0:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+
+ sharp@0.34.3:
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.4
+ semver: 7.7.2
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.34.3
+ '@img/sharp-darwin-x64': 0.34.3
+ '@img/sharp-libvips-darwin-arm64': 1.2.0
+ '@img/sharp-libvips-darwin-x64': 1.2.0
+ '@img/sharp-libvips-linux-arm': 1.2.0
+ '@img/sharp-libvips-linux-arm64': 1.2.0
+ '@img/sharp-libvips-linux-ppc64': 1.2.0
+ '@img/sharp-libvips-linux-s390x': 1.2.0
+ '@img/sharp-libvips-linux-x64': 1.2.0
+ '@img/sharp-libvips-linuxmusl-arm64': 1.2.0
+ '@img/sharp-libvips-linuxmusl-x64': 1.2.0
+ '@img/sharp-linux-arm': 0.34.3
+ '@img/sharp-linux-arm64': 0.34.3
+ '@img/sharp-linux-ppc64': 0.34.3
+ '@img/sharp-linux-s390x': 0.34.3
+ '@img/sharp-linux-x64': 0.34.3
+ '@img/sharp-linuxmusl-arm64': 0.34.3
+ '@img/sharp-linuxmusl-x64': 0.34.3
+ '@img/sharp-wasm32': 0.34.3
+ '@img/sharp-win32-arm64': 0.34.3
+ '@img/sharp-win32-ia32': 0.34.3
+ '@img/sharp-win32-x64': 0.34.3
+ optional: true
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ side-channel-list@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
+ simple-swizzle@0.2.2:
+ dependencies:
+ is-arrayish: 0.3.2
+ optional: true
+
+ source-map-js@1.2.1: {}
+
+ stop-iteration-iterator@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ internal-slot: 1.1.0
+
+ string.prototype.matchall@4.0.12:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ internal-slot: 1.1.0
+ regexp.prototype.flags: 1.5.4
+ set-function-name: 2.0.2
+ side-channel: 1.1.0
+
+ string.prototype.repeat@1.0.0:
+ dependencies:
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+
+ string.prototype.trim@1.2.10:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-data-property: 1.1.4
+ define-properties: 1.2.1
+ es-abstract: 1.24.0
+ es-object-atoms: 1.1.1
+ has-property-descriptors: 1.0.2
+
+ string.prototype.trimend@1.0.9:
+ dependencies:
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ string.prototype.trimstart@1.0.8:
+ dependencies:
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+
+ strip-json-comments@3.1.1: {}
+
+ styled-jsx@5.1.6(react@19.1.0):
+ dependencies:
+ client-only: 0.0.1
+ react: 19.1.0
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ ts-api-utils@2.1.0(typescript@5.9.2):
+ dependencies:
+ typescript: 5.9.2
+
+ tslib@2.8.1: {}
+
+ turbo-darwin-64@2.5.4:
+ optional: true
+
+ turbo-darwin-arm64@2.5.4:
+ optional: true
+
+ turbo-linux-64@2.5.4:
+ optional: true
+
+ turbo-linux-arm64@2.5.4:
+ optional: true
+
+ turbo-windows-64@2.5.4:
+ optional: true
+
+ turbo-windows-arm64@2.5.4:
+ optional: true
+
+ turbo@2.5.4:
+ optionalDependencies:
+ turbo-darwin-64: 2.5.4
+ turbo-darwin-arm64: 2.5.4
+ turbo-linux-64: 2.5.4
+ turbo-linux-arm64: 2.5.4
+ turbo-windows-64: 2.5.4
+ turbo-windows-arm64: 2.5.4
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ typed-array-buffer@1.0.3:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-typed-array: 1.1.15
+
+ typed-array-byte-length@1.0.3:
+ dependencies:
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ has-proto: 1.2.0
+ is-typed-array: 1.1.15
+
+ typed-array-byte-offset@1.0.4:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ has-proto: 1.2.0
+ is-typed-array: 1.1.15
+ reflect.getprototypeof: 1.0.10
+
+ typed-array-length@1.0.7:
+ dependencies:
+ call-bind: 1.0.8
+ for-each: 0.3.5
+ gopd: 1.2.0
+ is-typed-array: 1.1.15
+ possible-typed-array-names: 1.1.0
+ reflect.getprototypeof: 1.0.10
+
+ typescript-eslint@8.40.0(eslint@9.34.0)(typescript@5.9.2):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2)
+ '@typescript-eslint/parser': 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+ '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2)
+ '@typescript-eslint/utils': 8.40.0(eslint@9.34.0)(typescript@5.9.2)
+ eslint: 9.34.0
+ typescript: 5.9.2
+ transitivePeerDependencies:
+ - supports-color
+
+ typescript@5.9.2: {}
+
+ unbox-primitive@1.1.0:
+ dependencies:
+ call-bound: 1.0.4
+ has-bigints: 1.1.0
+ has-symbols: 1.1.0
+ which-boxed-primitive: 1.1.1
+
+ undici-types@6.21.0: {}
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ which-boxed-primitive@1.1.1:
+ dependencies:
+ is-bigint: 1.1.0
+ is-boolean-object: 1.2.2
+ is-number-object: 1.1.1
+ is-string: 1.1.1
+ is-symbol: 1.1.1
+
+ which-builtin-type@1.2.1:
+ dependencies:
+ call-bound: 1.0.4
+ function.prototype.name: 1.1.8
+ has-tostringtag: 1.0.2
+ is-async-function: 2.1.1
+ is-date-object: 1.1.0
+ is-finalizationregistry: 1.1.1
+ is-generator-function: 1.1.0
+ is-regex: 1.2.1
+ is-weakref: 1.1.1
+ isarray: 2.0.5
+ which-boxed-primitive: 1.1.1
+ which-collection: 1.0.2
+ which-typed-array: 1.1.19
+
+ which-collection@1.0.2:
+ dependencies:
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-weakmap: 2.0.2
+ is-weakset: 2.0.4
+
+ which-typed-array@1.1.19:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ for-each: 0.3.5
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ yocto-queue@0.1.0: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..3ff5faa
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,3 @@
+packages:
+ - "apps/*"
+ - "packages/*"
diff --git a/turbo.json b/turbo.json
new file mode 100644
index 0000000..d508947
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://turborepo.com/schema.json",
+ "ui": "tui",
+ "tasks": {
+ "build": {
+ "dependsOn": ["^build"],
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
+ "outputs": [".next/**", "!.next/cache/**"]
+ },
+ "lint": {
+ "dependsOn": ["^lint"]
+ },
+ "check-types": {
+ "dependsOn": ["^check-types"]
+ },
+ "dev": {
+ "cache": false,
+ "persistent": true
+ }
+ }
+}